tutorial, no_image, java,

Java - no_image

Upendra Upendra Follow Jan 23, 2025 · 6 mins read
Java - no_image
Share this

Generics

Generics are a facility of generic programming that were added to the Java programming language in 2004 within version J2SE 5.0. They were designed to extend Java’s type system to allow “a type or method to operate on objects of various types while providing compile-time type safety”.

The Java collections framework supports generics to specify the type of objects stored in a collection instance.

Motivation

The following block of Java code illustrates a problem that exists when not using generics. First, it declares an ArrayList of type Object. Then, it adds a String to the ArrayList. Finally, it attempts to retrieve the added String and cast it to an Integer — an error in logic, as it is not generally possible to cast an arbitrary string to an integer.

List v = new ArrayList();
v.add("test"); // A String that cannot be cast to an Integer
Integer i = (Integer)v.get(0); // Run time error

Although the code is compiled without error, it throws a runtime exception (java.lang.ClassCastException) when executing the third line of code. This type of logic error can be detected during compile time by using generics and is the primary motivation for using them.

The above code fragment can be rewritten using generics as follows:

List<String> v = new ArrayList<String>();
v.add("test");
Integer i = (Integer)v.get(0); // (type error)  compilation-time error

The type parameter String within the angle brackets declares the ArrayList to be constituted of String (a descendant of the ArrayList’s generic Object constituents). With generics, it is no longer necessary to cast the third line to any particular type, because the result of v.get(0) is defined as String by the code generated by the compiler.

The logical flaw in the third line of this fragment will be detected as a compile-time error (with J2SE 5.0 or later) because the compiler will detect that v.get(0) returns String instead of Integer.

Generic Methods

We write generic methods with a single method declaration, and we can call them with arguments of different types. The compiler will ensure the correctness of whichever type we use.

These are some properties of generic methods:

  • Generic methods have a type parameter (the diamond operator enclosing the type) before the return type of the method declaration;
  • Type parameters can be bounded;
  • Generic methods can have different type parameters separated by commas in the method signature;
  • Method body for a generic method is just like a normal method.

Here’s an example of defining a generic method to convert an array to a list:

public <T> List<T> fromArrayToList(T[] a) {   
    return Arrays.stream(a).collect(Collectors.toList());
}

The <T> in the method signature implies that the method will be dealing with generic type T. This is needed even if the method is returning void.

As mentioned, the method can deal with more than one generic type. Where this is the case, we must add all generic types to the method signature.

Here is how we would modify the above method to deal with type T and type G:

public static <T, G> List<G> fromArrayToList(T[] a, Function<T, G> mapperFunction) {
    return Arrays.stream(a)
      .map(mapperFunction)
      .collect(Collectors.toList());
}

We’re passing a function that converts an array with the elements of type T to list with elements of type G.

An example would be to convert Integer to its String representation:

@Test
public void givenArrayOfIntegers_thanListOfStringReturnedOK() {
    Integer[] intArray = {1, 2, 3, 4, 5};
    List<String> stringList
      = Generics.fromArrayToList(intArray, Object::toString);
 
    assertThat(stringList, hasItems("1", "2", "3", "4", "5"));
}

Note that Oracle recommendation is to use an uppercase letter to represent a generic type and to choose a more descriptive letter to represent formal types. In Java Collections, we use T for type, K for key and V for value.

Generic Classes

A generic class declaration looks like a non-generic class declaration, except that the class name is followed by a type parameter section.

As with generic methods, the type parameter section of a generic class can have one or more type parameters separated by commas. These classes are known as parameterized classes or parameterized types because they accept one or more parameters.

Following example illustrates how we can define a generic class:

public class Box<T> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }

   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();
      Box<String> stringBox = new Box<String>();
    
      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));

      System.out.printf("Integer Value :%d\n\n", integerBox.get());
      System.out.printf("String Value :%s\n", stringBox.get());
   }
}

This will produce the following result:

Integer Value :10
String Value :Hello World

Bounded Generics

Remember that type parameters can be bounded. Bounded means “restricted,” and we can restrict the types that a method accepts.

For example, we can specify that a method accepts a type and all its subclasses (upper bound) or a type and all its superclasses (lower bound).

To declare an upper-bounded type, we use the keyword extends after the type, followed by the upper bound that we want to use:

public <T extends Number> List<T> fromArrayToList(T[] a) {
    ...
}

We use the keyword extends here to mean that the type T extends the upper bound in case of a class or implements an upper bound in case of an interface.

Multiple Bounds

A type can also have multiple upper bounds:

<T extends Number & Comparable>

If one of the types that are extended by T is a class (e.g. Number), we have to put it first in the list of bounds. Otherwise, it will cause a compile-time error.

Links

Generics in Java

The Basics of Java Generics

Java - Generics

Further reading

Lesson: Generics

Java Generics Example Tutorial - Generic Method, Class, Interface

Language Features of Java Generics

Next Questions

What do you know about wildcard?

credit goes to @swayangjit
Join Newsletter
Get the latest news right in your inbox. We never spam!
Upendra
Written by Upendra Follow
Hi, I am Upendra, the author in Human and machine languages,I don't know to how 3 liner bio works so just Connect with me on social sites you will get to know me better.