Test.java
package test;
import java.util.ArrayList;
import java.util.List;
public class Test<T> {
	public static void main(String[] args) {
		Object obj;
		Number num;
		Integer in = 10;
		System.out.println("in is " + in.getClass().getCanonicalName());
		num = in;
		System.out.println("num is " + num.getClass().getCanonicalName());
		// java.lang.Integer
		obj = in;
		System.out.println("obj is " + obj.getClass().getCanonicalName());
		// java.lang.Integer
		List<Object> objList = new ArrayList<Object>();
		List<Number> numList = new ArrayList<Number>();
		List<Integer> inList = new ArrayList<Integer>();
		inList.add(in);
		System.out.println("inList is " + inList.getClass().getCanonicalName());
		System.out.println("inList.get(0) is " + inList.get(0).getClass().getCanonicalName());
		numList.add(in);
		System.out.println("numList is " + numList.getClass().getCanonicalName());
		System.out.println("numList.get(0) is " + numList.get(0).getClass().getCanonicalName());
		objList.add(in);
		System.out.println("objList is " + objList.getClass().getCanonicalName());
		System.out.println("objList.get(0) is " + objList.get(0).getClass().getCanonicalName());
	}
}
in is java.lang.Integer
num is java.lang.Integer
obj is java.lang.Integer
inList is java.util.ArrayList
inList.get(0) is java.lang.Integer
numList is java.util.ArrayList
numList.get(0) is java.lang.Integer
objList is java.util.ArrayList
objList.get(0) is java.lang.Integer
List<Object> declared variable represent a  List<Integer> type ? The answer is NO. let us think about this.python
		List<Object> objList1 = new ArrayList<Object>();
		List<Object> objList2 = new ArrayList<Number>();//if it can be true here then next step will be error.
		objList2.add(new Object);//error! objList2 actually is a List< Number > !
so we have no choice! let List<Object> = new List<Object> is the only way to keep safe.
but we really want a syntax to let List<Parent> variable represent List<Child>, because there are too many children type. child1, child2, child3, .... we want a syntax to let variable represent one of List< child1> , List<child2>, List<child3>, ...  be careful. we know that List<child1> and  List<child2> can not represent each other. but we want to declare that List<? extends Parent> can represent List<child1> when it is = new List<child1>(). or it can represent List<child2> when it is = new List<child2>(). etc.  when we see List<? extends Parent> g ,we know that g actually is a List<child1> or a List<child2> or a List<child3>  or List< Parent >. one of them , not any of them! so we use the ? extends Parent  instead of * extends Parent.
because List<? extends Parent> g  actually is List<ChildX> , we can read from  List<ChildX> use a Parent type variable. we can not put a Parent or a Child to its element position. because actually the element position may be Child1 type. maybe  Child2 type... anyway, it is uncertain. what we know is it must look like a Parent type. we can read from the element position then use it as a Parent. but we can not replace it. if we do so ,we may break the rule to make Child <= Parent happens! or Child1 <= Child2. that must be forbidden!
then let us see List<? super Parent> g  . it represent a List<P1>, or List<P2>, or List<P3>, ... which P1 is parent of Parent, P2 is parent of Parent, P3 is parent of Parent...
we can safely set a child of Parent to the g's element just like  Parent p = new Child(). also we face the uncertainty. so we can not actually read from the element unless we use Object p = g.get(0).
when to use ? let us think about this scenario: we want a List<T> => List<T,T> convert
DoubleElement.java
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class DoubleElement<T> {
	public final T x;
	public final T y;
	public DoubleElement(T e) {
		this.x = e;
		this.y = e;
	}
	
	
	@Override
	public String toString() {
		return "{x:" + x + ", y:" + y + "}";
	}
	public static <T> List<DoubleElement<T>> toDoubleElementArray(List<T> list) {
		List<DoubleElement<T>> doubleElementArray = new ArrayList<DoubleElement<T>>(list.size());
		for (T e : list) {
			doubleElementArray.add(new DoubleElement<T>(e));
		}
		return doubleElementArray;
	}
	public static void main(String[] args) {
		List<Integer> inList = Arrays.asList(new Integer[] { 1, 2, 3 });
		List<Number> numList = Arrays.asList(new Number[] { 1, 2.5f, 3 });
		List<Float> floatList = Arrays.asList(new Float[] { 1.1f, 2.2f, 3.3f });
		List<DoubleElement<Integer>> doubleInList = DoubleElement.toDoubleElementArray(inList);
		System.out.println(doubleInList);
		List<DoubleElement<Number>> doubleNumList = DoubleElement.toDoubleElementArray(numList);
		System.out.println(doubleNumList);
		List<DoubleElement<Float>> doubleFloatList = DoubleElement.toDoubleElementArray(floatList);
		System.out.println(doubleFloatList);
		//we want to constraint this because we only want to use Number and its Child to work.
		List<String> strList = Arrays.asList(new String[] { " I ", " am ", " evil !" });
		List<Object> objList = Arrays.asList(new Object[] { " I ", " am ", " evil !", " too !" });
		List<DoubleElement<String>> doubleStrList = DoubleElement.toDoubleElementArray(strList);
		System.out.println(doubleStrList);
		List<DoubleElement<Object>> doubleObjList = DoubleElement.toDoubleElementArray(objList);
		System.out.println(doubleObjList);
	}
}
[{x:1, y:1}, {x:2, y:2}, {x:3, y:3}]
[{x:1, y:1}, {x:2.5, y:2.5}, {x:3, y:3}]
[{x:1.1, y:1.1}, {x:2.2, y:2.2}, {x:3.3, y:3.3}]
[{x: I , y: I }, {x: am , y: am }, {x: evil !, y: evil !}]
[{x: I , y: I }, {x: am , y: am }, {x: evil !, y: evil !}, {x: too !, y: too !}]
T works fine. but we want to add a constraint to T. only List<Number> and its Child List<Float> List<Integer> ... can use this method. how to ?
public static <T> List<DoubleElement<Number>> toDoubleElementArray(List<Number> list) {
//this will well done with List<Number> but not List<Float> or List<Integer> or ...
yes! it is showtime of  List<? extends Number>  !
DoubleElement.java
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class DoubleElement<T> {
	public final T x;
	public final T y;
	public DoubleElement(T e) {
		this.x = e;
		this.y = e;
	}
	@Override
	public String toString() {
		return "{x:" + x + ", y:" + y + "}";
	}
	public static List<DoubleElement<? extends Number>> toDoubleElementArray(List<? extends Number> list) {
		List<DoubleElement<? extends Number>> doubleElementArray = new ArrayList<DoubleElement<? extends Number>>(
				list.size());
		for (Number e : list) {
			doubleElementArray.add(new DoubleElement<Number>(e));
		}
		return doubleElementArray;
	}
	public static void main(String[] args) {
		List<Integer> inList = Arrays.asList(new Integer[] { 1, 2, 3 });
		List<Number> numList = Arrays.asList(new Number[] { 1, 2.5f, 3 });
		List<Float> floatList = Arrays.asList(new Float[] { 1.1f, 2.2f, 3.3f });
		List<DoubleElement<? extends Number>> doubleInList = DoubleElement.toDoubleElementArray(inList);
		System.out.println(doubleInList);
		List<DoubleElement<? extends Number>> doubleNumList = DoubleElement.toDoubleElementArray(numList);
		System.out.println(doubleNumList);
		List<DoubleElement<? extends Number>> doubleFloatList = DoubleElement.toDoubleElementArray(floatList);
		System.out.println(doubleFloatList);
		
        //we want to constraint this because we only want to use Number and its Child to work.
        List<String> strList = Arrays.asList(new String[] { " I ", " am ", " evil !" });
        List<Object> objList = Arrays.asList(new Object[] { " I ", " am ", " evil !", " too !" });
        
        //this will compile error!
        List<DoubleElement<String>> doubleStrList = DoubleElement.toDoubleElementArray(strList);
        System.out.println(doubleStrList);
        //this will compile error!
        List<DoubleElement<Object>> doubleObjList = DoubleElement.toDoubleElementArray(objList);
        System.out.println(doubleObjList);
	}
}
/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package java.util.function;
import java.util.Objects;
/**
 * Represents a function that accepts one argument and produces a result.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {
    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
    /**
     * Returns a function that always returns its input argument.
     *
     * @param <T> the type of the input and output objects to the function
     * @return a function that always returns its input argument
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
TestFunction.java
package test;
import java.util.function.Function;
public class TestFunction {
	public static void main(String[] args) {
		Function<Integer, Float> func = e -> {
			return e + 5.5f;
		};
		
		Function<Number, Number> func2 = e -> {
			return Math.round(e.floatValue());
		};
		
		//OK round( e+5.5 )
		Number result = func.andThen(func2).apply(5);
		System.out.println(result);
	   
		//this will constraint you because the <? super Float>
		Function<Integer, Number> func3 = e -> {
			return Math.round(e.floatValue());
		};
		
		//compile error!
		Number result3 = func.andThen(func3).apply(5);
		System.out.println(result);
	}
}
Recommended Posts