【问题标题】:Eclipse IDE Java implicit castingEclipse IDE Java 隐式转换
【发布时间】:2018-07-18 10:18:16
【问题描述】:

在将我的 Eclipse IDE 安装从 Oxygen.3a (4.7.3) 更新到 Photon 时,我注意到尽管之前编译(和工作)正常,但我的一些代码已经损坏。

考虑以下代码:

import java.util.ArrayList;
import java.util.stream.Stream;

public class Test {

    class MyClass {

    }

    interface MyInterface {

    }

    public static void main(String[] args) {

        Stream<MyClass> myClassStream = new ArrayList<MyClass>().stream();
        Stream<MyInterface> myInterfaceStream = new ArrayList<MyInterface>().stream();

        Stream<MyInterface> concatenation = Stream.concat(

                // Tooltip for filter() displays the result type of Stream<MyClass>
                myClassStream.filter(element -> element instanceof MyInterface),

                // Tooltip displays type Stream<MyInterface>
                myInterfaceStream);
    }

}

在 Photon 中,会出现一个错误,指出 Stream.concat 返回 Stream&lt;Object&gt;,而不是 Stream&lt;MyInterface&gt;。在 Oxygen 中,它没有(返回类型为 Stream&lt;MyInterface&gt;)。看起来有些东西隐式地将filter 的返回类型转换为Stream&lt;? extends MyClass, MyInterface&gt;,然后导致Stream.concat 返回预期的类型。当然,这在语义上是安全的,因为filter 返回的流中的所有元素都实现了MyInterface

为什么这段代码会中断?我怎样才能得到以前的行为?

【问题讨论】:

  • 错误报告似乎有所改进。做myClassStream.filter(...).(MyInterface.class::cast)
  • Eclipse 使用自己的 Java 编译器,所以这与 javac 无关。
  • 好吧,在实际代码中MyClassMyInterface 也没有连接。但是,MyClass 的几个子类实现了MyInterface,过滤器会尝试对它们进行排序。
  • @JoopEggen 喜欢这样吗? myClassStream.filter(element -&gt; element instanceof MyInterface).map(MyInterface.class::cast)
  • 是的。现在流属于 MyInterface,而不是 MyClass,它在运行时恰好是 MyInterface 对象。

标签: java eclipse casting implicit-conversion


【解决方案1】:

总结:

  • 您的代码无效。
  • Oxygen 的 Java 编译器错误地允许您的代码编译。
  • Photon 的 Java 编译器正确报告您的代码错误。

concat() 将返回一个 Stream 类型,该类型与被连接的流的类型最接近。例如,如果你 concat()Stream&lt;Int&gt;Stream&lt;Long&gt;,那么 concat() 将返回 Stream&lt;Number&gt;

如果你concat() 两个流的元素彼此没有关系,例如Stream&lt;String&gt;Stream&lt;Long&gt;,那么concat() 将返回一个Stream&lt;Object&gt;。这就是您的代码中发生的情况,因为 MyClassMyInterface 彼此之间没有任何关系,除了将 Object 作为父级之外。

看起来有些东西隐式地转换了返回类型 过滤到 Stream 然后导致 Stream.concat 返回预期的类型。

该解释看起来很诱人,因为它似乎符合事实,但是如果将过滤器中的谓词更改为测试Runnable 而不是MyInterface,会发生什么情况?

Stream<MyInterface> concatenation2 = Stream.concat(
    myClassStream.filter(element -> element instanceof Runnable),
    myInterfaceStream);

代码仍然可以编译并且工具提示没有改变,所以过滤显然不会影响返回类型。换句话说,concat() 的第一个参数将返回Stream&lt;MyClass&gt;,而不管filter() 中做了什么。您的过滤器保证它也只会返回 MyInterface 元素这一事实并不相关,但它似乎很重要,因为从 concat() 接收流的变量类型是 Stream&lt;MyInterface&gt;

如果从concat()接收Stream的变量类型从MyInterface变为Deque&lt;LocalDateTime&gt;这样荒谬无意义的东西会怎样?...

Stream<Deque<LocalDateTime>> concatenation3 = Stream.concat(
    myClassStream.filter(element -> element instanceof MyInterface),
    myInterfaceStream);

有两点值得注意:

  • 即使该代码显然无效,它仍然可以在 Oxygen 上编译(但不是在 Photon 上)。
  • concat() 的工具提示现在显示其返回类型为Stream&lt;Deque&lt;LocalDateTime&gt;&gt;,这显然没有意义。

为什么这段代码会中断?我怎样才能得到以前的行为?

Oxygen 的编译器允许使用 Stream.concat() 进行无效的变量定义,而这似乎已在 Photon 中得到修复。你不应该想要以前的行为,因为它是不正确的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多