Mientras que la actualización de la instalación de Eclipse IDE de Oxygen.3a (4.7.3) de fotones he notado que algunos de mi código ha roto a pesar de la compilación (y trabajar) bien con anterioridad.
Considere el siguiente 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);
}
}
En fotones, aparece un error diciendo que los Stream.concat
retornos Stream<Object>
, no Stream<MyInterface>
. En oxígeno, no lo hizo (el tipo de retorno era Stream<MyInterface>
). Parece que algo estaba echando implícitamente el tipo de retorno de filter
a Stream<? extends MyClass, MyInterface>
los cuales conducen a Stream.concat
devolver el tipo esperado. Esto fue, por supuesto, seguro semánticamente como todos los elementos de la secuencia devuelta por la filter
puso en práctica MyInterface
.
¿Por qué romper este código? ¿Cómo podría obtener un comportamiento anterior?
Resumen:
- Su código es válido.
- compilador Java de oxígeno permite incorrectamente su código para compilar.
- compilador Java de fotones informa correctamente un error con su código.
concat()
devolverá una corriente de un tipo que es el valor más cercano para que se concatenan los tipos de las corrientes. Por ejemplo, si concat()
una Stream<Int>
con un Stream<Long>
entonces concat()
devolverá una Stream<Number>
.
Y si usted concat()
dos corrientes cuyos elementos no tener ninguna relación entre sí, como por ejemplo Stream<String>
y Stream<Long>
, a continuación, concat()
devolverá una Stream<Object>
. Eso es lo que sucede en su código, ya MyClass
y MyInterface
no tener ninguna relación entre sí, aparte de tener Object
como padre.
Parece que algo estaba echando implícitamente el tipo de retorno del filtro de flujo de los cuales conducen a Stream.concat devolver el tipo esperado.
Esto se ve muy tentador explicación ya que parece ajustarse a los hechos, pero ¿qué ocurre si el predicado en el filtro se cambia a prueba para Runnable
en lugar de MyInterface
?
Stream<MyInterface> concatenation2 = Stream.concat(
myClassStream.filter(element -> element instanceof Runnable),
myInterfaceStream);
El código se compila y todavía no se ha modificado la descripción, por lo que el filtrado es claramente no afectando el tipo de retorno. Dicho de otra manera, el primer parámetro que concat()
devolverá un Stream<MyClass>
independientemente de lo que se hace en filter()
. El hecho de que el filtro garantiza que sería también devolver sólo MyInterface
los elementos no es relevante, pero que parecía ser significativa debido a que el tipo de la variable que recibe la corriente de concat()
era Stream<MyInterface>
.
Y lo que sucede si el tipo de la variable que recibe la corriente de concat()
se cambia de MyInterface
algo absurda y sin sentido tales como Deque<LocalDateTime>
? ...
Stream<Deque<LocalDateTime>> concatenation3 = Stream.concat(
myClassStream.filter(element -> element instanceof MyInterface),
myInterfaceStream);
Dos cosas son notables:
- A pesar de que el código es inválido, obviamente, todavía compila en oxígeno (pero no en fotones).
- La descripción de
concat()
ahora muestra el tipo que devuelve a serStream<Deque<LocalDateTime>>
lo que hace que claramente no tiene sentido.
¿Por qué romper este código? ¿Cómo podría obtener un comportamiento anterior?
Compilador de oxígeno fue lo que permite la definición de variables no válidos usando Stream.concat()
, y parece que esto se fijó en fotones. Usted no debe desea que el comportamiento anterior ya que era incorrecta.