compila o código em Eclipse, mas não javac: lambdas com subinterface funcional ao curry. Qual é correto?

Aaron Rotenberg:

Eu desenvolvi algum código em Eclipse, testado com sucesso, empurrou-o para o nosso servidor Jenkins CI, e recebi um email que Maven estava engasgada com um erro de compilação Java. I isolado posteriormente o problema e criou o seguinte exemplo mínimo mostrando a questão:

import java.util.List;
import java.util.function.Function;

class MinimalTypeFailureExample {
    public static void main(String[] args) {
        List<String> originalList = null;  // irrelevant
        List<IntToByteFunction> resultList = transform(originalList,
                outer -> inner -> doStuff(inner, outer));
        System.out.println(resultList);
    }

    static <F, T> List<T> transform(List<F> originalList,
            MyFunction<? super F, ? extends T> function) {
        return null;  // irrelevant
    }

    static Byte doStuff(Integer inner, String outer) {
        return null;  // irrelevant
    }
}

@FunctionalInterface
interface MyFunction<F, T> extends Function<F, T> {
    @Override
    T apply(F input);
}

@FunctionalInterface
interface IntToByteFunction {
    Byte applyIntToByte(Integer inner);
}

Em Eclipse, Isso compila código sem erro e aparece para executar como pretendido. No entanto, compilar com javac dá o seguinte erro:

MinimalTypeFailureExample.java:7: error: incompatible types: cannot infer type-variable(s) F,T
                List<IntToByteFunction> resultList = transform(originalList, outer -> inner -> doStuff(inner, outer));
                                                              ^
    (argument mismatch; bad return type in lambda expression
      T is not a functional interface)
  where F,T are type-variables:
    F extends Object declared in method <F,T>transform(List<F>,MyFunction<F,? extends T>)
    T extends Object declared in method <F,T>transform(List<F>,MyFunction<F,? extends T>)
1 error

Alterando o tipo de argumento transform()de MyFunctiona Function, ou remover a sequência especial ? extendsno tipo de argumento, faz com que a compilação de código exemplo em javac.

Claramente, Eclipse ou javac é uma violação da especificação de linguagem Java. A pergunta é, posso apresentar o relatório de bug no Eclipse ou javac ? As regras de inferência de tipo para lambdas genéricos são tão complexos que eu não tenho idéia se este programa é Java legal ou não de acordo com os JLS.

nota motivação

No código original, transform()foi Goiaba de com.google.common.collect.Lists.transform(). A MyFunctioninterface de era 's Goiaba com.google.common.base.Functioninterface, que se estende java.util.function.Functionpor razões históricas.

O propósito deste código era criar uma vista de uma lista de um primeiro tipo como uma lista de um segundo tipo. O segundo tipo era um tipo de interface funcional e queria preencher a lista de saída com funções deste tipo construído com base nos valores de entrada na lista, por isso a expressão lambda avaliar num.

Info versão para reprodutibilidade

versões Eclipse testado:

  • 2018-09 id (4.9.0) Constituição: 20180917-1800
  • 2019-03 RC1 (4.11 RC1) Desenvolver ID: 20190307-2044

versões javac testados:

howlger:

Parece que você executar em JDK bug JDK-8156954 , que foi corrigido no Java 9, mas não em Java 8.

É um erro de Java 8 javac, porque no seu exemplo todos os tipos de variáveis do transformmétodo pode ser inferida sem violar a especificação da linguagem Java da seguinte forma:

  • F:String (Através do primeiro parâmetro originalListde tipo List<String>)
  • T:IntToByteFunction (Através do tipo de retorno List<IntToByteFunction>)

Estes tipos de variáveis inferidas são compatíveis com o tipo do segundo parâmetro, o lambda acorrentado expressão:

  • outer -> inner -> doStuff(inner, outer)resolve (com doStuff(Integer, String)a
  • String -> Integer -> doStuff(Integer, String) rESOLVE
  • String -> Integer -> Byte é compatível com
  • String -> IntToByteFunction é compatível com
  • MyFunction<? super String, ? extends IntToByteFunction>

O seu exemplo pode ser minimizado ainda mais:

import java.util.function.Function;

class MinimalTypeFailureExample {

    void foo() {
        transform((Function<Integer, String>)null, o -> i -> {return "";});
    }

    <T, F> void transform(F f, MyFunction<T, ? extends F> m) {}

}

@FunctionalInterface
interface MyFunction<T, R> extends Function<T, R> {
    @Override
    R apply(T t);
}

MyFunctionSubstitui o mesmo com o mesmo ( R apply(T t);). Se Functionem vez de MyFunctionser usado ou se MyFunctionestende Functionmas sem @Override R apply(T t);seguida, o desaparecimento de erro. Também com Fem vez ? extends Fdo erro desaparece.

Mesmo que o seu exemplo difere do exemplo na mencionada erro, pode-se supor que é o mesmo bug, porque é o único "incompatibilidade argumento, mau tipo de retorno em lambda expressão bug que foi corrigido no Java 9, mas não em Java 8 e que ocorre apenas com funções de lambda, em combinação com Java genéricos.

Este artigo é coletado da Internet.

Se houver alguma infração, entre em [email protected] Delete.

editar em
0

deixe-me dizer algumas palavras

0comentários
loginDepois de participar da revisão

Artigos relacionados

TOP lista

quentelabel

Arquivo