为什么你需要Lambda表达式
程序员需要Lambda表达式的原因主要有三个:
1. 更紧凑的代码
2. 通过提供额外的功能对方法的功能进行修改的能力
3. 更好地支持多核处理
更紧凑的代码
Lambda表达式以一种简洁的方式去实现仅有一个方法的Java类。
例如,如果代码中有大量的匿名内部类–诸如用于UI应用中的监听器与处理器实现,以及用于并发应用中的Callable与Runnable实现–在使用了Lambda表达式之后,将使代码变得非常短,且更易于理解。
修改方法的能力
有时,方法不具备我们想要的一些功能。例如,Collection接口中的contains()方法只有当传入的对象确实存在于该集合对象中时才会返回true。但我们无法去干预该方法的功能,比如,若使用不同的大小写方案也可以认为正在查找的字符串存在于这个集合对象中,我们希望此时contains()方法也能返回true。
简单点儿说,我们所期望做的就是”将我们自己的新代码传入”已有的方法中,然后再调用这个传进去的代码。Lambda表达式提供了一种很好的途径来代表这种被传入已有方法且应该还会被回调的代码。
Lambda表达式概览
在前面提到的使用不同大小写方案查找字符串的例子中,我们想做的就是把方法toLowerCase()的表示法作为第二个参数传入到contains()方法中,为此需要做如下的工作:
1. 找到一种途径,可将代码片断当作一个值(某种对象)进行处理
2. 找到一种途径,将上述代码片断传递给一个变量
换言之,我们需要将一个程序逻辑包装到某个对象中,并且该对象可以被进行传递。为了说的更具体点儿,让我们来看两个基本的Lambda表达式的例子,它们都是可以被现有的Java代码进行替换的。
过滤
你可能想传递的代码片断可能就是过滤器了清单1所示,
清单1
1 2 3 4 5 6 7 | File dir = new File("/an/interesting/location/"); FileFilter directoryFilter = new FileFilter() { public boolean accept(File file) { return file.isDirectory(); } }; File[] directories = dir.listFiles(directoryFilter); |
在使用Lambda表达式之后,代码会得到极大的简化,
清单2
1 2 3 | File dir = new File("/an/interesting/location/"); FileFilter directoryFilter = (File f) -> f.isDirectory(); File[] directories = dir.listFiles(directoryFilter); |
赋值表达式的左边会推导出类型(FileFilter),右边则看起来像FileFilter接口中accept()方法的一个缩小版,该方法会接受一个File对象,在判定f.isDirectory()之后返回一个布尔值。
编译器知道FileFilter只有唯一的方法accept(),所以它必定是该方法的实现。我们还知,accept()方法只需要一个File类型的参数。因此,f必定是File类型的。如清单3所示,
清单3
1 2 | File dir = new File("/an/interesting/location/"); File[] directories = dir.listFiles(f -> f.isDirectory()); |
你可以看到,使用Lambda表达式会大幅降低模板代码的数量。
事件处理器
UI程序是另一个大量使用匿名内部类的领
清单4
1 2 3 4 5 6 | Button button = new Button(); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ui.showSomething(); } }); |
使用Lambda表达式就可写出如清单5所示的代码,
清单5
1 2 | ActionListener listener = event -> {ui.showSomething();}; button.addActionListener(listener); |
该监听器在必要时可被复用,但如果它仅需被使用一次,清单6中的代码则考虑了一种很好的方式。
清单6
1 | button.addActionListener(event -> {ui.showSomething();}); |
外部遍历 vs. 内部遍历
Java语言为增强的for循环构造了一个外部迭代器,并使用这个迭代器去遍历集合对象,
清单7
1 2 3 4 5 6 | List<String> myStrings = getMyStrings(); for (String myString : myStrings) { if (myString.contains(possible)){ System.out.println(myString + " contains " + possible); } } |
使用这种方法,集合类代表着全部元素的一个”整体”视图,并且该集合对象还能支持对任意元素的随机访问,程序员可能会有这种需求。另一种可选的方案就是要求集合对象要能够在内部管理迭代器(或循环),这种方案就是内部遍历,当使用Lambda表达式时会优先选择内部遍历。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |