Ao atualizar minha instalação do Eclipse IDE de Oxygen.3a (4.7.3) para Photon Tenho notado que alguns dos meus códigos quebrou apesar compilar (e trabalho) bem anteriormente.
Considere o seguinte código:
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);
}
}
Em Photon, um erro aparece dizendo que os Stream.concat
retornos Stream<Object>
, não Stream<MyInterface>
. Em Oxygen, isso não aconteceu (o tipo de retorno foi Stream<MyInterface>
). Parece que algo estava lançando implicitamente o tipo de retorno filter
para Stream<? extends MyClass, MyInterface>
que, em seguida, levar a Stream.concat
devolução do tipo esperado. Este foi, naturalmente, segura semanticamente como todos os elementos no fluxo retornado por filter
se implementar MyInterface
.
Por que este código quebrar? Como eu poderia começar comportamento anterior?
resumo:
- Seu código é inválido.
- compilador Java de oxigênio incorretamente permite o código para compilar.
- compilador Java da Photon corretamente relata um erro com o seu código.
concat()
irá retornar um fluxo de um tipo que é a correspondência mais próxima para os tipos de fluxos de ser concatenados. Por exemplo, se você concat()
um Stream<Int>
com um Stream<Long>
, em seguida, concat()
retornará um Stream<Number>
.
E se concat()
duas correntes cujos elementos não têm qualquer relação com o outro, como Stream<String>
e Stream<Long>
, em seguida, concat()
retornará um Stream<Object>
. Isso é o que acontece em seu código, uma vez MyClass
e MyInterface
não têm qualquer relação entre si, além de ter Object
como um pai.
Parece que algo estava lançando implicitamente o tipo de retorno de filtro para riacho que, em seguida, levar a Stream.concat retornando o tipo esperado.
Essa explicação parece tentador uma vez que parece encaixar os fatos, mas o que acontece se o predicado em seu filtro é alterado para teste para Runnable
em vez de MyInterface
?
Stream<MyInterface> concatenation2 = Stream.concat(
myClassStream.filter(element -> element instanceof Runnable),
myInterfaceStream);
O código ainda compila e a dica é inalterada, de modo a filtragem claramente não está impactando o tipo de retorno. Dito de outra forma, o primeiro parâmetro para concat()
retornará um Stream<MyClass>
, independentemente do que é feito em filter()
. O fato de que seu filtro garantido que ele também retornar apenas MyInterface
elementos não é relevante, mas parecia ser significativa porque o tipo da variável de receber o fluxo de concat()
era Stream<MyInterface>
.
E o que acontece se o tipo da variável de receber o fluxo de concat()
é alterada de MyInterface
alguma coisa absurda e sem sentido, como Deque<LocalDateTime>
? ...
Stream<Deque<LocalDateTime>> concatenation3 = Stream.concat(
myClassStream.filter(element -> element instanceof MyInterface),
myInterfaceStream);
Duas coisas são notáveis:
- Mesmo que esse código é obviamente inválido, ainda compila em oxigênio (mas não em Photon).
- A dica para
concat()
agora mostra seu tipo de retorno a serStream<Deque<LocalDateTime>>
o que claramente não faz sentido.
Por que este código quebrar? Como eu poderia começar comportamento anterior?
Compilador de oxigênio estava permitindo que as definições das variáveis inválidos usando Stream.concat()
, e parece que este foi fixado em Photon. Você não deve querer que o comportamento anterior, uma vez que estava incorreto.