Sunday, October 22, 2017

Java Advanced Generics Examples Part 1 - Wildcards

Java Generics are invariant. Wildcards is a mechanism to make expression of covariance available in order to expand the usages of the generics.

  1. Wildcards could be used to expand the code usage to certain type hierarchy instead of limiting to one type, the super and extends keywords  provide help here.
  2. With wildcards, sometimes same object will be labeled as different captures. Help method could be used to synchronize the type in another method.
  3. Explicit type parameter is in this format: Class.<Type>method(). It could be used to declare a limit to a wild card.

The following code shows examples of:
  1. wildcard with super and extends
  2. wildcard with help method
  3. explicit type parameter
  4. example of multiple extends


public class GenericUsages {
       // this list is a destination or consumer: super
       public static void addNumbers(final List<? super Integer> list) {
             for (int i = 1; i <= 10; i++) {
                    list.add(i);
             }
       }
       
       // this list is a source or producer: extends
       public static int sumOfList(final List<? extends Integer> list) {
             int s = 0;
             for (Number n : list)
                    s += n.doubleValue();
             return s;
       }

       @Test
       public void testSimpleSuperAndExtend() {
             System.out.println("===testSimpleSuperAndExtend===");
             final List<Integer> intList = new ArrayList<>();
             addNumbers(intList);
             final int result = sumOfList(intList);
             System.out.println(result);
       }

       public static void increment(Map<?, String> in) {
             incrementInternal(in);
       }

       // A help method to avoid compiling errors
       private static <T> void incrementInternal(final Map<T, String> in) {
             Set<T> keySet = in.keySet();
             for (T key : keySet) {
                    in.put(key, in.get(key) + ":)");
             }
       }

       @Test
       public void testHelpMethod() {
             System.out.println("===testHelper===");
             Map<Number, String> map = new HashMap<>();
             map.put(1, "Integer 1");
             map.put(2.0, "Double 2.0");
             map.put(3L, "Long 3");
             increment(map);
             System.out.println(map);

             Map<String, String> map2 = new HashMap<>();
             map2.put("k1", "v1");
             map2.put("k2", "v2");
             map2.put("k3", "v3");
             increment(map2);
             System.out.println(map2);

       }

       public static <E> Set<E> union(final Set<? extends E> s1, final Set<? extends E> s2) {
             final Set<E> result = new HashSet<>(s1);
             result.addAll(s2);
             return result;
       }

       @Test
       public void testExplicitTypeParameter() {
             System.out.println("===testExplicitTypeParameter===");
             Set<Integer> integers = new HashSet<>();
             integers.add(1);
             integers.add(2);
             Set<Double> doubles = new HashSet<>();
             doubles.add(1.0);
             doubles.add(2.0);
             Set<Number> result = GenericUsages.<Number>union(integers, doubles);
             System.out.println(result);
             Set<String> strings = new HashSet<>();
             strings.add("1s");
             strings.add("2s");
             Set<?> result2 = GenericUsages.union(integers, strings);
//           Compiling errors:
//           Set<Number> result2 = GenericUsages.union(integers, strings);
//           Set<?> result3 = GenericUsages.<Number>union(integers, strings);
             System.out.println(result2);
       }

       interface Label<T> {
             String getLabel();
       }

       public static <S extends Label<? super S>, U extends Label<? super U>> String m1(final S s, final U u) {
             final String result = s.getLabel().toString() + u.getLabel().toString();
             return result;
       }

       public static class Base implements Label<Base> {
             private String label;

             public Base(final String label) {
                    this.label = label;
             }

             @Override
             public String getLabel() {
                    return this.label;
             }
       }

       public static class S1 extends Base {
             public S1() {
                    super("S1");
             }
       }

       public static class U1 extends Base {
             public U1() {
                    super("U1");
             }
       }

       @Test
       public void testComplicatedSuperAndExtend() {
             System.out.println("===testComplicatedSuperAndExtend===");
             final S1 s1 = new S1();
             final U1 u1 = new U1();
             String result = m1(s1, u1);
             System.out.println(result);
       }

       public static <X extends A & B & C> C m2(final X x) {
             return x;
       }

       public static class A {
       }

       interface B {
       }

       interface C {
       }

       public static class D extends A implements B, C {
       }

       @Test
       public void testMultipleSuperTypes() {
             System.out.println("===testMultipleSuperTypes===");
             final D d = new D();
             System.out.println(m2(d).toString());
       }
}









No comments:

Post a Comment