首页 文章资讯内容详情

Java中Lambda表达式的使用

2026-06-01 3 花语

本文内容纲要:

简介 (译者注:虽然看着很先进,其实Lambda表达式的本质只是一个"语法糖

",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。本人建议不要乱用,因为这就和某些很高级的黑客写的代码一样,简洁,难懂,难以调试,维护人员想骂娘.)

Lambda表达式是JavaSE8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。

Lambda表达式还增强了集合库。JavaSE8添加了2个对集合数据进行批量操作的包:java.util.function包以及java.util.stream包。流(stream)就如同迭代器(iterator),但附加了许多额外的功能。总的来说,lambda表达式和stream是自Java语言添加泛型(Generics)和注解(annotation)以来最大的变化。在本文中,我们将从简单到复杂的示例中见认识lambda表达式和stream的强悍。

环境准备 如果还没有安装Java8,那么你应该先安装才能使用lambda和stream(译者建议在虚拟机

中安装,测试使用)。像NetBeans和IntelliJIDEA一类的工具和IDE就支持Java8特性,包括lambda表达式,可重复的注解,紧凑的概要文件和其他特性。

下面是JavaSE8和NetBeansIDE8的下载链接:

JavaPlatform(JDK8)

:从Oracle下载Java8,也可以和NetBeansIDE一起下载

NetBeansIDE8

:从NetBeans官网下载NetBeansIDE

Lambda表达式的语法

基本语法:

(parameters)->expression

(parameters)->{statements;}

下面是Javalambda表达式的简单例子:

//1.不需要参数,返回值为5 ()->5 //2.接收一个参数(数字类型),返回其2倍的值 x->2*x //3.接受2个参数(数字),并返回他们的差值 (x,y)->x–y //4.接收2个int型整数,返回他们的和 (intx,inty)->x+y //5.接受一个string对象,并在控制台打印,不返回任何值(看起来像是返回void) (Strings)->System.out.print(s)

基本的Lambda例子 现在,我们已经知道什么是lambda表达式,让我们先从一些基本的例子开始。在本节中,我们将看到lambda表达式如何影响我们编码的方式。假设有一个玩家List,程序员可以使用for语句("for循环")来遍历,在JavaSE8中可以转换为另一种形式:

String[]atp={"RafaelNadal","NovakDjokovic", "StanislasWawrinka", "DavidFerrer","RogerFederer", "AndyMurray","TomasBerdych", "JuanMartinDelPotro"}; List<String>players=Arrays.asList(atp); //以前的循环方式 for(Stringplayer:players){ System.out.print(player+";"); } //使用lambda表达式以及函数操作(functionaloperation) players.forEach((player)->System.out.print(player+";")); //在Java8中使用双冒号操作符(doublecolonoperator) players.forEach(System.out::println);

正如您看到的,lambda表达式可以将我们的代码缩减到一行。另一个例子是在图形用户界面程序中,匿名类可以使用lambda表达式来代替。同样,在实现Runnable接口时也可以这样使用:

//使用匿名内部类 btn.setOnAction(newEventHandler<ActionEvent>(){ @Override publicvoidhandle(ActionEventevent){ System.out.println("HelloWorld!"); } }); //或者使用lambdaexpression btn.setOnAction(event->System.out.println("HelloWorld!"));

下面是使用lambdas来实现Runnable接口的示例:

//1.1使用匿名内部类 newThread(newRunnable(){ @Override publicvoidrun(){ System.out.println("Helloworld!"); } }).start(); //1.2使用lambdaexpression newThread(()->System.out.println("Helloworld!")).start(); //2.1使用匿名内部类 Runnablerace1=newRunnable(){ @Override publicvoidrun(){ System.out.println("Helloworld!"); } }; //2.2使用lambdaexpression Runnablerace2=()->System.out.println("Helloworld!"); //直接调用run方法(没开新线程哦!) race1.run(); race2.run();

Runnable的lambda表达式,使用块格式,将五行代码转换成单行语句。接下来,在下一节中我们将使用lambdas对集合进行排序。

使用Lambdas排序集合

在Java中,Comparator类被用来排序集合。在下面的例子中,我们将根据球员的name,surname,name长度以及最后一个字母。和前面的示例一样,先使用匿名内部类来排序,然后再使用lambda表达式精简我们的代码。

在第一个例子中,我们将根据name来排序list。使用旧的方式,代码如下所示: String[]players={"RafaelNadal","NovakDjokovic", "StanislasWawrinka","DavidFerrer", "RogerFederer","AndyMurray", "TomasBerdych","JuanMartinDelPotro", "RichardGasquet","JohnIsner"}; //1.1使用匿名内部类根据name排序players Arrays.sort(players,newComparator<String>(){ @Override publicintcompare(Strings1,Strings2){ return(s1.compareTo(s2)); } });

使用lambdas,可以通过下面的代码实现同样的功能:

//1.2使用lambdaexpression排序players Comparator<String>sortByName=(Strings1,Strings2)->(s1.compareTo(s2)); Arrays.sort(players,sortByName); //1.3也可以采用如下形式: Arrays.sort(players,(Strings1,Strings2)->(s1.compareTo(s2)));

其他的排序如下所示。和上面的示例一样,代码分别通过匿名内部类和一些lambda表达式来实现Comparator:

//1.1使用匿名内部类根据surname排序players Arrays.sort(players,newComparator<String>(){ @Override publicintcompare(Strings1,Strings2){ return(s1.substring(s1.indexOf("")).compareTo(s2.substring(s2.indexOf("")))); } }); //1.2使用lambdaexpression排序,根据surname Comparator<String>sortBySurname=(Strings1,Strings2)-> (s1.substring(s1.indexOf("")).compareTo(s2.substring(s2.indexOf("")))); Arrays.sort(players,sortBySurname); //1.3或者这样,怀疑原作者是不是想错了,括号好多... Arrays.sort(players,(Strings1,Strings2)-> (s1.substring(s1.indexOf("")).compareTo(s2.substring(s2.indexOf("")))) ); //2.1使用匿名内部类根据namelenght排序players Arrays.sort(players,newComparator<String>(){ @Override publicintcompare(Strings1,Strings2){ return(s1.length()-s2.length()); } }); //2.2使用lambdaexpression排序,根据namelenght Comparator<String>sortByNameLenght=(Strings1,Strings2)->(s1.length()-s2.length()); Arrays.sort(players,sortByNameLenght); //2.3orthis Arrays.sort(players,(Strings1,Strings2)->(s1.length()-s2.length())); //3.1使用匿名内部类排序players,根据最后一个字母 Arrays.sort(players,newComparator<String>(){ @Override publicintcompare(Strings1,Strings2){ return(s1.charAt(s1.length()-1)-s2.charAt(s2.length()-1)); } }); //3.2使用lambdaexpression排序,根据最后一个字母 Comparator<String>sortByLastLetter= (Strings1,Strings2)-> (s1.charAt(s1.length()-1)-s2.charAt(s2.length()-1)); Arrays.sort(players,sortByLastLetter); //3.3orthis Arrays.sort(players,(Strings1,Strings2)->(s1.charAt(s1.length()-1)-s2.charAt(s2.length()-1)));

就是这样,简洁又直观。在下一节中我们将探索更多lambdas的能力,并将其与stream结合起来使用。

使用Lambdas和Streams Stream是对集合的包装,通常和lambda一起使用。使用lambdas可以支持许多操作,如map,filter,limit,sorted,count,min,max,sum,collect等等。同样,Stream使用懒运算,他们并不会真正地读取所有数据,遇到像getFirst()这样的方法就会结束链式语法。在接下来的例子中,我们将探索lambdas和streams能做什么。我们创建了一个Person类并使用这个类来添加一些数据到list中,将用于进一步流操作。Person只是一个简单的POJO类: publicclassPerson{ privateStringfirstName,lastName,job,gender; privateintsalary,age; publicPerson(StringfirstName,StringlastName,Stringjob, Stringgender,intage,intsalary){ this.firstName=firstName; this.lastName=lastName; this.gender=gender; this.age=age; this.job=job; this.salary=salary; } //GetterandSetter //..... }

接下来,我们将创建两个list,都用来存放Person对象:

List<Person>javaProgrammers=newArrayList<Person>(){ { add(newPerson("Elsdon","Jaycob","Javaprogrammer","male",43,2000)); add(newPerson("Tamsen","Brittany","Javaprogrammer","female",23,1500)); add(newPerson("Floyd","Donny","Javaprogrammer","male",33,1800)); add(newPerson("Sindy","Jonie","Javaprogrammer","female",32,1600)); add(newPerson("Vere","Hervey","Javaprogrammer","male",22,1200)); add(newPerson("Maude","Jaimie","Javaprogrammer","female",27,1900)); add(newPerson("Shawn","Randall","Javaprogrammer","male",30,2300)); add(newPerson("Jayden","Corrina","Javaprogrammer","female",35,1700)); add(newPerson("Palmer","Dene","Javaprogrammer","male",33,2000)); add(newPerson("Addison","Pam","Javaprogrammer","female",34,1300)); } }; List<Person>phpProgrammers=newArrayList<Person>(){ { add(newPerson("Jarrod","Pace","PHPprogrammer","male",34,1550)); add(newPerson("Clarette","Cicely","PHPprogrammer","female",23,1200)); add(newPerson("Victor","Channing","PHPprogrammer","male",32,1600)); add(newPerson("Tori","Sheryl","PHPprogrammer","female",21,1000)); add(newPerson("Osborne","Shad","PHPprogrammer","male",32,1100)); add(newPerson("Rosalind","Layla","PHPprogrammer","female",25,1300)); add(newPerson("Fraser","Hewie","PHPprogrammer","male",36,1100)); add(newPerson("Quinn","Tamara","PHPprogrammer","female",21,1000)); add(newPerson("Alvin","Lance","PHPprogrammer","male",38,1600)); add(newPerson("Evonne","Shari","PHPprogrammer","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岁的女性Javaprogrammers:"); javaProgrammers.stream() .filter(ageFilter) .filter(genderFilter) .forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName()));

使用limit方法,可以限制结果集的个数:

System.out.println("最前面的3个Javaprogrammers:"); javaProgrammers.stream() .limit(3) .forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName())); System.out.println("最前面的3个女性Javaprogrammers:"); javaProgrammers.stream() .filter(genderFilter) .limit(3) .forEach((p)->System.out.printf("%s%s;",p.getFirstName(),p.getLastName()));

排序呢?我们在stream中能处理吗?答案是肯定的。在下面的例子中,我们将根据名字和薪水排序Java程序员,放到一个list中,然后显示列表:

System.out.println("根据name排序,并显示前5个Javaprogrammers:"); 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排序Javaprogrammers:"); 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("工资最低的Javaprogrammer:"); Personpers=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("工资最高的Javaprogrammer:"); Personperson=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("将PHPprogrammers的firstname拼接成字符串:"); StringphpDevelopers=phpProgrammers .stream() .map(Person::getFirstName) .collect(joining(";"));//在进一步的操作中可以作为标记(token) System.out.println("将Javaprogrammers的firstname存放到Set:"); Set<String>javaDevFirstName=javaProgrammers .stream() .map(Person::getFirstName) .collect(toSet()); System.out.println("将Javaprogrammers的firstname存放到TreeSet:"); TreeSet<String>javaDevLastName=javaProgrammers .stream() .map(Person::getLastName) .collect(toCollection(TreeSet::new));

Streams还可以是并行的(parallel)。示例如下:

System.out.println("计算付给Javaprogrammers的所有money:"); inttotalSalary=javaProgrammers .parallelStream() .mapToInt(p->p.getSalary()) .sum();

我们可以使用summaryStatistics方法获得stream中元素的各种汇总数据。接下来,我们可以访问这些方法,比如getMax,getMin,getSum或getAverage:

//计算count,min,max,sum,andaveragefornumbers List<Integer>numbers=Arrays.asList(1,2,3,4,5,6,7,8,9,10); IntSummaryStatisticsstats=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://www.cnblogs.com/franson-2016/p/5593080.html