最通俗易懂的讲解:lambda表达式

Java8发布已经有一段时间了,这次发布的改动比较大,很多人将这次改动与Java5的升级相提并论。Java8其中一个很重要的新特性就是lambda表达式,允许我们将行为传到函数中。想想看,在Java8 之前我们想要将行为传入函数,仅有的选择就是匿名内部类。

Java8发布以后,lambda表达式将大量替代匿名内部类的使用,简化代码的同时,更突出了原来匿名内部类中最重要的那部分包含真正逻辑的代码。尤其是对于做数据的同学来说,当习惯使用类似scala之类的函数式编程语言以后,体会将更加深刻。现在我们就来看看Java8中lambda表达式的一些常见写法。

lambda体中调用方法的参数列表和返回值类型,要和函数式接口中抽象方法的参数列表和返回值类型保持一致。

一、替代匿名内部类

lambda表达式用的最多的场合就是替代匿名内部类,实现Runnable接口是匿名内部类的经典例子。lambda表达式的功能相当强大,用()->就可以代替整个匿名内部类!

packageOSChina.Lambda;

importorg.junit.Test;

importjava.util.Comparator;

importjava.util.function.Consumer;

importjava.util.function.Function;

importjava.util.function.Predicate;

importjava.util.function.Supplier;

publicclassTest1{

publicstaticvoidmain(String[] args){

Runnable runnable =newRunnable() {

@Override

publicvoidrun(){

System.out.println("普通,线程启动");

}

};

runnable.run();

test2();

test3();

test4();

test5();

}

//无参数,无返回值

publicstaticvoidtest2(){

//“->”左边只有一个小括号,表示无参数,右边是Lambda体(就相当于实现了匿名内部类里面的方法了,(即就是一个可用的接口实现类了。))

Runnable runnable = ()->System.out.println("Lambda 表达式方式,线程启动");

runnable.run();

}

//有一个参数,并且无返回值

publicstaticvoidtest3(){

//这个e就代表所实现的接口的方法的参数,

Consumer consumer = e->System.out.println("Lambda 表达式方式,"+e);

consumer.accept("传入参数");

}

//有两个以上的参数,有返回值,并且 Lambda 体中有多条语句

publicstaticvoidtest4(){

//Lambda 体中有多条语句,记得要用大括号括起来

Comparator com = (x, y) -> {

System.out.println("函数式接口");

returnInteger.compare(x, y);

};

intcompare = com.compare(100,244);

System.out.println("有两个以上的参数,有返回值,"+compare);

}

//若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写

publicstaticvoidtest5(){

//Comparator com = (x, y) -> Integer.compare(100, 244);

System.out.println("若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写,"+Integer.compare(100,244));

}

}

二、Java8四大内置函数式接口

如果使用lambda还要自己写一个接口的话太麻烦,所以Java自己提供了一些接口:

1、Consumer 消费性接口:void accept(T t);

//有一个参数,并且无返回值

publicstaticvoidtest3(){

//这个e就代表所实现的接口的方法的参数,

Consumer consumer = e->System.out.println("Lambda 表达式方式,"+e);

consumer.accept("传入参数");

}

2、Supplier供给型接口:T get();

package OSChina.Lambda;

importjava.util.ArrayList;

importjava.util.function.Supplier;

publicclassTest2{

publicstaticvoidmain(String[] args){

ArrayList res = getNumList(10,()->(int)(Math.random()*100));

System.out.println(res);

}

publicstaticArrayList getNumList(intnum, Supplier sup){

ArrayListlist=newArrayList<>();

for(inti =0; i < num; i++) {

Integer e = sup.get();

list.add(e);

}

returnlist;

}

}

3、Function 函数式接口:R apply(T t);

packageOSChina.Lambda;

importjava.util.function.Function;

publicclassTest2{

publicstatic void main(String[] args) {

String newStr = strHandler("abc",(str)->str.toUpperCase());

System.out.println(newStr);

newStr = strHandler("  abc  ",(str)->str.trim());

System.out.println(newStr);

}

publicstatic String strHandler(String str, Functionfun){

returnfun.apply(str);

}

}

4、Predicate 断言式接口:boolean test(T t);

判断一些字符串数组判断长度>2的字符串:

package OSChina.Lambda;

importjava.util.ArrayList;

importjava.util.Arrays;

importjava.util.List;

importjava.util.function.Predicate;

publicclassTest2{

publicstaticvoidmain(String[] args) {

List list = Arrays.asList("hello","jiangshuying","lambda","www","ok","q");

List ret = filterStr(list,(str)->str.length()>2);

System.out.println(ret);

}

publicstaticList filterStr(List list, Predicate pre){

ArrayList arrayList =newArrayList<>();

for(Stringstr:list){

if(pre.test(str)) {

arrayList.add(str);

}

}

returnarrayList;

}

}

三、方法引用与构造器引用

要求:实现抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!

方法引用:使用操作符“::”将类与方法分隔开来。

对象::实例方法名

类::静态方法名

类::实例方法名

举个例子:

publicstaticvoidtest9(){

Comparator comparator = (x,y)->Integer.compare(x,y);

Comparator comparator1 = Integer::compare;

intcompare = comparator.compare(1,2);

intcompare1 = comparator1.compare(1,2);

System.out.println("compare:"+compare);

System.out.println("compare1:"+compare1);

}

四、lambda表达式的一些常见用法

1、使用lambda表达式对集合进行迭代

package OSChina.Lambda;

importjava.util.Arrays;

importjava.util.List;

publicclassTest3{

publicstaticvoidmain(String[] args){

Listlist= Arrays.asList("java","c#","javascript");

//before java8

for(String str:list){

System.out.println("before java8,"+str);

}

//after java8

list.forEach(x-> System.out.println("after java8,"+x));

}

}

2、用lambda表达式实现map

map函数可以说是函数式编程里最重要的一个方法了。map的作用是将一个对象变换为另外一个。在我们的例子中,就是通过map方法将cost增加了0,05倍的大小然后输出。

package OSChina.Lambda;

importjava.util.Arrays;

importjava.util.List;

publicclassTest3{

publicstaticvoidmain(String[] args){

Listlist= Arrays.asList(10.0,20.0,30.0);

list.stream().map(x->x+x*0.05).forEach(x-> System.out.println(x));

}

}

3、用lambda表达式实现map与reduce

既然提到了map,又怎能不提到reduce。reduce与map一样,也是函数式编程里最重要的几个方法之一,map的作用是将一个对象变为另外一个,而reduce实现的则是将所有值合并为一个,请看:

package OSChina.Lambda;

importjava.util.Arrays;

importjava.util.List;

publicclassTest3{

publicstaticvoidmain(String[] args){

//before java8

List cost = Arrays.asList(10.0,20.0,30.0);

doublesum =0;

for(doubleeach:cost) {

each += each *0.05;

sum += each;

}

System.out.println("before java8,"+sum);

//after java8

Listlist= Arrays.asList(10.0,20.0,30.0);

doublesum2 =list.stream().map(x->x+x*0.05).reduce((sum1,x)->sum1+x).get();

System.out.println("after java8,"+sum2);

}

}

相信用map+reduce+lambda表达式的写法高出不止一个level。

4、filter操作

filter也是我们经常使用的一个操作。在操作集合的时候,经常需要从原始的集合中过滤掉一部分元素。

packageOSChina.Lambda;

importjava.util.Arrays;

importjava.util.List;

importjava.util.stream.Collectors;

publicclassTest3{

publicstaticvoidmain(String[] args){

List cost = Arrays.asList(10.0,20.0,30.0,40.0);

List filteredCost = cost.stream().filter(x -> x >25.0).collect(Collectors.toList());

filteredCost.forEach(x -> System.out.println(x));

}

}

5、与函数式接口Predicate配合

除了在语言层面支持函数式编程风格,Java 8也添加了一个包,叫做java.util.function。它包含了很多类,用来支持Java的函数式编程。

其中一个便是Predicate,使用java.util.function.Predicate函数式接口以及lambda表达式,可以向API方法添加逻辑,用更少的代码支持更多的动态行为。Predicate接口非常适用于做过滤。

package OSChina.Lambda;

import java.lang.reflect.Array;

import java.util.Arrays;

import java.util.List;

import java.util.function.Predicate;

publicclassTest4{

publicstaticvoid filterTest(List languages, Predicate condition) {

languages.stream().filter(x -> condition.test(x)).forEach(x -> System.out.println(x +" "));

}

publicstaticvoid main(String[] args) {

List languages = Arrays.asList("Java","Python","scala","Shell","R");

filterTest(languages,x->x.startsWith("J"));//Java 

filterTest(languages,x -> x.endsWith("a"));//Java,scala 

filterTest(languages,x -> true);//Java,Python,scala,Shell,R

filterTest(languages,x -> false);//

filterTest(languages,x -> x.length() >4);//Python,scala,Shell,

}

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言:Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级。在Java Code Geek...
    糖宝_阅读 1,328评论 1 1
  • 原链接:http://www.cnblogs.com/langtianya/p/3757993.html JDK各...
    把爱放下会走更远阅读 1,137评论 0 10
  • 参考ImportNew - lemeilleur 翻译自javarevisited 用例1、用lambda表达式实...
    mulinsentt阅读 576评论 0 1
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,736评论 0 3
  • 二婆(母亲的二婶)家后院有一棵香杏树,这是一棵异于普通的杏树,它的果仁不是苦苦的那种,嚼起来清香四溢,越吃越想吃。...
    宝天曼风景阅读 766评论 0 0