尝试打印JAVA8收集器的结果时出现歧义错误

尝试打印JAVA8收集器的结果时出现歧义错误,java,java-8,java-stream,collectors,ecj,Java,Java 8,Java Stream,Collectors,Ecj,我在打印JAVA8收集器的结果时遇到了模糊错误 我试图打印Product对象中ID总和的结果,但出现以下错误: “println(double)方法对于PrintStream类型不明确” 下面是一小行代码,其中我得到了编译错误: 已编辑:添加代码片段以了解更多详细信息: java域类 包com.sample.replicate.bug public class Product { private double id; private String productName;

我在打印JAVA8收集器的结果时遇到了模糊错误

我试图打印
Product
对象中ID总和的结果,但出现以下错误:

“println(double)方法对于PrintStream类型不明确”

下面是一小行代码,其中我得到了编译错误:

已编辑:添加代码片段以了解更多详细信息:

  • java域类
  • 包com.sample.replicate.bug

    public class Product {
    
        private double id;
    
        private String productName;
    
        public double getId() {
            return id;
        }
    
        public void setId(double id) {
            this.id = id;
        }
    
        public String getProductName() {
            return productName;
        }
    
        public void setProductName(String productName) {
            this.productName = productName;
        }
    
    }
    
  • Main.java类,我在其中得到编译错误:
  • 下面是我遇到编译错误的代码行:

    System.out.println(productList.stream().collect(Collectors.summingDouble(x -> x.getId())));
    
    类快照:

    如果在单独的行中使用收集器(在
    println
    方法之外),则不会出现任何错误

    如果我们在
    println()
    方法中使用JAVA 8收集器,为什么编译器不能检测它的确切返回类型

    使用命令提示符添加另一种方法的详细信息:

    我尝试使用相同JDK版本的命令提示符,程序编译并成功执行。所以霍尔格的答案似乎是正确的。这似乎仅适用于Eclipse编译器:

    我不能完全确定这里的确切代码,但是如果没有必需的类型(
    println
    有许多重载参数),并且流的泛型类型,就会产生歧义。尤其是使用
    Double id
    而不是
    Double
    。也许其他人可以做一个更好的解释

    对局部变量的赋值可能有效


    更好的方法是使用基元类型的流。上面使用了一个
    双流
    。对于一个“id”,我更希望是一个长流。

    这是Eclipse编译器中的一个错误,兔子洞甚至比编译器错误更深。我将您的代码示例简化为

    public static void main(String[] args)
    {
      println(Stream.of(42).collect(Collectors.summingDouble(d -> d)));
    }
    public static void println(double x) {}
    public static void println(char[] x) {}
    public static void println(String x) {}
    public static void println(Object x) {}
    
    我只保留了影响编译器行为的
    println
    方法

    有方法
    println(Object x)
    ,这是一个应该被调用的方法,因为它是唯一一个适用于没有装箱操作的方法,
    println(double)
    ,这是错误消息中提到的并且在取消装箱后适用的方法,还有两个方法
    println(char[]x)
    println(String x)
    ,这根本不适用

    删除
    println(double x)
    方法会使错误消失,这是可以理解的,即使错误不正确,但奇怪的是,删除
    println(Object x)
    方法并不能解决错误

    更糟糕的是,删除不适用的方法,
    println(char[]x)
    println(String x)
    ,也会删除错误,但会生成调用错误的不适用方法的代码:

    public static void main(String[] args)
    {
      println(Stream.of(42).collect(Collectors.summingDouble(d -> d)));
    }
    public static void println(double x) { System.out.println("println(double)"); }
    public static void println(char[] x) { System.out.println("println(char[])"); }
    //public static void println(String x) { System.out.println("println(String)"); }
    public static void println(Object x) { System.out.println("println(Object)"); }
    
    线程“main”java.lang.ClassCastException中的异常:java.lang.Double无法转换为[C] 在Tmp2.main(未知源) 线程“main”java.lang.ClassCastException中的异常:java.lang.Double无法转换为java.lang.String 在Tmp2.main(未知源) 我认为,我们不需要深入研究正式的Java语言规范,就可以认识到这种行为是不合适的

    删除两个不适用的方法,
    println(char[]x)
    println(String x)
    ,编译器会选择正确的方法,
    println(Object x)
    而不是
    println(double x)
    ,但这并不令人印象深刻

    作为参考,我使用版本Oxygen.3a Release(4.7.3a),build 20180405-1200进行了测试。可能还有其他版本也受到影响。

    是的,这是一个问题,但更仔细的调查表明,这可能是由于JLS中的遗漏造成的

    更具体地说,如果将中的一句话更改为如下所示,错误将消失:

    旧的:

    对于多边形类实例创建表达式或多边形方法调用表达式,C包含所有约束公式,当推断多边形表达式的调用类型时,这些约束公式将出现在§18.5.2生成的集合C中

    仅提及“限制条件”似乎是不够的

    拟议新设:

    对于poly类实例创建表达式或poly方法调用表达式,C包含在推断poly表达式的调用类型时减少和合并§18.5.2生成的集合C所产生的所有类型边界和捕获边界

    PS:Javac以在内部和外部推理之间实现比JLS中捕获的更多/不同的数据流而闻名,这可能是Javac选择
    println(对象)的原因
    。在某些方面,此实现可能更接近预期的语义,在本问题的示例中,常识与javac是一致的。这就是为什么IMHO应该专注于改进JLS(以及过渡ecj)

    EDIT:虽然上面的分析是可编辑的,修复了问题,甚至可能与javac的实际操作相匹配,但它无法解释为什么问题只出现在
    println(…)
    的重载解析下,而不出现在
    char[]
    变量的赋值中


    在对这一差异进行更多研究后,制定了一个替代变更,该变更将有效(通过几个间接方式)强制编译器重新计算捕获边界,而不是像上面建议的那样放弃它。此更改与当前JLS一致。此问题的确切因果链超出了本论坛的范围,但请感兴趣的各方阅读上面链接的Eclipse bug的一些背景。

    对我来说很好,有什么问题有
    id
    的类型吗?可能有任何关于它的抽象信息吗?无法在muy环境中复制。您能分享编译器的确切输出或IDE的屏幕截图吗?我得到了
    public static void main(String[] args)
    {
      println(Stream.of(42).collect(Collectors.summingDouble(d -> d)));
    }
    public static void println(double x) { System.out.println("println(double)"); }
    public static void println(char[] x) { System.out.println("println(char[])"); }
    //public static void println(String x) { System.out.println("println(String)"); }
    public static void println(Object x) { System.out.println("println(Object)"); }
    
    public static void main(String[] args)
    {
      println(Stream.of(42).collect(Collectors.summingDouble(d -> d)));
    }
    public static void println(double x) { System.out.println("println(double)"); }
    //public static void println(char[] x) { System.out.println("println(char[])"); }
    public static void println(String x) { System.out.println("println(String)"); }
    public static void println(Object x) { System.out.println("println(Object)"); }