【外文翻译】外国友人写得很不错的Java Lambda表达式入门教程,我终于翻译好给大家啦!!!...
“
英语原文的链接在最底下的“阅读原文”
”
简介
(译者认为: 超过 3 行的逻辑就不适用 Lambda 表达式了。虽然看着很先进,其实 Lambda 表达式的本质只是一个 " 语法糖 ", 由编译器推断并帮你转换包装为常规的代码, 因此你可以使用更少的代码来实现同样的功能。本人建议不要乱用, 因为这就和某些很高级的黑客写的代码一样, 简洁, 难懂, 难以调试, 维护人员想骂娘。谢谢!)
Lambda 表达式是 Java SE 8 中一个重要的新特性。lambda 表达式允许你通过表达式来代替功能接口。lambda 表达式就和方法一样, 它提供了一个正常的参数列表和一个使用这些参数的主体 (body, 可以是一个表达式或一个代码块)。Lambda 表达式还增强了集合库。
Java SE 8 添加了 2 个对集合数据进行批量操作的包: java.util.function 包以及 java.util.stream 包。流 (stream) 就如同迭代器 (iterator), 但附加了许多额外的功能。总的来说, lambda 表达式和 stream 是自 Java 语言添加泛型(Generics) 和注解 (annotation) 以来最大的变化。在本文中, 我们将从简单到复杂的示例中见识 lambda 表达式和 stream 的强悍。
环境准备
如果还没有安装 Java 8, 那么你应该先安装才能使用 lambda 和 stream(译者建议在虚拟机中安装, 测试使用)。像 NetBeans 和 IntelliJ IDEA 一类的工具和 IDE 就支持 Java 8 特性, 包括 lambda 表达式, 可重复的注解, 紧凑的概要文件和其他特性。下面是 Java SE 8 和 NetBeans IDE 8 的下载链接:
Java Platform (JDK 8) http://www.oracle.com/technetwork/java/javase/downloads/index.html
从 Oracle 下载 Java 8, 也可以和 NetBeans IDE 一起下载 https://netbeans.org/downloads/index.html
Lambda 表达式的语法
基本语法:(parameters) -> expression或(parameters) ->{ statements; }下面是 Java lambda 表达式的简单例子:
// 1. 不需要参数,返回值为 5
() -> 5// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
基本的 Lambda 例子现在, 我们已经知道什么是 lambda 表达式, 让我们先从一些基本的例子开始。在本节中, 我们将看到 lambda 表达式如何影响我们编码的方式。假设有一个玩家 List , 程序员可以使用 for 语句 ("for 循环") 来遍历, 在 Java SE 8 中可以转换为另一种形式:
String[] atp = {"Rafael Nadal", "Novak Djokovic","Stanislas Wawrinka","David Ferrer","Roger Federer","Andy Murray","Tomas Berdych","Juan Martin Del Potro"};
List<String> players = Arrays.asList(atp);// 以前的循环方式
for (String player : players) {System.out.print(player + "; ");
}// 使用 lambda 表达式以及函数操作(functional operation)
players.forEach((player) -> System.out.print(player + "; "));// 在 Java 8 中使用双冒号操作符(double colon operator)
players.forEach(System.out::println);
正如您看到的, lambda 表达式可以将我们的代码缩减到一行。另一个例子是在图形用户界面程序中, 匿名类可以使用 lambda 表达式来代替。同样, 在实现 Runnable 接口时也可以这样使用:
// 使用匿名内部类
btn.setOnAction(new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent event) {System.out.println("Hello World!"); }});// 或者使用 lambda expression
btn.setOnAction(event -> System.out.println("Hello World!"));
下面是使用 lambdas 来实现 Runnable 接口 的示例:
// 1.1使用匿名内部类
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Hello world !");}
}).start();// 1.2使用 lambda expression
new Thread(() -> System.out.println("Hello world !")).start();// 2.1使用匿名内部类
Runnable race1 = new Runnable() {@Overridepublic void run() {System.out.println("Hello world !");}
};// 2.2使用 lambda expression
Runnable race2 = () -> System.out.println("Hello world !");// 直接调用 run 方法(没开新线程哦!)
race1.run();
race2.run();
Runnable 的 lambda 表达式, 使用块格式, 将五行代码转换成单行语句。接下来, 在下一节中我们将使用 lambdas 对集合进行排序。使用 Lambdas 排序集合在 Java 中, Comparator 类被用来排序集合。在下面的例子中, 我们将根据球员的 name, surname, name 长度 以及最后一个字母。和前面的示例一样, 先使用匿名内部类来排序, 然后再使用 lambda 表达式精简我们的代码。在第一个例子中, 我们将根据 name 来排序 list。使用旧的方式, 代码如下所示:
String[] players = {"Rafael Nadal", "Novak Djokovic", "Stanislas Wawrinka", "David Ferrer","Roger Federer", "Andy Murray","Tomas Berdych", "Juan Martin Del Potro","Richard Gasquet", "John Isner"};// 1.1 使用匿名内部类根据 name 排序 players
Arrays.sort(players, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return (s1.compareTo(s2));}
});
使用 lambdas, 可以通过下面的代码实现同样的功能:
// 1.2 使用 lambda expression 排序 players
Comparator<String> sortByName = (String s1, String s2) -> (s1.compareTo(s2));
Arrays.sort(players, sortByName);// 1.3 也可以采用如下形式:
Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));
其他的排序如下所示。和上面的示例一样, 代码分别通过匿名内部类和一些 lambda 表达式来实现 Comparator :
// 1.1 使用匿名内部类根据 surname 排序 players
Arrays.sort(players, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return (s1.substring(s1.indexOf(" ")).compareTo(s2.substring(s2.indexOf(" "))));}
});// 1.2 使用 lambda expression 排序,根据 surname
Comparator<String> sortBySurname = (String s1, String s2) -> ( s1.substring(s1.indexOf(" ")).compareTo( s2.substring(s2.indexOf(" ")) ) );
Arrays.sort(players, sortBySurname);// 1.3 或者这样,怀疑原作者是不是想错了,括号好多...
Arrays.sort(players, (String s1, String s2) -> ( s1.substring(s1.indexOf(" ")).compareTo( s2.substring(s2.indexOf(" ")) ) ) );// 2.1 使用匿名内部类根据 name lenght 排序 players
Arrays.sort(players, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return (s1.length() - s2.length());}
});// 2.2 使用 lambda expression 排序,根据 name lenght
Comparator<String> sortByNameLenght = (String s1, String s2) -> (s1.length() - s2.length());
Arrays.sort(players, sortByNameLenght);// 2.3 or this
Arrays.sort(players, (String s1, String s2) -> (s1.length() - s2.length()));// 3.1 使用匿名内部类排序 players, 根据最后一个字母
Arrays.sort(players, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));}
});// 3.2 使用 lambda expression 排序,根据最后一个字母
Comparator<String> sortByLastLetter = (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));
Arrays.sort(players, sortByLastLetter);// 3.3 or this
Arrays.sort(players, (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1)));
就是这样, 简洁又直观。在下一节中我们将探索更多 lambdas 的能力, 并将其与 stream 结合起来使用。使用 Lambdas 和 StreamsStream 是对集合的包装, 通常和 lambda 一起使用。使用 lambdas 可以支持许多操作, 如 map, filter, limit, sorted, count, min, max, sum, collect 等等。同样, Stream 使用懒运算, 他们并不会真正地读取所有数据, 遇到像 getFirst() 这样的方法就会结束链式语法。在接下来的例子中, 我们将探索 lambdas 和 streams 能做什么。我们创建了一个 Person 类并使用这个类来添加一些数据到 list 中, 将用于进一步流操作。Person 只是一个简单的 POJO 类:
public class Person {private String firstName, lastName, job, gender;
private int salary, age;public Person(String firstName, String lastName, String job,String gender, int age, int salary) {this.firstName = firstName;this.lastName = lastName;this.gender = gender;this.age = age;this.job = job;this.salary = salary;
}
// Getter and Setter
// . . . . .
}
接下来, 我们将创建两个 list, 都用来存放 Person 对象:
List<Person> javaProgrammers = new ArrayList<Person>() {{add(new Person("Elsdon", "Jaycob", "Java programmer", "male", 43, 2000));add(new Person("Tamsen", "Brittany", "Java programmer", "female", 23, 1500));add(new Person("Floyd", "Donny", "Java programmer", "male", 33, 1800));add(new Person("Sindy", "Jonie", "Java programmer", "female", 32, 1600));add(new Person("Vere", "Hervey", "Java programmer", "male", 22, 1200));add(new Person("Maude", "Jaimie", "Java programmer", "female", 27, 1900));add(new Person("Shawn", "Randall", "Java programmer", "male", 30, 2300));add(new Person("Jayden", "Corrina", "Java programmer", "female", 35, 1700));add(new Person("Palmer", "Dene", "Java programmer", "male", 33, 2000));add(new Person("Addison", "Pam", "Java programmer", "female", 34, 1300));}
};List<Person> phpProgrammers = new ArrayList<Person>() {{add(new Person("Jarrod", "Pace", "PHP programmer", "male", 34, 1550));add(new Person("Clarette", "Cicely", "PHP programmer", "female", 23, 1200));add(new Person("Victor", "Channing", "PHP programmer", "male", 32, 1600));add(new Person("Tori", "Sheryl", "PHP programmer", "female", 21, 1000));add(new Person("Osborne", "Shad", "PHP programmer", "male", 32, 1100));add(new Person("Rosalind", "Layla", "PHP programmer", "female", 25, 1300));add(new Person("Fraser", "Hewie", "PHP programmer", "male", 36, 1100));add(new Person("Quinn", "Tamara", "PHP programmer", "female", 21, 1000));add(new Person("Alvin", "Lance", "PHP programmer", "male", 38, 1600));add(new Person("Evonne", "Shari", "PHP programmer", "female", 40, 1800));}
};
现在我们使用 forEach 方法来迭代输出上述列表:
System.out.println("所有程序员的姓名:");
javaProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
phpProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
我们同样使用 forEach 方法, 增加程序员的工资 5%:
System.out.println("给程序员加薪 5% :");
Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary());javaProgrammers.forEach(giveRaise);
phpProgrammers.forEach(giveRaise);
另一个有用的方法是过滤器 filter() , 让我们显示月薪超过 1400 美元的 PHP 程序员:
System.out.println("下面是月薪超过 $1,400 的PHP程序员:")
phpProgrammers.stream().filter((p) -> (p.getSalary() > 1400)).forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
我们也可以定义过滤器, 然后重用它们来执行其他操作:
// 定义 filters
Predicate<Person> ageFilter = (p) -> (p.getAge() > 25);
Predicate<Person> salaryFilter = (p) -> (p.getSalary() > 1400);
Predicate<Person> genderFilter = (p) -> ("female".equals(p.getGender()));System.out.println("下面是年龄大于 24岁且月薪在$1,400以上的女PHP程序员:");
phpProgrammers.stream().filter(ageFilter).filter(salaryFilter).filter(genderFilter).forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));// 重用filters
System.out.println("年龄大于 24岁的女性 Java programmers:");
javaProgrammers.stream().filter(ageFilter).filter(genderFilter).forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
使用 limit 方法, 可以限制结果集的个数:
System.out.println("最前面的3个 Java programmers:");
javaProgrammers.stream().limit(3).forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));System.out.println("最前面的3个女性 Java programmers:");
javaProgrammers.stream().filter(genderFilter).limit(3).forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
排序呢? 我们在 stream 中能处理吗? 答案是肯定的。在下面的例子中, 我们将根据名字和薪水排序 Java 程序员, 放到一个 list 中, 然后显示列表:
// 静态引入
import static java.util.stream.Collectors.toList;
System.out.println("根据 name 排序,并显示前5个 Java programmers:");
List<Person> sortedJavaProgrammers = javaProgrammers.stream().sorted((p, p2) -> (p.getFirstName().compareTo(p2.getFirstName()))).limit(5).collect(toList());sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));System.out.println("根据 salary 排序 Java programmers:");
sortedJavaProgrammers = javaProgrammers.stream().sorted( (p, p2) -> (p.getSalary() - p2.getSalary()) ).collect( toList() );sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));
如果我们只对最低和最高的薪水感兴趣, 比排序后选择第一个 / 最后一个 更快的是 min 和 max 方法:
System.out.println("工资最低的 Java programmer:");
Person pers = javaProgrammers.stream().min((p1, p2) -> (p1.getSalary() - p2.getSalary())).get()System.out.printf("Name: %s %s; Salary: $%,d.", pers.getFirstName(), pers.getLastName(), pers.getSalary())System.out.println("工资最高的 Java programmer:");
Person person = javaProgrammers.stream().max((p, p2) -> (p.getSalary() - p2.getSalary())).get()System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary())
上面的例子中我们已经看到 collect 方法是如何工作的。结合 map 方法, 我们可以使用 collect 方法来将我们的结果集放到一个字符串, 一个 Set 或一个 TreeSet 中:
System.out.println("将 PHP programmers 的 first name 拼接成字符串:");
String phpDevelopers = phpProgrammers.stream().map(Person::getFirstName).collect(joining(" ; ")); // 在进一步的操作中可以作为标记(token) System.out.println("将 Java programmers 的 first name 存放到 Set:");
Set<String> javaDevFirstName = javaProgrammers.stream().map(Person::getFirstName).collect(toSet());System.out.println("将 Java programmers 的 first name 存放到 TreeSet:");
TreeSet<String> javaDevLastName = javaProgrammers.stream().map(Person::getLastName).collect(toCollection(TreeSet::new));
Streams 还可以是并行的 (parallel)。示例如下:
System.out.println("计算付给 Java programmers 的所有money:");
int totalSalary = javaProgrammers.parallelStream().mapToInt(p -> p.getSalary()).sum();
我们可以使用 summaryStatistics 方法获得 stream 中元素的各种汇总数据。接下来, 我们可以访问这些方法, 比如 getMax, getMin, getSum 或 getAverage:
//计算 count, min, max, sum, and average for numbers
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();System.out.println("List中最大的数字 : " + stats.getMax());
System.out.println("List中最小的数字 : " + stats.getMin());
System.out.println("所有数字的总和 : " + stats.getSum());
System.out.println("所有数字的平均值 : " + stats.getAverage());
OK, 就这样, 希望你喜欢它!
总结
在本文中, 我们学会了使用 lambda 表达式的不同方式, 从基本的示例, 到使用 lambdas 和 streams 的复杂示例。此外, 我们还学习了如何使用 lambda 表达式与 Comparator 类来对 Java 集合进行排序。
中文翻译者:铁锚
中文翻译文章链接:
https://blog.csdn.net/renfufei/article/details/24600507
英文原文文章链接在底部的“阅读原文”,即可直接阅读全英文的原文版本
关注我!Java从此不迷路!
☟☟☟☟ 点击“阅读原文”,即可阅览原汁原味的英文版的技术文章。
☟☟☟☟
☟☟☟☟
☟☟☟☟
【外文翻译】外国友人写得很不错的Java Lambda表达式入门教程,我终于翻译好给大家啦!!!...相关推荐
- 阿里的推荐算法竞赛的宣传稿写得很不错,很生动,吸引眼球
阿里的推荐算法竞赛的宣传稿写得很不错,很生动,吸引眼球.贴在这里,以后可以借鉴 ------------------------------------------------------------ ...
- 写给运营同学和初学者的SQL入门教程
作者简介 多肉,饿了么资深python工程师.曾在17年担任饿了么即时配送众包系统的研发经理,这篇文章最早的版本就诞生于那段时间,目前负责配送相关业务系统的整体稳定性建设.个人比较喜欢c和python ...
- 一篇生物学博士的自白,写的很不错,博士生的真实写照
文章索引: 一.前言 二.读完博士能够干什么? 三.怎样的人适合读博士? 四.怎样读博士? 五.在美国读博士 六.结语--关于事业 正文: 这篇文章说明了男怕入错行. 一.前言 原先我是准备等到毕业的 ...
- 一个写得很不错的vuex详解(转)
https://segmentfault.com/a/1190000015782272?utm_source=tag-newest 转载于:https://www.cnblogs.com/hj0711 ...
- 表妹求我写个node脚本,把java错误码表转成excel并翻译成英文
java原始代码部分如下 public static final int ERR_ONLINE_DECLINED = 1025; //交易联机拒绝//public static final int E ...
- 写给Python程序员的PHP快速入门教程
因为某些原因需要临时接手一个PHP项目,所以决定花点时间学习下PHP,对有其它语言编程经验的人来说来,上手还是很顺的.如果你也刚好在学PHP,希望本文对你有帮助. 安装Laragon 如果你是Wind ...
- 会做菜就会编程?一篇写给从未编程过的人的入门教程
简介: 编程没有那么难,会做菜就会编程. 平时工作之余,很多蚂蚁技术同学也乐于分享技术心得和经验感悟,我们会不定期精选其中的优秀文章,分享给大家. 不少同学对于编程感到好奇,但一看到厚厚的教程就打退堂 ...
- Understand Lambda Expressions in 3 minutes(翻译)
本文翻译自CodeProject上的一篇简单解释Lambda表达式的文章,适合新手理解.译文后面我补充了一点对Lambda表达式的说明. 1.什么是Lambda表达式? Lambda表达式是一种匿名方 ...
- 很有用的自定义View详解教程
注册 登录 转载地址:http://www.jianshu.com/p/c84693096e41 自定义View,有这一篇就够了 字数4899 阅读2302 评论20 喜欢105 我的CS ...
最新文章
- 超越RetinaFace,腾讯优图 ASFD 已在 WIDER FACE 霸榜半年!
- MPU6050参考代码
- no such file or directory AndroidManifest.xml
- phoenix Explain Plan 翻译
- python常用的绘图库_Python3绘图库Matplotlib(01)
- python画多层网络_绘制多层n
- matlab repmat 函数的使用
- PyTorch学习—15.PyTorch中TensorBoard的使用
- 接口自动化测试框架搭建(4、公用方法之url的拼接)--python+HTMLTestRunnerCN+request+unittest+mock+db
- 上海工程技术大学c语言商店存货管理系统,商店存货管理系统.docx
- 【应用随机过程】01. 随机过程的基本概念
- linux将时钟放在桌面上的,天气预报时钟插件加入你的Ubuntu桌面中
- mongo数据库之修改器的简单使用
- 计算机应用基础2020答案形考,国开2020秋季答案《计算机应用基础(本)》形考学习过程表现...
- 球相交的表面积并/体积并
- 熬了一夜!我用Python做了一个网站,帮小姐姐生成漫画头像
- Cesium实现自定义的广告牌效果
- 你知道吗?iPhone耳机旁边的小孔是做什么用的?
- 车牌首字母对应省份代码
- NLP5:NLTK词性标注
热门文章
- matlab scatter 散点图画法
- tmux常用命令大全
- (转载)简述马尔可夫链
- 冲激响应不变法或双线性变换法中的参数T为什么是一个无关紧要的参数
- 关于type_info与typeid
- 大数据入门及各类技术介绍
- Internal error: : 8 [#1] PREEMPT SMP ARM,vmlinux反汇编命令调试查找错误的步骤
- linux运行java程序内存过大_排查java应用linux环境内存占用过高的问题
- cpp mysql_使用MYSQLCPPCONN连接MYSQL数据库与读写BLOB字段
- R语言垃圾邮件分类--朴素贝叶斯(机器学习)