这段代码使用ecj而不是javac进行编译。这是ecj、javac中的bug还是两者都不是?

这段代码使用ecj而不是javac进行编译。这是ecj、javac中的bug还是两者都不是?,java,javac,ecj,Java,Javac,Ecj,以下代码创建一个收集器,该收集器生成一个不可修改的分类数据集: package com.stackoverflow; import java.util.Collections; import java.util.SortedSet; import java.util.TreeSet; import java.util.stream.Collector; import java.util.stream.Collectors; public class SOExample { publ

以下代码创建一个
收集器
,该收集器生成一个
不可修改的分类数据集

package com.stackoverflow;

import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public class SOExample {

    public static <T extends Comparable<T>> Collector<T, ?, SortedSet<T>> toSortedSet() {
        return Collectors.toCollection(TreeSet::new);
    }

    public static <T extends Comparable<T>> Collector<T, ?, SortedSet<T>> toUnmodifiableSortedSet() {
        return Collectors.collectingAndThen(toSortedSet(), Collections::<T> unmodifiableSortedSet);
    }
}
public static <T extends Comparable<T>> Collector<T, ?, SortedSet<T>> toUnmodifiableSortedSet() {
    return Collectors.collectingAndThen(Collectors.toCollection(TreeSet::new), Collections::<T>unmodifiableSortedSet);
}
但是,在javac下:

$ javac -version
Picked up _JAVA_OPTIONS: -Duser.language=en -Duser.country=GB
javac 1.8.0_73

$ javac SOExample.java
Picked up _JAVA_OPTIONS: -Duser.language=en -Duser.country=GB
SOExample.java:16: error: method collectingAndThen in class Collectors cannot be applied to given types;
        return Collectors.collectingAndThen(toSortedSet(), Collections::<T> unmodifiableSortedSet);
                         ^
  required: Collector<T#1,A,R>,Function<R,RR>
  found: Collector<T#2,CAP#1,SortedSet<T#2>>,Collection[...]edSet
  reason: cannot infer type-variable(s) T#3
    (actual and formal argument lists differ in length)
  where T#1,A,R,RR,T#2,T#3 are type-variables:
    T#1 extends Object declared in method <T#1,A,R,RR>collectingAndThen(Collector<T#1,A,R>,Function<R,RR>)
    A extends Object declared in method <T#1,A,R,RR>collectingAndThen(Collector<T#1,A,R>,Function<R,RR>)
    R extends Object declared in method <T#1,A,R,RR>collectingAndThen(Collector<T#1,A,R>,Function<R,RR>)
    RR extends Object declared in method <T#1,A,R,RR>collectingAndThen(Collector<T#1,A,R>,Function<R,RR>)
    T#2 extends Comparable<T#2>
    T#3 extends Object declared in method <T#3>unmodifiableSortedSet(SortedSet<T#3>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error
$javac-version
选择了以下选项:-Duser.language=en-Duser.country=GB
JavaC1.8.0_73
$javac SOExample.java
选择了以下选项:-Duser.language=en-Duser.country=GB
java:16:error:MethodCollectingAndThen类内收集器无法应用于给定类型;
返回Collectors.collectionAndThen(toSortedSet(),Collections::unmodifiableSortedSet);
^
必需:收集器,函数
找到:收集器,集合[…]数据集
原因:无法推断类型变量T#3

(实际参数列表和正式参数列表长度不同) 其中T#1、A、R、RR、T#2、T#3是类型变量: T#1扩展了方法collectingAndThen(收集器,函数)中声明的对象 方法CollectionAndThen(收集器,函数)中声明的扩展对象 R扩展方法collectingAndThen(收集器,函数)中声明的对象 RR扩展方法collectingAndThen(收集器,函数)中声明的对象 T#2扩展到可比较 T#3扩展方法unmodifiableSortedSet(SortedSet)中声明的对象 其中CAP#1是一个新类型变量: CAP#1将对象从捕获扩展到? 1错误
如果我将有问题的行更改为以下内容,则代码将在两个编译器下编译:

return Collectors.collectingAndThen(toSortedSet(), (SortedSet<T> p) -> Collections.unmodifiableSortedSet(p));
return Collectors.collecting然后(toSortedSet(),(SortedSet p)->Collections.unmodifiableSortedSet(p));
这是ecj、javac中的一个bug,还是允许这两种行为的欠规范


Javac在Java9和Java10中的行为相同。

有趣的是,它编译时不需要
toSortedSet

package com.stackoverflow;

import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public class SOExample {

    public static <T extends Comparable<T>> Collector<T, ?, SortedSet<T>> toSortedSet() {
        return Collectors.toCollection(TreeSet::new);
    }

    public static <T extends Comparable<T>> Collector<T, ?, SortedSet<T>> toUnmodifiableSortedSet() {
        return Collectors.collectingAndThen(toSortedSet(), Collections::<T> unmodifiableSortedSet);
    }
}
public static <T extends Comparable<T>> Collector<T, ?, SortedSet<T>> toUnmodifiableSortedSet() {
    return Collectors.collectingAndThen(Collectors.toCollection(TreeSet::new), Collections::<T>unmodifiableSortedSet);
}
关于为什么不能按原样编译的问题,我怀疑这与两种方法之间的捕获类型不一样有关,
toSortedSet
需要与
toUnmodifiableSortedSet
中使用的
t
的确切类型相同(正如您为两种方法定义的泛型
t

我进一步相信这就是原因,因为您可以为您的
类定义一个泛型类型
T
,并在两种方法中使用它(如果您删除
static
):


public-class-TestOracle已将此作为一个测试来接受。

它编译时也不使用
toSortedSet
返回Collectors.collectionandthen(Collectors.toCollection(TreeSet::new),Collections::unmodifiableSortedSet)“实际参数列表和形式参数列表长度不同”我无法想象这些列表会是什么。雅各布,伟大的观察,非常奇怪的行为!肯定是javac bug吗?对我来说,它看起来确实像javac bug-错误消息毫无意义。谢谢Jacob,你认为它是javac中的bug吗?我不这么认为;我认为这只是因为你为每个方法定义了两种不同的泛型类型,
T
。所以ecj不应该编译它?我认为不应该,除非ecj隐含地推断
toUnmodifiableSortedSet
中定义的
T
应该是
toSortedSet
中使用的。我同意不假设,但目前甚至想不出任何关于错误消息的解释。
public class Test<T extends Comparable<? super T>> {
    public static void main(String[] args) throws Exception {
        System.out.println(Stream.of(5, 3, 4, 2, 1, 5, 4, 3, 2, 1)
            .collect(new Test<Integer>().toUnmodifiableSortedSet()));
    }

    public Collector<T, ?, SortedSet<T>> toSortedSet() {
        return Collectors.toCollection(TreeSet::new);
    }

    public Collector<T, ?, SortedSet<T>> toUnmodifiableSortedSet() {
        return Collectors.collectingAndThen(toSortedSet(), Collections::unmodifiableSortedSet);
    }
}