此代码使用ecj但不使用javac编译。这是ecj,javac或两者中的错误吗?

时间:2018-04-10 21:01:14

标签: java javac ecj

以下代码创建Collector,生成UnmodifiableSortedSet

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);
    }
}

代码在ecj编译器下编译:

$ java -jar ~/Downloads/ecj-3.13.101.jar -source 1.8 -target 1.8 SOExample.java
Picked up _JAVA_OPTIONS: -Duser.language=en -Duser.country=GB

然而在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

如果我将违规行更改为以下内容,则代码将在两个编译器下编译:

return Collectors.collectingAndThen(toSortedSet(), (SortedSet<T> p) -> Collections.unmodifiableSortedSet(p));

这是ecj,javac还是一个允许这两种行为的不足规范的错误?

Javac在java 9和10中的行为相同。

2 个答案:

答案 0 :(得分:3)

Oracle已将此接受为compiler bug

答案 1 :(得分:2)

有趣的是,它编译时无需toSortedSet

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

如果您明确地将T传递给toSortedSet(删除static并使用this.<T>toSortedSet()同样有效),它也会进行编译:

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

关于你为什么不按原样编译的问题,我怀疑它与两种方法之间的捕获类型不一致,toSortedSet需要相同的{{1}类型在T中使用(为两种方法定义泛型类型toUnmodifiableSortedSet)。

我进一步认为这是原因,因为您可以为T定义通用类型T并在两种方法中使用它(如果您删除class):

static

以上编译并运行得很好。