Java generic story

Introduction

Because of the previous Java static story , I'm going to continue Java time.

goal

Whether it's generics or generics, aside. Let's take a look at some simple examples and play with generics in Java.

Generics (generic type) and type safety

Introduced in jdk 1.5.

Just at the time of writing this, Java said "Please update jdk 9.0.4", and I heard that java10 will be released, so it became jdk 1.5 ... ..

Before that,

List lst = new ArrayList();
Map map = new HashMap();

It seems that it was written in a raw type like this. It can still work, but it is not recommended.

Any object will fit in. It will fit in.

lst.add("sample");
lst.add(11111);

// for-each is also 1.5 or later
//The iterator is still raw
Iterator it = lst.iterator();
while (it.hasNext()) {
  Object o = it.next();
  System.out.print(o); // sample1111
}

This does not guarantee type safety. You have to cast carefully when retrieving the elements in the collection

lst.add("sample");
lst.add(11111);

Iterator it = lst.iterator();
while (it.hasNext()) {
  Object o = it.next();
  System.out.print((String) o); //sample and ClassCastException
}

In this way, if you make a mistake in the type, whether it is a mistake or not, you will notice the exception only at runtime, and the program may stop at an unexpected timing.

Regarding Exception

The ClassCastException thrown when the cast fails is an exception class that inherits from the RuntimeException```.

RuntimeException is a runtime exception, and exception handling is up to you..


 In other words, the time to notice the error is not at compile time, but at subsequent execution time.


# Formal argument `` `<E> ```
 Since jdk 1.5, the ``` Collection``` interface has evolved (?) To` `Collection <E>` `` and can only store one type.

#### **`As written in the collection javadoc, E is"Types of elements in this collection"Is that. `**

The same is true for the List that inherits the collection, which is now ``` List ` ``. I haven't decided what will be included yet, but I guarantee that only one type will be included, so I'll put it in temporarily. It's probably Element's E.

So, when actually creating an instance of a list, `List <Integer> lst = new ArrayList <> ();` or ... Finally, the formal argument seats are filled, where Integer is the actual argument </ b> in this list.

Diamond operator since jdk7

List lst = new ArrayList(); List lst = new ArrayList<>(); //Now optional


 These generics interfaces and their implementation classes are called <b> generic types </ b>.

 Also, generics in java can be declared for classes, interfaces, methods and constructors.

# Difference between raw type and ``` <Object>` ``
 For example, like the prototype List, `` `List <Object>` `` can store objects of any type.

```java
 List<Object> objList = new ArrayList<>();
 objList.add("a");
 objList.add(1);
 objList.add(new Sample());

At this point, it doesn't seem to make much difference,

First, the raw type List is

  private static List rawList() {
    return new ArrayList();
  }

  private static void printList(List rawList) {
    rawList.forEach(System.out::println);
  }
  public static void main(String... args) {
    printList(rawList()); //Pass through
  } 

The compiler doesn't say anything. In other words, the timing when some type mismatch occurs and you notice it is at runtime, so it is not type safe.

On the other hand, `` `List ``` is

List<Object> objList = new ArrayList<String>(); //Compile error

And

  private static List<String> strList() {
    return new ArrayList<String>();
  }

  private static void printObjList(List<Object> objList) {
    objList.forEach(System.out::println);
  }

  public static void main(String... args) {
    printObjList(strList()); //Compile error
  }

And vice versa (?)

  private static List<Object> objList() {
    return new ArrayList<Object>();
  }

  private static void printStrList(List<String> strList) {
    strList.forEach(System.out::println);
  }

  public static void main(String... args) {
    printStrList(objList()); //Compile error
  }

Can not.

The reason is that `List <String>` is a subtype of List, but not `List <Object>` `. That is, ``` List <String> There is no inheritance relationship between and List <Object> `.

For this reason, generics are called invariants </ I>.

So, if you want to modify one of the previous codes

List<Object> objList = new ArrayList<String>(); //Compile error
List<?> someTypeList = new ArrayList<String>();

I think it will look like this.

<?>Regarding, I would like to organize it in the following wildcards.



# Differences between generics and sequences

## Array is covariant
 It is a continuation of the story that generics are immutable.
 As for the nature of covariance, we talked about the "inheritance relationship" earlier, but with an array you can do something like this.

```java
  private static void printAry(Object[] objAry) {
    Arrays.stream(objAry).forEach(System.out::println);
  }

  private static String[] strAry(String[] strAry) {
    return strAry;
  }

  printAry(strAry(new String[]{"a", "b", "c"}));

If there is an inheritance relationship (String is a sub of Object) between String and Object, the inheritance relationship will also be applied between String [] and Object [].

In other words

Object[] objAry = new String[10];
objAry[0] = 1; 

I'm trying to store an invalid type, but I don't notice it at compile time.

Generics eraser (discard type)

  • Realization
    At runtime, the array already knows the element type and will execute with that type.

  • Impossible to materialize
    On the other hand, generics are implemented by eraser (element type information is erased at run time) once it is checked at compile time. One information is lost at run time compared to at compile time.
    This allowed me to add generics to an existing raw type, even for a collection of raw types prior to jdk 1.5.

Generic design

Tuple Tuples are data structures that can store multiple and different elements in order.

Pair.java


public class Pair<V, W> {
  private final V v;
  private final W w;

  Pair(V v, W w) {
    this.v = v;
    this.w = w;
  }

  V getV() {
    return v;
  }

  W getW() {
    return w;
  }
}
Pair<String, Integer> tuple2 = new Pair<>("toilet-score", 100);

String v = tuple2.getV();
Integer w = tuple2.getW();
  
System.out.println(v + w);

By expanding the usage type of pairs that store and retrieve data of two basic heterogeneous types, such as

TupleUtils.java


public class Tuple {
  public static class Tuple2<A, B> {
    private final A a;
    private final B b;

    public Tuple2(A a, B b) {
      this.a = a;
      this.b = b;
    }

    public A getA() {
      return a;
    }

    public B getB() {
      return b;
    }
  }

  public static class Tuple3<A, B, C> extends Tuple2<A, B> {
    private final C c;

    public Tuple3(A a, B b, C c) {
      super(a, b);
      this.c = c;
    }

    public C getC() {
      return c;
    }
  }

  // Tuple4, Tuple5 ... 
}

(Added static inner class for versatility, changed accessor for each constructor to public) I think we can create a general-purpose tuple utility class that can store data of three, four, or more types in a type-safe way.

Borrow the wisdom of our predecessors

As a more reliable and diverse pattern, the library already exists, so the famous one is Commons Lang Pair etc. .

On the other hand, although it is small, it takes the trouble to provide from one type to ten types (!) With a simple configuration javatuples: Official github See also .

Regarding javatuples, I personally thought that tuples that have only one type called Unit started, and from there it has a beautiful inheritance form ... but it has two types. It was interesting that the Tuple class was the axis and the Tuple was inherited for the Unit as well.

Wildcard

As an extension of the previous story, the generics are immutable. The pseudotype `<T>` guarantees that there will be one certain type, but it is a type that inherits the T type. `List <Object>` and `List <String>` do not have an inheritance relationship. That is, it is not flexible.

So, at the same timing as Generics (jdk 1.5), wildcards will appear.

Non-boundary wildcard ``` <?>` ``

If you want to use generics but haven't decided on the actual type parameters yet, pass `? ``` To the temporary type <E> ``.

//Because T cannot be resolved,Compile error
List<T> someList = new ArrayList<String>(); 

//Because you are trying to store it before the actual type is decided,Compile error
List<?> anotherList = new ArrayList<>(); anotherList.add("a"); 

// OK
List<?> theOtherList = new ArrayList<String>(); theOtherList.add("a"); 

Boundary wildcard (upper limit) ``` <? Extend T>` ``

// OK.Integer is the sub of Number-class.
List<? extends Number> myList = new ArrayList<Integer>();  

 // OK.Long is Number sub-class.
List<? extends Number> yourList = new ArrayList<Long>();  

//Because Object is a type that exceeds Number,Compile error
List<? extends Number> someList = new ArrayList<Object>();

Boundary wildcard (lower limit) ``` <? Super T>` ``

//Because Long is not a superordinate class of Integer,Compile error
List<? super Integer> suNumList2 = new ArrayList<Long>(); 

// OK.Number is a superordinate class of Integer. 
List<? super Integer> suNumList = new ArrayList<Number>();

Functional Interface and Generics

Below are the main functional interfaces introduced in jdk 1.8. Functional Interface javadoc , but one abstract method It's an interface that only has.

The following is part of the Function interface contained in java.util.Objects.

Function.java


@FunctionalInterface
public interface Function<T, R> {
    /**
     * Applies this function to the given argument. 
     *Accepts the given arguments.
     * 
     * @param t the function argument 
     *Parameter t Function argument
     * 
     * @return the function result 
     *Result of return function
     */
    R apply(T t);

    // omit 
}

These function interfaces, such as Function BiFunction Consumer Supplier ... I haven't decided on the type yet, but I accept something Again, the type hasn't been decided yet, but it represents a structure that returns something as a result.

IntSupplier getAsInt()Some methods, etc. have decided in advance that the return value is only an int type, but basically you can see that we are trying to be flexible by using generics..



# Generics and I-Generics Method-like Play
 It's a strange subtitle, but it's just like a play memo.

 The other day, I created an algorithm.
 It is an O (N) function that accepts a list that does not care about the element type, processes the list, and returns another list packed with operation results.


#### **`Something.java`**
```java

  private static List<Object> doSomething(List<Object> list) {

    List<Object> result = new ArrayList<>();

    //processing

    return result;
  }

But

Something.java


  public static void main(String[] args) {
   List<String> strListA = Arrays.asList("c", "a", "b", "b", "c", "a", "d", "b"); 
  
   List<Object> strListB = Arrays.asList("c", "a", "b", "b", "c", "a", "d", "b");

   // List<Object>Not List<String>Compile error to pass
   doSomething(strListA).forEach(System.out::print);
   
   doSomething(strListB).forEach(System.out::print);
  }

I didn't like the fact that all the list type parameters passed to the parameters are restricted to the Object type. For example, if you add a method that generates a list that accepts only numbers and you want to pass it as a parameter, it's a bit inconvenient.

Something.java


  private static List<Number> makeNumberList(Number...nums) {
    List<Number> list = new ArrayList<>();
    for (Number num : nums) list.add(num);
    return list;
  }

Something.java


  public static void main(String[] args) {
   doSomething(makeNumberList(1, 2, 3, 4, 1)).forEach(System.out::print); //Compile error
  }

So change `<Object>` to ``` ` ``. ~~ Added a type token so that the type can be checked at compile time. ~~

Remarks (above, strikethrough)

//Kral literal class to methodBy passing doSomething(List list, Class type)

//Can convey type information at runtime doSomething(someList, Integer.class)

 I was trying to compile only when the type parameter and the type token match, but I put it on hold because the usage of type in the method was lost in the process of modification.



#### **`Something.java`**
```java

  private static <T> List<T> doSomething(List<T> list) {
    
    List<T> result = new ArrayList<>();
    
    //processing
    
    return result;
  }

Try to include the Number type and its subordinate types in the method that creates the number type list ...

Something.java


  private static <T extends Number> List<T> makeNumberList(T...args) {
    List<T> list = new ArrayList<>();
    for (T arg : args) list.add(arg);
    return list;
  }

Something.java


  public static void main(String[] args) {
    List<Integer> someList = makeNumberList(5, 1, 2, 3, 3, 4, 3, 1, 2, 4, 5);
    doSomething(someList).forEach(System.out::print);
  }

This allows you to pass a list other than `List <Object>` as a parameter.

The end

For some reason, I was worried about generics. It's strange to say, but I was worried about something like "a type-safe and flexible magic tool that suddenly fell into a world that was type-safe but not so safe" (what are you saying). It may be.

While writing this myself, there were many things like this was ambiguous, or I didn't know this, so please let me know as soon as you find any mistakes.

reference

Effective Java 2nd Edition Oracle Java docs

  • https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.2
  • https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html#package.description

that's all

Recommended Posts