无法理解此Java Stream + Generics示例

Lui*_*ese 7 java eclipse generics java-8 java-stream

有人可以帮助我理解为什么这段代码的行为如评论中所述

// 1) compiles
List<Integer> l = Stream.of(1, 2, 3).collect(ArrayList::new, ArrayList::add, ArrayList<Integer>::addAll);

/*
 *  2) does not compile
 *  
 *  Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
 *      Type mismatch: cannot convert from Object to <unknown>
 *      The type ArrayList does not define add(Object, Integer) that is applicable here
 *      The type ArrayList does not define addAll(Object, Object) that is applicable here
 */
Stream.of(1, 2, 3).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

// 3) compiles
Stream.of(1, 2, 3).collect(ArrayList<Integer>::new, ArrayList::add, ArrayList::addAll);

/*
 *  4) does not compile
 *  
 *  Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
 *      Type mismatch: cannot convert from Object to <unknown>
 *      The type ArrayList does not define add(Object, Integer) that is applicable here
 *      The type ArrayList<Integer> does not define addAll(Object, Object) that is applicable here
 */
Stream.of(1, 2, 3).collect(ArrayList::new, ArrayList::add, ArrayList<Integer>::addAll);  
Run Code Online (Sandbox Code Playgroud)

它显然与泛型方法中的类型定义有关,它是必须以某种方式提供的信息......但为什么它是强制性的?在哪里,怎么样,语法,我应该从方法签名想通了of()collect()

public static<T> Stream<T> of(T... values) {...}

<R> R collect(Supplier<R> supplier,
              BiConsumer<R, ? super T> accumulator,
              BiConsumer<R, R> combiner);
Run Code Online (Sandbox Code Playgroud)

use*_*547 7

虽然这不是一个分析http://download.oracle.com/otndocs/jcp/lambda-0_9_3-fr-eval-spec/index.html上的Lambda规范的答案,但我试图找出它依赖的内容.

Stream类中复制两个方法:

static class Stream2<T> {

    @SafeVarargs
    @SuppressWarnings("varargs") // Creating a stream from an array is safe
    public static<T> Stream2<T> of(T... values) {
        return new Stream2<>();
    }

     public  <R> R collect(  Supplier<R> supplier,
             BiConsumer<R, ? super T> accumulator,
             BiConsumer<R, R> combiner){return null;}

}
Run Code Online (Sandbox Code Playgroud)

这编译:

Stream2.of(1,2,3).collect(ArrayList::new, ArrayList::add, ArrayList::addAll );
Run Code Online (Sandbox Code Playgroud)

喜欢OP(2).

现在collect通过将第一个参数移动到第三个位置来更改方法

     public  <R> R collect(BiConsumer<R, ? super T> accumulator,
             BiConsumer<R, R> combiner,
             Supplier<R> supplier
     ){return null;}
Run Code Online (Sandbox Code Playgroud)

这仍然有效(5):

 Stream2.of(1,2,3).collect(ArrayList::add, ArrayList::addAll,ArrayList::new );
Run Code Online (Sandbox Code Playgroud)

这也有效(6):

 Stream2.of(1,2,3).collect(ArrayList::add, ArrayList::addAll,ArrayList<Integer>::new );
Run Code Online (Sandbox Code Playgroud)

这些不起作用(7,8):

 Stream2.of(1,2,3).collect(ArrayList<Integer>::add, ArrayList::addAll,ArrayList::new );
 Stream2.of(1,2,3).collect(ArrayList<Integer>::add, ArrayList<Integer>::addAll,ArrayList::new );
Run Code Online (Sandbox Code Playgroud)

但这再次起作用(9):

 Stream2.of(1,2,3).collect(ArrayList<Integer>::add, ArrayList<Integer>::addAll,ArrayList<Integer>::new );
Run Code Online (Sandbox Code Playgroud)

所以我想当供应商使用显式类型参数进行注释时,它似乎有效.当只有消费者时,却没有.但也许其他人知道为什么会有所作为.

编辑:尝试使用TestList,它甚至更奇怪:

public class StreamTest2 {

    public static void main(String[] args) {

        Stream.of(1, 2, 3).collect(TestList::new, TestList::add, TestList<Integer>::addAll);
        Stream.of(1, 2, 3).collect(TestList::new, TestList::add, TestList<Integer>::addAll2);
        Stream.of(1, 2, 3).collect(TestList::new, TestList::add, TestList<Integer>::addAll3);
        Stream.of(1, 2, 3).collect(TestList::new, TestList::add, TestList<Integer>::addAll4);
        Stream.of(1, 2, 3).collect(TestList::new, TestList::add, TestList<Integer>::addAll5);
        Stream.of(1, 2, 3).collect(TestList::new, TestList::add, TestList<Integer>::addAll6);

    }
}

class TestList<T> extends AbstractList<T> {

    @Override
    public T get(int index) {
        return null;
    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        return true;
    }

    public boolean addAll2(TestList<? extends T> c) {
        return true;
    }
    public boolean addAll3(Collection<T> c) {
        return true;
    }

    public boolean addAll4(List<? extends T> c) {
        return true;
    }
    public boolean addAll5(AbstractList<? extends T> c) {
        return true;
    }

    public boolean addAll6(Collection<? extends T> c) {
        return true;
    }

    @Override
    public boolean add(T e) {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

addAll不起作用,但是addAll2- 6做的工作.即使是addAll6作品,也与原作相同addAll.