【问题标题】:Lambda expression with generic具有泛型的 Lambda 表达式
【发布时间】:2016-07-12 07:48:48
【问题描述】:

我正在学习 Java 中的 lambda 表达式,但是,我曾考虑将它与泛型类型一起使用。 (例如 int、String)。据我学习和研究在 Java 中使用 lambda 表达式,它必须在接口中声明。然后,在您想使用的地方定义它的实现。 (即(prototype args) -> {definition})。我试过只写带有类型问题的基本示例,如下所示。我只是想将它与Stringint 类型一起用作练习。但是,我无法将泛型类型初始化为0。我可以为null 做。我不确定null 是否等于0。问题如何解决?

public class Test<T,U> {

    public static <T,U> void main(String[] args) {

        Test myTest = new Test();

        Str myHello = (message1, message2) -> {
                            System.out.println("Hello " + message1 + message2);};

        myHello.welcome("Mr. ", "rickroll");

        MyGen addition = (U... operationArgs) -> {
                            T sum = 0;
                            for (U i : operationArgs) {
                                sum += i;
                            }
                            return sum;};

        System.out.println("2+3+4+5 = " + myTest.operate(addition, 2, 3, 4, 5));

        System.out.println("A.....gl ?" + myTest.operate(addition, "b", "c", "d", "e", "f"));
    }

    private T operate(MyGen choice, U... args) {
        return (T)choice.asYouWish(args);
    }

    interface Str {
        public void welcome(String a, String b);
    }

    interface MyGen<T,U> {
        public T asYouWish(U... args);
    }
}

【问题讨论】:

  • 将泛型类型初始化为0 没有意义。如果TList&lt;String&gt; 类型怎么办?
  • 如果您了解 C++,请不要将 Java 泛型与您从 C++ 中的模板中了解的内容混淆。 Java 泛型不像 C++ 模板。您不能将0 分配给T 类型的变量,因为T 可以是任何类型,并且您不能将0 分配给任何任意类型。 += 也不能用于任意类型。
  • 不,不是。 T 可以是任何东西。我可以创建一个新实例:new Test&lt;List&lt;String&gt;, 2DPoint&gt;()

标签: java generics lambda java-8


【解决方案1】:

您声明了几个类型参数而不使用它们,甚至可能不理解它们是独立的类型参数,尽管它们具有相同的名称。而且当你声明一个带有类型参数的类时,你必须在使用该类时声明类型参数。

所以当你定义一个类时

public class Test<T,U> {
    public static <T,U> void main(String[] args) { … }
    private T operate(MyGen choice, U... args) { … }
    interface MyGen<T,U> {
        public T asYouWish(U... args);
    }
}

和声明没什么区别

public class Test<T,U> {
    public static <A,B> void main(String[] args) { … }
    private T operate(MyGen choice, U... args) { … }
    interface MyGen<X,Y> {
        public X asYouWish(Y... args);
    }
}

将它们全部命名为TU 不会建立关系,只会使人类读者感到困惑。类的类型参数只影响它的非static 成员,Test 的唯一非static 成员是方法operate,它引用MyGen 而没有实际的类型参数。

正确的用法是

private T operate(MyGen<T,U> choice, U... args) {
    return choice.asYouWish(args);
}

因此您声明MyGen 参数必须根据Test 的参数化进行参数化,现在您可以在没有警告和类型转换的情况下调用asYouWish

需要强调的是,当你在实例化时为TU定义类型参数时,不能使用Test的同一个实例来使用Strings和Integers的方法Test.

此外,main 方法的类型参数独立于Test 的类型参数,并且由于它们没有用于方法的签名中,因此毫无用处。在 lambda 表达式中引用它们是没有意义的,即使 lambda 表达式的主体中没有编译器错误,在使用该函数的范围内也没有该类型的实例。

把它放在一起,你得到

public class Test<T,U> {

    public static void main(String[] args) {
        Str myHello = (message1, message2) ->
                        System.out.println("Hello " + message1 + message2);
        myHello.welcome("Mr. ", "rickroll");

        {
            Test<Integer,Integer> myTest = new Test();
            MyGen<Integer,Integer> addition = operationArgs -> {
                int sum = 0;
                for(int i: operationArgs) sum += i;
                return sum;
            };
            System.out.println("2+3+4+5 = " + myTest.operate(addition, 2, 3, 4, 5));
        }
        {
            Test<String,String> myTest = new Test();
            MyGen<String,String> addition = operationArgs -> {
                String sum = "";
                for(String i: operationArgs) sum += i;
                return sum;
            };
            System.out.println("A.....gl ?"
                + myTest.operate(addition, "b", "c", "d", "e", "f"));
        }
    }
    private T operate(MyGen<T,U> choice, U... args) {
        return choice.asYouWish(args);
    }
    interface Str {
        public void welcome(String a, String b);
    }
    interface MyGen<X,Y> {
        public X asYouWish(Y... args);
    }
}

您可以摆脱对Test 实例进行参数化的要求,只需将operate 转换为通用static 方法,因为无论如何都不需要该实例。如果你想定义一个通用的MyGen 函数,你必须抽象出+ 运算符,因为它与String 的情况不同,Java 中没有运算符重载。

此外,您必须在不需要中性元素的情况下实现它,因为0 在尝试对字符串使用相同的函数时不会神奇地变成空字符串。

import java.util.function.BinaryOperator;

public class Test {

    public static void main(String[] args) {
        Str myHello = (message1, message2) ->
                        System.out.println("Hello " + message1 + message2);
        myHello.welcome("Mr. ", "rickroll");

        example(Integer::sum, "2+3+4+5 = ", 2, 3, 4, 5);
        example(String::concat, "A.....gl ?", "b", "c", "d", "e", "f");
    }
    private static <E> void example(BinaryOperator<E> plus, String head, E... values) {
        MyGen<E,E> addition = args -> {
            E sum=args[0];
            for(int ix=1; ix<args.length; ix++) sum = plus.apply(sum, args[ix]);
            return sum;
        };
        System.out.println(head + Test.operate(addition, values));
    }
    private static <T,U> T operate(MyGen<T,U> choice, U... args) {
        return choice.asYouWish(args);
    }
    interface Str {
        public void welcome(String a, String b);
    }
    interface MyGen<X,Y> {
        public X asYouWish(Y... args);
    }
}

这仅用于演示目的,因为该工作已经完成,例如您可以将example 方法更改为:

private static <E> void example(BinaryOperator<E> plus, String head, E... values) {
    MyGen<E,E> addition = args -> Arrays.stream(args).reduce(plus).get();
    System.out.println(head + Test.operate(addition, values));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多