《JAVA8开发指南》第二章采用Lambda表达式(二)

注意事项

你会经常看到在接口类上标有@FunctionalInterface的注解。它和标签@Override很相似,表示方法是可以被覆盖的。本文中,@FunctionalInterface标签用来写在文档中,表示接口是一个函数接口。编译器也将在接口注解不符合函数接口定义的时候抛错。

你也将发现一些新的函数接口,比如在包java.util.function里面的Function<T, R>和Supplier<T>,你可以通过这些来使用任意形式的lambda表达式。

方法参数

方法参数允许你重用已经存在的方法定义并将它们像lamda表达式一样传递进来。它们的实用性在你写代码的时候展现,会使代码跟单纯的使用lambda表达式比更自然更易读。比如使用lambda表达式找隐藏的文件。

 

File[] hiddenFiles = mainDirectory.listFiles(f -> f.isHid

den());

使用方法参数,你能够使用双冒号直接应用方法isHidden。

File[] hiddenFiles = mainDirectory.listFiles(File::isHidden);

最直接理解lambda表达式的方法参数的方式是叫它"指定方法"。

方法参数的类型有以下四种:

1、静态方法的方法参数

Function<String, Integer> converter = Integer::parseInt;

Integer number = converter.apply("10");

2、实例方法的方法参数。

意思是将一个对象的方法运用到lambda表达式的第一个参数位置上。

 

Function<Invoice, Integer> invoiceToId = Invoice::getId;

3、已有对象的实例化方法参数。

Consumer<Object> print = System.out::println;

需要指出的是,这种方法参数在你遇到一个私有辅助方法并想将其注入到另一个方法中时非常有用。

 

File[] hidden = mainDirectory.listFiles(this::isXML);

private boolean isXML(File f) {

return f.getName.endsWith(".xml");

}

4、构造器参数:

Supplier<List<String>> listOfString = List::new;

大汇合

在本章的开始,你看到了一段冗长的分类变量invoices的java代码。

 

Collections.sort(invoices, new Comparator<Invoice>() {

public int compare(Invoice inv1, Invoice inv2) {

return Double.compare(inv2.getAmount(), inv1.getAmount());

}

});

现在,你将看到如何通过我们目前所掌握的java8特性重构这段代码,使其变得更可读更简洁。

首先,Comparator是一个函数接口,它仅定义了一个抽象方法叫“compare”,这个类传入了两个相同类型的对象,并返回一个整数。这种情况lambda表达式能够有很好的表现,如:

 

Collections.sort(invoices,

(Invoice inv1, Invoice inv2) -> {

return Double.compare(inv2.getAmount(),

inv1.getAmount());

});

我们发现lambda表达式的体仅仅的返回一个简单的表达式,所以可以使用更加简洁的形式:

 

Collections.sort(invoices,

(Invoice inv1, Invoice inv2)

-> Double.compare(inv2.getAmount(),

inv1.getAmount()));

java8中List接口支持sort方法,所以可以使用List代替Collections.sort,如下:

invoices.sort((Invoice inv1, Invoice inv2)

-> Double.compare(inv2.getAmount(),

inv1.getAmount()));

接下来,java8引入了一个静态辅助方法Comparator.comparing,它使用一个lambda参数抽取出比较的key值。该地方最后生成了一个Compare对象。你可以采用如下方法使用它。

 

Comparator<Invoice> byAmount

= Comparator.comparing((Invoice inv) -> inv.getAmount());

invoices.sort(byAmount);

你可能注意到了,更简洁的办法是采用Invoice::getAmount代替(Invoice inv)

-> inv.getAmount()。如下:

 

Comparator<Invoice> byAmount

= Comparator.comparing(Invoice::getAmount);

invoices.sort(byAmount);

由于getAmount方法返回的是一个double类型的值,所以使用Comparator.comparingDouble指定类型能够避免一些不必要的问题:

 

 Comparator<Invoice> byAmount
= Comparator.comparingDouble(Invoice::getAmount);
invoices.sort(byAmount);

最后,让我们整理下代码,使用import static引入方法,去掉持有Comparator对象的变量,给出本章开头引入的问题的解决方案。


 import static java.util.Comparator.comparingDouble;
invoices.sort(comparingDouble(Invoice::getAmount));

使用Lambda表达式测试

你可能关心lambda表达式如何影响测试。毕竟,lambda表达式引入的行为需要被测试验证。当你决定测试包含lambda表达式的时候,可以考虑以下两个方面。

如果lambda表达式很小,那么可以去测试使用了lambda表达式的周围代码行为。

如果lambda表达式非常复杂,则抽取它们到一个单独的方法参数中,这样你就可以将其注入并独立测试它们了。

总结

本章的重点概念如下:

lambda表达式可以被理解为一种匿名函数。

Lambda表达式和行为参数模型会代码更灵活更简洁。

函数接口是一个仅声明了一个抽象方法的接口。

Lambda表达式只能用在函数接口上下文中。

在你需要重用一个已有方法时,方法参数比单纯的lambda表达式更加自然,只需要将该方法传入参数位置即可。

测试时,将复杂的lambda表达式拆开,方便你将它们注入到方法参数中。

转载自 并发编程网 - ifeve.com

时间: 2025-01-20 22:07:33

《JAVA8开发指南》第二章采用Lambda表达式(二)的相关文章

Google Web App开发指南第二章:交互设计

首先掌握基础 借用篮球界一个传奇人物的话,在你做任何事之前,你必须"首先掌握基础".(说出这句话的是波士顿凯尔特篮球名宿Larry Bird,他同时也是一个Web App爱好者.)所有伟大的Web Apps都必须有一个清晰的集中点. 创建清晰的需求描述 伟大的web apps让用户很容易集中注意力.人们在某段时间内只能集中于少数几件事,因此,与那些提供给用户很多选择和很多特性的web apps相比,人们更喜欢那些没有干扰能让用户轻松完成手头任务的应用. 为了确保你的应用有一个集中点,创

Knockout应用开发指南 第二章:监控属性(Observables)

原文:Knockout应用开发指南 第二章:监控属性(Observables) 关于Knockout的3个重要概念(Observables,DependentObservables,ObservableArray),本人无法准确表达它的准确含义,所以暂定翻译为(监控属性.依赖监控属性和监控数组),如果有好的建议请指正,多谢. 1     创建带有监控属性的view model Observables Knockout是在下面三个核心功能是建立起来的: 监控属性(Observables)和依赖跟踪

Knockout应用开发指南 第一章:入门

原文:Knockout应用开发指南 第一章:入门 1    Knockout简介 (Introduction) Knockout是一个轻量级的UI类库,通过应用MVVM模式使JavaScript前端UI简单化. Knockout有如下4大重要概念: 声明式绑定 (Declarative Bindings):使用简明易读的语法很容易地将模型(model)数据关联到DOM元素上. UI界面自动刷新 (Automatic UI Refresh):当您的模型状态(model state)改变时,您的UI

Android艺术开发探索——第二章:IPC机制(下)

Android艺术开发探索--第二章:IPC机制(下) 我们继续来讲IPC机制,在本篇中你将会学习到 ContentProvider Socket Binder连接池 一.使用ContentProvider ContentProvider是Android中提供的专门用来不同应用之间数据共享的方式,从这一点来看,他天生就是适合进程间通信,和Messenger一样,ContentProvider的底层实现同样也是Binder,由此可见,Binder在Android系统中是何等的重要,虽然Conten

Knockout应用开发指南 第九章:高级应用举例

原文:Knockout应用开发指南 第九章:高级应用举例 1   Contacts editor 这个例子和微软为演示jQuery Data Linking Proposal例子提供的例子一样的提供的,我们可以看看Knockout实现是难了还是容易了. 代码量的多少不重要(尽快Knockout 的实现很简洁),重要的看起来是否容易理解且可读.查看HTML源代码,看看如何实现的view model以及绑定的.     代码: View View Code <h2>Contacts</h2&

[C# 3.0 入门] [第一章 Lambda表达式] 第二节:Lambda表达式带来了什么

本次的内容,主要是针对已经学习过C# 2.0的程序员读者的,前提是已经知道什么是匿名方法.如果还不清楚,请先阅读"连载:C# 2.0入门"(这篇会在今后翻译). 好的,现在进入正题. Lambda表达式(λ表达式),用一句话来解释,(不算很严谨)就是使匿名方法文字上更短的语法.虽然这样说,单"仅仅是文字上的变化,源代码的性质没有变"这样的想法也是一种误解.规模变化了,其性质也会变化.例如,实验室的烧杯中产生的现象,不一定会在大型的工厂里产生.同样的道理也适用于源代码

《JAVA8开发指南》为什么你需要关注 JAVA8

本章包含 代码的可读性 多核 JAVA8特性的快速指南 JAVA8:为什么你需要关注? JAVA已经更新了!在 2014 年 3 月,JAVA发布了新版本-JAVA8,JAVA8 引入的一些新特性可能会改变你日常中基本的编码方式.但不用担心,这本简洁的指南会带着你掌握一些要领,现在你就可以开始阅读. 第一章列举了 JAVA8 中增加的主要功能概况.接下来的两章则关注 JAVA8 的主要特性: lambda 表达式 和streams(流). 驱动 JAVA8 改进的两大动机: 代码可读性 更加简化

Java8初体验(一)lambda表达式语法

感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解偏差的地方,希望大家帮忙指出,我会持续修改和优化.本文是该系列的第一篇,主要介绍Java8对屌丝码农最有吸引力的一个特性-lambda表达式. java8的安装 工欲善其器必先利其器,首先安装JDK8.过程省略,大家应该都可以自己搞定.但是有一点这里强调一下(Windows系统):目前我们工作的版本

《JAVA8开发指南》使用流式操作

本章中,你将学习到怎样使用Stream API进行开发.首先,你将会了解Stream API背后的机制,什么是流以及流的用处.其次,你将学习到一系列的流式操作.流式数据处理模型以及能让你写出更复杂数据查询的流式集合操作.接下来是如何应用流式操作的例子.最后,你将学习到并行流. 为什么需要流式操作 集合API是Java API中最重要的部分.基本上每一个java程序都离不开集合.尽管很重要,但是现有的集合处理在很多方面都无法满足需要. 一个原因是,许多其他的语言或者类库以声明的方式来处理特定的数据