Java 8中是否有代理人?

R R*_*R R 12 java lambda delegates java-8

Java 8中是否有代理人?

如果没有,我们如何在没有委托的情况下在JDK 8中使用lambda表达式?

什么是方法参考?他们和代表一样吗?

小智 24

JDK 8中没有委托.在引擎盖下,lambdas是功能接口的实例(只有一个抽象方法的接口).根据您传递lambda的位置,编译器可以确定它正在实现的接口.例如,Collections.sort方法接受Comparator实例作为第二个参数.比较器恰好是一个功能接口,因此编译器将检查您传递的lambda是否与Comparator中的抽象方法匹配.

方法参考只是一种简化.当lambda只是调用现有方法时,您可以使用这种新语法来简化构造.链接教程中的示例很好地展示了它:

代替:

Arrays.sort(rosterAsArray,
    (a, b) -> Person.compareByAge(a, b)
);
Run Code Online (Sandbox Code Playgroud)

方法参考更简单:

Arrays.sort(rosterAsArray, Person::compareByAge);
Run Code Online (Sandbox Code Playgroud)

看看lambdafaq.

  • Lambda被转换为对生成的私有方法的方法引用,因此如果您可以使用它,则方法引用稍微更有效. (2认同)

Too*_*eve 5

感谢Pacerier对该问题的评论,这里有一种方法可以实现C#(单功能)委托所做的事情,即使在Java 7或更低版本中也是如此.

// This defines the 'delegate'.
public interface IA {
    int f(int a);
}

public class MyClass {
    // f1 and f2 have the same signature as 'IA.f'.
    private int f1(int a) {
        return a + 1;
    }

    private int f2(int a) {
        return 2 * a;
    }

    // These wrappers are one way to return a 'delegate'.
    // Each wrapper creates one instance of an anonymous class.
    // Notice that we did not have to declare MyClass as implementing IA,
    // and that we can wrap different methods of MyClass into 'IA's.
    // Contrast this with 'MyClass implements IA', which would require
    // a method 'f' in 'MyClass', and would not provide a way to
    // delegate to different methods of 'MyClass'.
    public IA wrapF1() {
        return (new IA(){
            public int f(int a) {
                return f1(a);
            }
        });
    }

    public IA wrapF2() {
        return (new IA(){
            public int f(int a) {
                return f2(a);
            }
        });
    }

    // returns a 'delegate', either to 'f1' or 'f2'.
    public IA callMe(boolean useF2) {
        if (!useF2)
            return wrapF1();
        else
            return wrapF2();
    }

}
Run Code Online (Sandbox Code Playgroud)

用法

...
// Create and use three 'delegates'.
// Technically, these are not quite the same as C# delegates,
// because we have to invoke a method on each.
// That is, we must do 'ia0.f(..)' instead of 'ia0(..)'.
// Nevertheless, it satisfies the design requirement.
MyClass c = new MyClass();
IA ia0 = c.wrapF1();
IA ia1 = c.callMe(false);
IA ia2 = c.callMe(true);
int result0 = ia0.f(13);
int result1 = ia1.f(13);
int result2 = ia2.f(13);
Run Code Online (Sandbox Code Playgroud)

产量

result0: 14    <-- f1, so 13 + 1
result1: 14    <-- f1, so 13 + 1
result2: 26    <-- f2, so 2 * 13
Run Code Online (Sandbox Code Playgroud)

注意:如果您只需要给定"委托"的每个类的单个实现,那么更简单的解决方案是直接在类上实现接口.这是一个例子.该类已经有了f3,现在它已扩展为实现IA:

public class MyClass2
        implements IA {
    private int baseValue;
    private int anotherValue;

    public MyClass2(int baseValue, int anotherValue) {
        this.baseValue = baseValue;
        this.anotherValue = anotherValue;
    }

    public int f3(int v1, int v2) {
        return 2 * v1 + v2;
    }

    public int f(int a) {
        return f3(baseValue + a, anotherValue);
    }
}

IA ia3 = new MyClass2(10, 3);
int result3 = ia3.f(13);   // = f3(10 + 13) = 2 * 23 + 3 = 49
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它与任何其他接口实现没有什么不同.关键是可以使用Java接口通过一些额外的编码来满足design concept 返回与指定签名匹配的函数.在第二种更简单的情况下,接口直接放在类上.在第一个更通用的案例中,接口被放置在匿名内部类的匿名实例上.为了清晰和易于访问,我在包装函数中隔离了那些"委托创建者".

确实,结果与C#委托不完全相同,因为必须要做ia.f()而不是ia().尽管如此,设计目标已经实现.


注意:在Java 8中,使用lambdas简化了编码.我没有使用Java 8,所以我不会在这里包含Java 8实现.(欢迎任何人提交添加该实现的编辑.我建议在下面为我wrapF1()wrapF2()上面显示新的主体,因为这样可以很容易地比较Java 7和Java 8版本.)