Lambda表达式的深入学习

这篇文章里面,给大家写一个比较复杂的Lambda表达式调用的例子。

首先我们定义两个接口:

public interface Worker {
    void workOn(String something);
}
public interface Task {
    void assignTo(Worker worker, String taskName);
}

我们写一段代码来使用上面两个接口:

public class Main {

    static class Manager {
        public void assignTask(Task task) {
            task.assignTo(System.out::println, "日本語を学ぶ");
        }
    }

    public static void main(String args[]) throws Exception {
        Manager manager = new Manager();
        manager.assignTask((worker, taskName) -> {
            worker.workOn(taskName);
        });
    }
}

上面的代码包含了两处Lambda表达式,有一定的复杂度,我们来分析一下。首先是main()方法里面的这处:

manager.assignTask((worker, taskName) -> {
    worker.workOn(taskName);
});

managerassignTask()方法接收的参数类型是Task

class Manager {
  public void assignTask(Task task) {...}
}

因此,传入的Lambda表达式实际上是给了Task接口里面的assignTo()方法作为实现。因此,Lambda表达式等于帮我们定义了一个Task的匿名实例(anonymous instance of Task)。上面的这段代码:

manager.assignTask((worker, taskName) -> {
    worker.workOn(taskName);
});

就等价于:

Task task = new Task() {
    @Override
    public void assignTo(Worker worker, String taskName) {
        worker.workOn(taskName);
    }
};

manager.assignTask(task);

可以看到Lambda表达式帮我们省去了创建Task的实例的代码。

接下来我们来看Manager这部分的代码:

static class Manager {
    public void assignTask(Task task) {
        task.assignTo(System.out::println, "日本語を学ぶ");
    }
}

得到了Task的实例以后,在assignTask()方法的内部就是使用task。而Task接口的assignTo()方法定义如下:

public interface Task {
    void assignTo(Worker worker, String taskName);
}

因此,这段Lambda表达式:

task.assignTo(System.out::println, "日本語を学ぶ");

就等价于:

Worker worker = new Worker() {
    @Override
    public void workOn(String something) {
        System.out.println(something);
    }
};

task.assignTo(worker, "日本語を学ぶ");

而根据上面对task的分析,把两段Lambda表达式全部展开的话,整个代码如下所示:

public class Main {

    static class Manager {
        public void assignTask(Task task) {
            Worker worker = new Worker() {
                @Override
                public void workOn(String something) {
                    System.out.println(something);
                }
            };

            task.assignTo(worker, "日本語を学ぶ");
        }
    }

    public static void main(String args[]) throws Exception {
        Manager manager = new Manager();

        Task task = new Task() {
            @Override
            public void assignTo(Worker worker, String taskName) {
                worker.workOn(taskName);
            }
        };

        manager.assignTask(task);
    }
}

展开后的代码和使用了Lambda表达式的代码比起来,长了很多。这种多层调用的接口结构,使用了Lambda表达式以后,虽然使得代码更加整洁,但是对于新手来讲迷惑性也更强了。

然而Lambda表达式在实际的使用场景当中,这种多层的调用结构很常见,还是要多加练习加以掌握。