文章目录
- 推演过程
- 如何理解lambda
- lambda的几种写法
- 大括号的注意点
- Stream
- 可继续
- 不可继续
- :: 方法引用(函数引用)
- 1、构造器引用(构造方法引用)
- 2、静态方法引用
- 3、某个对象的实例方法引用
- 4、
- list转换为list
- list转换为map
- Function.identity()是什么意思呢
- map转换为list
- 性能问题
- 附录
- 参考文档
- set 循环用逗号拼接
刚接触时比较生疏,好久都没能会用,后来偶然回头一看,居然会用了。
推演过程
说是函数式接口。其实也可以理解为匿名内部类。
最简单的例子:
@FunctionalInterface// 表示函数式接口,编译的时候会强制校验publicinterfaceAnimal{voidshow();publicstaticvoidmain(String[]args){Animalperson=()->System.out.println("2 tiao tui");//人有2条腿person.show();Animalpig=()->System.out.println("4 tiao tui");// 猪有四条腿pig.show();}}带参数的例子:
publicinterfaceCount{intadd(inta,intb);publicstaticvoidmain(String[]args){Countcount=(a,b)->a+b;// 如果只有一个参数,小括号也不用加System.out.println(count.add(2,3));}}省略写法:
@FunctionalInterfacepublicinterfaceAnimal{voidshow(Stringname);publicstaticvoidmain(String[]args){Animalperson=(name)->System.out.println("name");person.show("ren");Animalpig=System.out::println;//入参和方法中调用的是同一对象的时候,连入参也可以省略了pig.show("zhu");}}省略写法构造对象:
Acount 代码:
@DatapublicclassAcount{privateStringusername;privateStringpassword;publicAcount(Stringusername,Stringpassword){this.username=username;this.password=password;}}Manager代码:
publicinterfaceManager{Objectcreate(Stringusername,Stringpassword);publicstaticvoidmain(String[]args){Manageracount=(username,password)->newAcount(username,password);System.out.println(acount);Manageracount2=Acount::new;// 入参的所有参数给方法体,那么可以简写System.out.println(acount2);}}如何理解lambda
刚接触lambda确实有点蒙,不太看的懂。
但是只要抓住要点,lambda的变动点只有入参具体值和实现。
把握好这2个节点,就容易理解了。
lambda的几种写法
入参声明类型:(inta,intb)->{logger.info("1";)}入参不声明类型:(a,b)->{logger.info("1";)}出参大括号:(a,b)->{logger.info("1";)}出参不用大括号(写法待确认):(a,b)->logger.info("1";)大括号的注意点
如果有大括号,里面的语句要加;(分号),因为语句肯定要加分号的。
Strings=null;Optional<String>op=Optional.ofNullable(s);对比下这两句,如果有大括号,里面的语句要加;(分号)op.ifPresent((a)->System.out.println(1));op.ifPresent((a)->{System.out.println(1);});如果没有入参,那么方法名就是()->,千万别惯性的每次都写个a->,是和Function有关的。
如:
Optional.of(1111).orElseThrow(()->newException());Stream
stream是非常常用的。
里面的方法大致分为2类。
可继续,不可继续。
可继续
例如map(),filter()
不可继续
例如.count()等。
:: 方法引用(函数引用)
最常见的就是这个ArrayList::new,实际有用法远不止这几种。
注:::是方法引用,并没有调用,有时感觉能直接拿到对象,是因为其他函数刚好接收函数这个函数式接口,框架内部自动实现了调用。
1、构造器引用(构造方法引用)
Suppliersupplier=String::new;// 正确// 正确Optional<String>opt=Optional.empty();Stringval=opt.orElseGet(String::new);// ✅HashMap<Object,Object>map=newHashMap<>();map.computeIfAbsent("key",String::new);// 错误为什么同样是String::new,有的成功有的失败呢?
因为computeIfAbsent()
2、静态方法引用
// Function<T,String> 接收任意对象,转字符串Function<Object,String>func=String::valueOf;System.out.println(func.apply(123));// "123"System.out.println(func.apply(null));// "null"// Stream 场景最常用List<Integer>list=List.of(1,2,3);list.stream().map(String::valueOf).forEach(System.out::println);3、某个对象的实例方法引用
System.out::println✅ 实例方法引用(绑定指定对象) 疑问:System不是类吗?是类,System.out,拿现成的PrintStream实例,引用它的实例方法4、
list转换为list
Collectors.toList()
List<Dict>listConvert=list.stream().map(DictUtils::convert).collect(Collectors.toList());log.info("listConvert={}",JSON.toJSONString(listConvert));list转换为map
Collectors.toMap(Dict::getCode,Function.identity())
Map<String,Dict>map=list.stream().collect(Collectors.toMap(Dict::getCode,Function.identity()));log.info("map={}",JSON.toJSONString(map));Function.identity()是什么意思呢
Function.identity()相当于返回原对象。
map转换为list
map有stream吗? 没有 map的叫做forEach
map.forEach((key,value)->{
log.info(“key={},value={}”, key,JSON.toJSONString(value));
});
虽然map不能直接用stream,但是map.entrySet()可以用stream。 mapToList
List<Map.Entry<String, Dict>> collect = map.entrySet().stream().collect(Collectors.toList());
性能问题
lambda的优点是简洁,当然也有缺点,例如在循环中性能比较慢。
如果数量比较大,性能差距明显。
结论已经比较确定了,无论是实测性能,还是从反汇编分析,都证明确实慢。
因为标准的方法是先编译,后执行。lambda表达式是在运行时动态编译的,肯定比非lambda慢。
附录
参考文档
官网地址:
其实很多中文网站及博客也有很多这方面的资料。
set 循环用逗号拼接
// TODO