método elegido llamada en línea de referencia método

iobender:

Tengo el siguiente programa que falla al compilar:

Sólo el bloque 1 compila bien y funciona como se espera - Puedo condicionalmente seleccione un objeto y llamar a un método en él en línea.

Sólo bloquear 2 también compila bien y funciona como se esperaba - Puedo asignar una referencia condicionalmente método a una Supplier<String>variable y llamada .get()en esa variable.

Sin embargo bloque 3 falla al compilar:

Lambda.java:31: error: method reference not expected here
    String res = ((Supplier<String>) (args.length > 0 ? Lambda::foo : Lambda::bar)).get();
                                                        ^
Lambda.java:31: error: method reference not expected here
    String res = ((Supplier<String>) (args.length > 0 ? Lambda::foo : Lambda::bar)).get();

Yo creo que la combinación de las ideas en el bloque 1 y 2 que sería capaz de realizar el bloque 3 como el tipo de ((Supplier<String>) (args.length > 0 ? Lambda::foo : Lambda::bar))es Supplier<String>.

import java.util.function.Supplier;

class Lambda {

  private final String s;

  private Lambda(String s) {
    this.s = s;
  }

  private static String foo() {
    return "foo";
  }

  private static String bar() {
    return "bar";
  }

  private String str() {
    return s;
  }

  public static void main(String... args) {
    // Block 1
    Lambda l1 = new Lambda("x");
    Lambda l2 = new Lambda("y");
    System.out.println((args.length > 0 ? l1 : l2).str());

    // Block 2
    Supplier<String> s = (args.length > 0 ? Lambda::foo : Lambda::bar);
    System.out.println(s.get());

    // Block 3
    String res = ((Supplier<String>) (args.length > 0 ? Lambda::foo : Lambda::bar)).get();
    System.out.println(res);
  }

}

Para que quede claro: no estoy en busca de una solución aquí, esto no sería código de buena calidad en el primer lugar. Tengo curiosidad de por qué el último bloque falla al compilar.

Holger:

La razón es la siguiente definición en la especificación del lenguaje Java ®, §15.25.3

15.25.3. Referencia Expresiones condicionales

Una expresión condicional de referencia es una expresión poli si aparece en un contexto de asignación o un contexto invocación ( § 5.2 . § 5.3 ). De lo contrario, es una expresión independiente.

Desde contextos de fundición no están en la lista, la expresión condicional de referencia es una expresión independiente en ese contexto, lo que significa, que su tipo de resultado sólo está determinada por sus tipos de argumento. Como referencias de métodos no tienen un tipo por su cuenta, sino que se basan en un tipo de destino, no pueden ser utilizados aquí (sin otro tipo que proporciona constructo).

Comparar con §15.13 :

Expresiones Método de referencia son siempre expresiones poli ( §15.2 ).

Es un error de tiempo de compilación si una expresión de referencia método se produce en un programa en algún lugar distinto de un contexto de asignación ( § 5.2 ), un contexto invocación ( § 5.3 ), o un contexto de colada ( §5.5 ).

Así, mientras un contexto de fundición es una ubicación válida para un método de referencia, en general, la combinación de fundición contexto y condicionales de expresión resulta ser inválida debido a la naturaleza expresión independiente del condicional en el contexto de fundición.

A menos que, proporcionamos tipos explícitos dentro de la expresión, como con
args.length > 0 ? (Supplier<String>)Lambda::foo : (Supplier<String>)Lambda::bar, por supuesto.

Las consecuencias de esta regla se pueden demostrar con otros ejemplos que las expresiones lambda o referencias de métodos también, cuando pueden ser expresiones poli:

// poly expression, infers List<Number> for Arrays.asList(0) and 0 is assignable to Number
List<Number> list = args.length>0? Arrays.asList(0): null;

// stand-alone expression, fails with "List<Integer> cannot be converted to List<Number>"
List<Number> list = (List<Number>)(args.length>0? Arrays.asList(0): null);

No sé por qué el contexto de fundición no califica para una expresión condicional referencia a una expresión poli, pero así es como se ha especificado para Java a Java 8 11 ...

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=136628&siteId=1
Recomendado
Clasificación