Java 8的Lambda表达式详解
本篇内容介绍了"Java 8的Lambda表达式详解"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
功能接口
只包含一个方法的接口被称为功能接口,Lambda 表达式用用于任何功能接口适用的地方。
java.awt.event.ActionListener 就是一个功能接口,因为它只有一个方法:void actionPerformed(ActionEvent). 在 Java 7 中我们会编写如下代码:
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ui.dazzle(e.getModifiers()); } });
而 Java 8 中可以简化为:
button.addActionListener(e -> { ui.dazzle(e.getModifiers()); });
编译器知道Lambda 表达式必须符合 void actionPerformed(ActionEvent) 方法的定义。看起来 Lambda 实体返回 void,实际上它可以推断出参数 e 的类型是 java.awt.event.ActionEvent.
函数集合
Java 8 的类库包含一个新的包 java.util.functions ,这个包中有很多新的功能接口,这些接口可与集合 API 一起使用。
java.util.functions.Predicate
使用谓词 (Predicate) 来筛选集合:
Listnames = Arrays.asList("Alice", "Bob", "Charlie", "Dave"); List filteredNames = names .filter(e -> e.length() >= 4) .into(new ArrayList ()); for (String name : filteredNames) { System.out.println(name); }
这里我们有两个新方法:
Iterable
filter(Predicate super T>) 用于获取元素满足某个谓词返回 true 的结果
java.util.functions.Block
我们可使用一个新的迭代器方法来替换 for 循环 void forEach(Block super T>):
Listnames = Arrays.asList("Alice", "Bob", "Charlie", "Dave"); names .filter(e -> e.length() >= 4) .forEach(e -> { System.out.println(e); });
forEach() 方法是 internal iteration 的一个实例:迭代过程在 Iterable 和 Block 内部进行,每次可访问一个元素。
***的结果就是用更少的代码来处理集合:
Listnames = Arrays.asList("Alice", "Bob", "Charlie", "Dave"); names .mapped(e -> { return e.length(); }) .asIterable() // returns an Iterable of BiValue elements // an element's key is the person's name, its value is the string length .filter(e -> e.getValue() >= 4) .sorted((a, b) -> a.getValue() - b.getValue()) .forEach(e -> { System.out.println(e.getKey() + '\t' + e.getValue()); });
这样做的优点是:
元素在需要的时候才进行计算
如果我们取一个上千个元素的集合的前三条时,其他元素就不会被映射
鼓励使用方法链
我们无需才存储中间结果来构建新的集合
内部迭代过程因此大多数细节
例如,我们可以通过下面代码来并行 map() 操作
writing myCollection.parallel().map(e ‑> e.length()).
方法引用
我们可通过 :: 语法来引用某个方法。方法引用被认为是跟 Lambda 表达式一样的,可用于功能接口所适用的地方。
我们可以引用一个静态方法:
executorService.submit(MethodReference::sayHello); private static void sayHello() { System.out.println("hello"); }
或者是一个实例的方法:
Arrays.asList("Alice", "Bob", "Charlie", "Dave").forEach(System.out::println);
我们也可以创建工程方法并将构造器引用赋值给 java.util.functions.Factory:
FactorybiscuitFactory = Biscuit::new; Biscuit biscuit = biscuitFactory.make();
***,我们创建一个引用到随意实例的例子:
interface Accessor{ PROPERTY access(BEAN bean); } public static void main(String[] args) { Address address = new Address("29 Acacia Road", "Tunbridge Wells"); Accessor accessor = Address::getCity; System.out.println(accessor.access(address)); }
这里我们无需绑定方法引用到某个实例,我们直接将实例做为功能接口的参数进行传递。
默认方法
直到今天的 Java ,都不可能为一个接口添加方法而不会影响到已有的实现类。而 Java 8 允许你为接口自身指定一个默认的实现:
interface Queue { Message read(); void delete(Message message); void deleteAll() default { Message message; while ((message = read()) != null) { delete(message); } } }
子接口可以覆盖默认的方法:
interface BatchQueue extends Queue { void setBatchSize(int batchSize); void deleteAll() default { setBatchSize(100); Queue.super.deleteAll(); } }
或者子接口也可以通过重新声明一个没有方法体的方法来删除默认的方法:
interface FastQueue extends Queue { void deleteAll(); }
这个将强制所有实现了 FastQueue 的类必须实现 deleteAll() 方法。
HotSpot 实现
Lambda 不只是可以减少很多代码的编写,其字节码和运行时的实现也比 Java 7 中的匿名类的效率更高。针对每一个 Lambda 表达式,编译器都会创建一个对应的形如 Lambda$1() 这样的方法。这个过程被称之为 Lambda body desugaring. 当遇见一个 Lambda 表达式,编译器将会发起一个 invokedynamic 调用,并从目标功能接口中获取返回值。
"Java 8的Lambda表达式详解"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!