tutorial español downloads docs java generics java-8 language-specifications

español - java se 8 tutorial



¿Por qué agregar ".map(a-> a)" permite que esto se compile? (1)

A menos que me falte algo en cómo se producen las inferencias de FunctionalInterface, parece bastante obvio que no se puede llamar a reducir en un Stream <? súper predicado> porque no tiene suficiente escritura para ser inferido como BinaryOperator.

La referencia del método oculta una parte muy importante de la historia, el segundo parámetro.

return predicates.map(a->a).reduce((predicate, other) -> predicate.or(other));

Si elimina la llamada para asignar, el compilador no tiene la oportunidad de escribir la secuencia de forma adecuada para satisfacer los requisitos de la segunda captura. Con map, al compilador se le da la latitud para determinar los tipos necesarios para satisfacer las capturas, pero sin un enlace concreto de los genéricos, las dos capturas solo pueden satisfacerse con una Corriente de Objeto que es probable que resultaría a través de map ().

La interfaz de Predicate como se implementa ahora es simplemente construir una cadena, pero se espera que el uso sea una entidad compuesta. Se supone que toma un solo parámetro, pero de hecho la naturaleza de AND y OR requiere dos parámetros sin una garantía de tipo debido a las deficiencias de los genéricos de Java. De esta manera, la API parece ser menos que idealmente diseñada.

La llamada a map () cede el control de la escritura, desde el Stream of Predicates explícito, a uno que el compilador puede garantizar que satisfaga todas las capturas.

Los dos siguientes satisfacen al compilador en IDEone , induciendo directamente un tipo suficientemente flexible en el caso de Object, o un tipo conocido en el caso de T.

public <T> Optional<? extends Predicate<? super T>> with(Stream<Predicate<Object>> predicates) public <T> Optional<? extends Predicate<? super T>> with(Stream<Predicate<T>> predicates)

Los genéricos de Java todavía necesitan una forma de forzar la equivalencia de tipo de captura, ya que los métodos de ayuda son claramente insuficientes.

Esto está relacionado con mi respuesta a "tipos incompatibles de reducción de flujo" . No sé por qué lo que sugerí funciona, y Holger me presionó con razón. Pero incluso él no parece tener una explicación clara de por qué funciona. Entonces, hagámoslo como su propia pregunta:

El siguiente código no se compila en javac (para los enlaces a ideone a continuación, este es sun-jdk-1.8.0_51 , por http://ideone.com/faq ):

public <T> Object with(Stream<Predicate<? super T>> predicates) { return predicates.reduce(Predicate::or); }

Y con razón: reunir dos predicados de esta secuencia es como escribir:

Predicate<? super T> a = null; Predicate<? super T> b = null; a.or(b); // Compiler error!

Sin embargo, se compila en intellij, aunque con una advertencia de tipo en bruto en el Predicate::or referencia del método. Aparentemente, también se compilaría en eclipse (según la pregunta original).

Pero este código hace:

public <T> Object with(Stream<Predicate<? super T>> predicates) { return predicates.map(a -> a).reduce(Predicate::or); // ^----------^ Added }

Demo de Ideone

A pesar del hecho de que pensé intentar esto, no tengo claro exactamente por qué funcionaría esto. Mi explicación es que .map(a -> a) actúa como un "cast", y le da al algoritmo de inferencia de tipos un poco más de flexibilidad para elegir un tipo que permita aplicar la reduce . Pero no estoy seguro exactamente de qué tipo es ese tipo.

Tenga en cuenta que esto no es equivalente a usar .map(Function.identity()) , ya que está restringido para devolver el tipo de entrada. demo ideone

¿Alguien puede explicar por qué esto funciona con referencia a la especificación del idioma, o si, como lo sugiere Holger, es un error de compilación?

Un poco más de detalle:

El tipo de retorno del método se puede hacer un poco más específico; Lo omití arriba para que los genéricos desagradables en el tipo de retorno no interfieran:

public <T> Optional<? extends Predicate<? super T>> with( Stream<Predicate<? super T>> predicates) { return predicates.map(a -> a).reduce(Predicate::or); }

Esta es la salida de compilar con -XDverboseResolution=all . No estoy completamente seguro de si esta es la salida más relevante que puedo publicar para depurar la inferencia de tipos; Por favor avise si hay algo mejor:

Interesting.java:5: Note: resolving method <init> in type Object to candidate 0 class Interesting { ^ phase: BASIC with actuals: no arguments with type-args: no arguments candidates: #0 applicable method found: Object() Interesting.java:7: Note: resolving method map in type Stream to candidate 0 return predicates.map(a -> a).reduce(Predicate::or); ^ phase: BASIC with actuals: <none> with type-args: no arguments candidates: #0 applicable method found: <R>map(Function<? super T#1,? extends R>) (partially instantiated to: (Function<? super Predicate<? super T#2>,? extends Object>)Stream<Object>) where R,T#1,T#2 are type-variables: R extends Object declared in method <R>map(Function<? super T#1,? extends R>) T#1 extends Object declared in interface Stream T#2 extends Object declared in method <T#2>with(Stream<Predicate<? super T#2>>) Interesting.java:7: Note: Deferred instantiation of method <R>map(Function<? super T#1,? extends R>) return predicates.map(a -> a).reduce(Predicate::or); ^ instantiated signature: (Function<? super Predicate<? super T#2>,? extends Predicate<CAP#1>>)Stream<Predicate<CAP#1>> target-type: <none> where R,T#1,T#2 are type-variables: R extends Object declared in method <R>map(Function<? super T#1,? extends R>) T#1 extends Object declared in interface Stream T#2 extends Object declared in method <T#2>with(Stream<Predicate<? super T#2>>) where CAP#1 is a fresh type-variable: CAP#1 extends Object super: T#2 from capture of ? super T#2 Interesting.java:7: Note: resolving method reduce in type Stream to candidate 1 return predicates.map(a -> a).reduce(Predicate::or); ^ phase: BASIC with actuals: <none> with type-args: no arguments candidates: #0 not applicable method found: <U>reduce(U,BiFunction<U,? super T,U>,BinaryOperator<U>) (cannot infer type-variable(s) U (actual and formal argument lists differ in length)) #1 applicable method found: reduce(BinaryOperator<T>) #2 not applicable method found: reduce(T,BinaryOperator<T>) (actual and formal argument lists differ in length) where U,T are type-variables: U extends Object declared in method <U>reduce(U,BiFunction<U,? super T,U>,BinaryOperator<U>) T extends Object declared in interface Stream Interesting.java:7: Note: resolving method metafactory in type LambdaMetafactory to candidate 0 return predicates.map(a -> a).reduce(Predicate::or); ^ phase: BASIC with actuals: Lookup,String,MethodType,MethodType,MethodHandle,MethodType with type-args: no arguments candidates: #0 applicable method found: metafactory(Lookup,String,MethodType,MethodType,MethodHandle,MethodType) Interesting.java:7: Note: resolving method metafactory in type LambdaMetafactory to candidate 0 return predicates.map(a -> a).reduce(Predicate::or); ^ phase: BASIC with actuals: Lookup,String,MethodType,MethodType,MethodHandle,MethodType with type-args: no arguments candidates: #0 applicable method found: metafactory(Lookup,String,MethodType,MethodType,MethodHandle,MethodType)