如何使用lambda表达式提升开发效率?
OSC开源社区
2023-09-20 20:48:50

原标题:如何使用lambda表达式提升开发效率?

Java8 的一个大亮点是引入 Lambda 表达式,使用它设计的代码会更加简洁。当开发者在编写 Lambda 表达式时,也会随之被编译成一个函数式接口。

OSCHINA 本期高手问答 (8 月 23 日 - 8 月 29 日) 我们请来了嘉宾 阿超老师 来和大家一起探讨关于 Lambda 和 Stream 的问题,将以【如何使用 lambda 表达式提升开发效率】为切入点展开讨论。

可讨论的问题包括但不限于:

  • lambda 表达式的应用场景
  • Stream 的应用场景
  • Lambda/Stream 的进一步封装

除了上述三个范围,你也可以将讨论的内容外延到函数式编程的整个领域(不限于编程语言),包括各大开源项目中对其的封装、应用等等,还可以专注于开源的 orm 框架 Mybatis-Plus 的源码、实践等细节。

嘉宾介绍

阿超,00 后全栈开发,dromara 组织成员、hutool 团队成员、mybatis-plus 团队成员、stream-query 项目作者,参与贡献的开源项目包括不限于 apache-shenyu、apache-streampark 等。

个人主页:https://gitee.com/VampireAchao/

为了鼓励踊跃提问,问答结束后我们会从提问者中抽取 5 名幸运会员,赠予 开源项目 stream-query 的开源周边 T 恤,由阿超亲自设计!

Lambda 表达式

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

简单来说:就是把我们的函数 (方法) 作为参数传递、调用等

例子:自定义函数式接口(用 jdk自带的函数式接口也可以)

importjava.io.Serializable;

/**

* 可序列化的Functional

*

* @authorVampireAchao

*/

@FunctionalInterface

publicinterfaceFunc<T, R> extendsSerializable{

/**

* 调用

*

* @paramt 参数

* @return返回值

*/

R apply(T t);

}

我们定义一个类可以去实现该接口

/**

* 可序列化的函数式接口实现类

*

* @authorVampireAchao

*/

publicclassFuncImplimplementsFunc<Object, String> {

/**

* 调用

*

* @paramo 参数

* @return返回值

*/

@Override

publicString apply(Object o){

returno.toString;

}

}

到此为止,都非常的简单

这里就有个问题:假设我有很多的地方需要不同的类去实现 Func,我就得每次都去写这么一个类,然后实现该接口并重写方法

这样很麻烦!因此我们使用匿名内部类

Func< String, Integer> func = newFunc< String, Integer> {

/**

* 调用

*

* @param s 参数

* @return 返回值

*/

@Override

publicInteger apply( Strings) {

returns.hashCode;

}

};

我们可以看到,使用了匿名内部类后不用每次去新建这个类了,只需要在调用的地方,new一下接口,创建一个匿名内部类即可

但这样还有个问题,我们每次都要写这么一大几行代码,特别麻烦

由此而生,我们有了 lambda这种简写的形式

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#syntax

Func< String, String> func1 = ( Strings) -> {

returns.toUpperCase;

};

如果只有一行,我们可以省略掉中括号以及 return

Func< String, String> func2 = ( Strings) -> s.toUpperCase;

我们可以省略掉后边的参数类型

Func< String, String> func3 = s -> s.toUpperCase;

如果我们满足特定的形式,我们还可以使用方法引用(双冒号)的形式缩写

Func< String, String> func4 = String::toUpperCase;

这里除了我们的参数->返回值写法:s->s.toUpperCase,还有很多种

例如无参数带返回值写法 ->"yes"、无参无返回值写法 ->{}等等

而方法引用这种写法有如下几种:

https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

package org.dromara.streamquery;

importjava.util .function.Function;

importjava.util .function.IntFunction;

importjava.util .function.Supplier;

/**

* 语法糖——方法引用

*

* @author VampireAchao

*/

publicclassMethodReferences {

publicstaticObjectstaticSupplier {

return"whatever";

}

publicObjectinstanceSupplier {

return"whatever";

}

publicObjectanonymousInstanceFunction {

return"whatever";

}

publicstaticvoidmain( String[] args) {

// 引用构造函数

Supplier conSup = -> newMethodReferences;

conSup = MethodReferences:: new;

// 数组构造函数引用

IntFunction intFunction = value -> newint[value];

// intFunc == new int[20];

int[] intFuncResult = intFunction.apply( 20);

// 引用静态方法

Supplier< Object> statSup = -> staticSupplier;

statSup = MethodReferences::staticSupplier;

ObjectstatSupResult = statSup.get;

// 引用特定对象的实例方法

Supplier< Object> instSup = newMethodReferences::instanceSupplier;

instSup = newMethodReferences::instanceSupplier;

ObjectinstSupResult = instSup.get;

// 引用特定类型的任意对象的实例方法

FunctionObject> anonInstFunc = streamDemo -> streamDemo.anonymousInstanceFunction;

anonInstFunc = MethodReferences::anonymousInstanceFunction;

}

}

顺便放几个常用的,jdk自带的函数式接口写法

package org.dromara.streamquery;

importjava.math.BigDecimal;

importjava.util .function.*;

/**

* 常用的几个函数式接口写法

*

* @author VampireAchao

*/

classUsual {

publicstaticConsumer< Object> consumer {

// 有参数无返回值

returno -> {

};

}

publicstaticFunctionObject> function{

// 有参数有返回值

returno -> o;

}

publicstaticPredicate< Object> predicate {

// 有参数,返回值为boolean

returno -> true;

}

publicstaticSupplier< Object> supplier {

// 无参数有返回值

returnObject:: new;

}

publicstaticBiConsumer< String, Integer> biConsumer {

// 俩参数无返回值

return(q, o) -> {

};

}

publicstaticBiFunction biFunction {

// 俩参数,有返回值

return(q, o) -> newBigDecimal(q).add(BigDecimal.valueOf(o));

}

publicstaticUnaryOperator< Object> unaryOperator {

// 一个参数,返回值类型和参数一样

returnq -> q;

}

publicstaticBinaryOperator< Object> binaryOperator {

// 俩参数和返回值类型保持一致

return(a, o) -> a;

}

}

Stream

Java 8 API添加了一个新的抽象称为流 Stream,可以让你以一种声明的方式处理数据。方法全是传入函数作为参数,来达到我们的目的。

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

// 声明式编程是告诉计算机需要计算“什么”而不是“如何”去计算

// 现在,我想要一个List,包含3个数字6

List sixSixSix =

// 我想要:

Stream

// 数字6

.generate( -> 6)

// 3个

.limit( 3)

// 最后收集起来转为List

.collect(Collectors.toList);

sixSixSix. forEach(System.out::print);

Stream使用一种类似用 SQL语句从数据库查询数据的直观方式来提供一种对 Java集合运算和表达的高阶抽象。

// 就像sql里的排序、截取

// 我要把传入的list逆序,然后从第五个(元素下标为4)开始取值,取4条

abc = abc.stream

// 排序(按照自然顺序的逆序)

.sorted(Comparator.reverseOrder)

// 从下标为4开始取值

.skip( 4)

// 取4条

.limit( 4)

// 最后收集起来转为List

.collect(Collectors.toList);

System. out.println( "我要把传入的list逆序,然后从第五个(元素下标为4)开始取值,取4条");

abc.forEach(System. out::print);

System. out.println;

Stream API可以极大提高 Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

/**

* 老办法实现一个list,存储3个6

*

* @return[6, 6, 6]

*/

privatestaticList oldSix {

// 老办法

List sixSixSix = newArrayList<>( 3);

sixSixSix.add( 6);

sixSixSix.add( 6);

sixSixSix.add( 6);

System.out.println( "老办法实现一个list,存储3个6");

for(Integer integer : sixSixSix) {

System.out. print(integer);

}

System.out.println;

returnsixSixSix;

}

/**

* 新方法实现一个list,存储3个6

*

* @return[6, 6, 6]

*/

privatestaticList newSix {

List sixSixSix = Stream.generate( -> 6).limit( 3).collect(Collectors.toList);

System.out.println( "新方法实现一个list,存储3个6");

sixSixSix. forEach(System.out::print);

System.out.println;

returnsixSixSix;

}

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

// 管道中传输,节点中处理

intpipe = abc.stream

// 筛选

.filter(i -> i > 'G')

// 排序

.sorted(Comparator.reverseOrder)

.mapToInt(Object::hashCode)

// 聚合

.sum;

System.out. println( "将26个字母组成的集合过滤出大于'G'的,逆序,再获取hashCode值,进行求和");

System.out. println(pipe);

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作 (terminal operation) 得到前面处理的结果。

// 将26个大写字母Character集合转换为String然后转换为小写字符

List< String> terminalOperation = abc.stream

// 中间操作(intermediate operation)

.map( String::valueOf).map( String::toLowerCase)

// 最终操作(terminal operation)

.collect(Collectors.toList);

System.out.println( "26个大写字母Character集合,转换成String然后转换为小写字符,收集起来");

terminalOperation.forEach(System.out::print);

System.out.println;

下面欢迎大家就 Lambda 和 Stream 相关问题向阿超老师提问,长按识别下方二维码/点击文末阅读原文直接回帖提问既可。

立即参与提问

相关内容

热门资讯

原创 福... 2025年11月5日,海南三亚某军港,中国第一艘电磁弹射型航空母舰福建舰正式入列。随着八一军旗授出,...
中超双雄亚冠再遇冷!海港再败蓉... 11月25日的亚冠赛场,再次成为映照中超球队“内外温差”的镜子。上海海港主场1-3完败首尔FC,跨赛...
七十亩果园“躲猫猫” 为何三天... 七十亩果园“躲猫猫” 为何三天就吸引近三百人参与? 专家:网红乡村体验项目要持续内容迭代,强化沉浸...
所罗门群岛总理:澳总理确实宣布... 【文/观察者网 熊超然】去年12月,所罗门群岛总理马内莱和澳大利亚总理阿尔巴尼斯发表联合声明称,澳大...
原创 克... 北京时间11月25日,克林根两双,罗威8分5板,俩人一起打了43分22秒,杨瀚森为什么只能打两分半钟...