lambda之美
大前提:jdk8 允许lambda表达式 最好在maven中加入
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
只总结真香案例!!!
案例一:
从"1" "2" "bilibili" "of" "codesheep" "5" "codesheep" "5" "at" "BILIBILI" "codesheep" "23" "CHEERS" "6"中
找出所有 长度>=5的字符串,并且忽略大小写、去除重复字符串,然后按字母排序,最后用“ * ”连接成一个字符串输出
List<String> list = new ArrayList<>();
list.add("1");
···
list,add("6");
String str = list.stream()//list转为stream流
.filter(i -> !isNum(i))//过滤出不是数字的 也就是 得到字符 isNum是自己封装的方法
.filter(i -> i.length()>5)//过滤出长度大于5的
.map(i -> i.toLowerCase())//转为小写
.distinct()//去重
.sorted(Comparator.naturalOrder())//字符串排序
.collect(Collectors.joining("*"));//字符串连接
System.out.println(str);
案例二:
public class Lambda2 {
public static void main(String[] args) {
/**
* 函数接口:Predict
* 抽象方法:test(T t)
* 参数:T
* 返回值类型:Boolean
* 功能:判断真假
* 示例:判断学生身高
* 结果:韩非的身高高于185吗?: false
*/
Predicate<Integer> predicate = x -> x > 185;
Student student = new Student("韩非", 23, 175);
System.out.println("韩非的身高高于185吗?: " + predicate.test(student.getLength()));
/**
* 函数接口:Consumer
* 抽象方法:accept(T t)
* 参数:T
* 返回值类型:void
* 功能:消费消息
* 示例:输出值
* 结果:列东方位 青龙
*/
Consumer<String> consumer = System.out::println;
consumer.accept("列东方位 青龙");
/**
* 函数接口:Function
* 抽象方法:R apply(T t)
* 参数:T
* 返回值类型:R
* 功能:将T映射为R(转换功能)
* 示例:输出student名字
* 结果:韩非
*
* 备注:Student::getName这种lambda表达式写法被称为 方法引用 格式为 ClassName::MethodName
*/
Function<Student, String> function = Student::getName;
String name = function.apply(student);
System.out.println(name);
/**
* 函数接口:Supplier
* 抽象方法:T get()
* 参数:void
* 返回值类型:T
* 功能:生产消息
* 示例:工厂方法
* 结果:10
*/
Supplier<Integer> supplier = () -> Integer.valueOf(BigDecimal.TEN.toString());
System.out.println(supplier.get());
/**
* 函数接口:UnaryOperator
* 抽象方法:T apply(T t)
* 参数:T
* 返回值类型:T
* 功能:一元操作
* 示例:逻辑非(!)
* 结果:false
*/
UnaryOperator<Boolean> unaryOperator = uglily -> !uglily;
Boolean apply2 = unaryOperator.apply(true);
System.out.println(apply2);
//使用BinaryOperator函数式接口 抽象方法T apply(T t, U u) 功能:二元操作 参数T,U 返回值类型T 求两个数乘积
/**
* 函数接口:BinaryOperator
* 抽象方法:T apply(T t, U u)
* 参数:T,U
* 返回值类型:T
* 功能:二元操作
* 示例:求两个数乘积
* 结果: 6
*/
BinaryOperator<Integer> operator = (x, y) -> x * y;
Integer integer = operator.apply(2, 3);
System.out.println(integer);
/**
* 演示函数式接口
* 结果:我是一个演示的函数式接口
*/
test(() -> "我是一个演示的函数式接口");
}
/**
* 演示自定义函数式接口使用
*
* @param worker
*/
public static void test(Worker worker) {
String work = worker.work();
System.out.println(work);
}
public interface Worker {
String work();
}
}
案例三:
/**
* 惰性求值:只描述Stream,操作的结果也是Stream,这样的操作称为惰性求值。惰性求值可以像建造者模式一样链式使用,最后再使用及早求值得到最终结果。
* 及早求值:得到最终的结果而不是Stream,这样的操作称为及早求值。
*
* 常用的流:collect(Collectors.toList())
* 功能:将流转为list
* 结果:[Student(name=路飞, age=22, length=175, specialisies=null), Student(name=红发, age=40, length=180, specialisies=null)]
*/
List<Student> studentList = Stream.of(
new Student("路飞", 22, 175),
new Student("红发", 40, 180)
).collect(Collectors.toList());
System.out.println(studentList);
案例四:
/**
* 常用的流:filter
* 功能:顾名思义,起过滤筛选的作用。内部就是Predicate接口。惰性求值。
* 示例:筛选出身高小于180的同学
* 结果:[Student(name=路飞, age=22, length=175, specialisies=null)]
*/
List<Student> students = new ArrayList<>(3);
students.add(new Student("路飞", 22, 175));
students.add(new Student("红发", 40, 180));
students.add(new Student("白胡子", 50, 185));
List<Student> list = students.stream()
.filter(stu -> stu.getLength() < 180)
.collect(Collectors.toList());
System.out.println(list);
案例五:
/**
* 常用的流:map
* 功能:转换功能,内部就是Function接口。惰性求值
* 示例:获取所有同学的名字
* 结果:[路飞, 红发, 白胡子]
*/
List<Student> students = new ArrayList<>(3);
students.add(new Student("路飞", 22, 175));
students.add(new Student("红发", 40, 180));
students.add(new Student("白胡子", 50, 185));
List<String> names = students.stream().map(student -> student.getName())
.collect(Collectors.toList());
System.out.println(names);
案例六:
/**
* 常用的流:flatMap
* 功能:将多个Stream合并为一个Stream。惰性求值
* 示例:调用Stream.of的静态方法将两个list转换为Stream,再通过flatMap将两个流合并为一个
* 结果:[
* Student(name=路飞, age=22, length=175, specialisies=null),
* Student(name=红发, age=40, length=180, specialisies=null),
* Student(name=白胡子, age=50, length=185, specialisies=null),
* Student(name=艾斯, age=25, length=183, specialisies=null),
* Student(name=雷利, age=48, length=176, specialisies=null)
* ]
*/
List<Student> students = new ArrayList<>(3);
students.add(new Student("路飞", 22, 175));
students.add(new Student("红发", 40, 180));
students.add(new Student("白胡子", 50, 185));
List<Student> studentList = Stream.of(students,
Arrays.asList(new Student("艾斯", 25, 183),
new Student("雷利", 48, 176)))
.flatMap(students1 -> students1.stream()).collect(Collectors.toList());
System.out.println(studentList);
案例七:
/**
* 常用的流:max min
* 功能:我们经常会在集合中求最大或最小值,使用流就很方便。及早求值。
* 示例:得到年龄最大和最小的同学
* 结果:Student(name=白胡子, age=50, length=185, specialisies=null)
* Student(name=路飞, age=22, length=175, specialisies=null)
*
* 补充:max、min接收一个Comparator(例子中使用java8自带的静态函数,只需要传进需要比较值即可。)
* 并且返回一个Optional对象,该对象是java8新增的类,专门为了防止null引发的空指针异常。可以使用max.isPresent()判断是否有值;
* 可以使用max.orElse(new Student()),当值为null时就使用给定值;也可以使用max.orElseGet(() -> new Student());
* 这需要传入一个Supplier的lambda表达式。
*/
List<Student> students = new ArrayList<>(3);
students.add(new Student("路飞", 22, 175));
students.add(new Student("红发", 40, 180));
students.add(new Student("白胡子", 50, 185));
Optional<Student> max = students.stream()
.max(Comparator.comparing(stu -> stu.getAge()));
Optional<Student> min = students.stream()
.min(Comparator.comparing(stu -> stu.getAge()));
//判断是否有值
if (max.isPresent()) {
System.out.println(max.get());
}
if (min.isPresent()) {
System.out.println(min.get());
}
案例八:
/**
* 常用的流:count
* 功能:统计功能,一般都是结合filter使用,因为先筛选出我们需要的再统计即可。及早求值
* 示例:统计年龄小于45的人数
* 结果:年龄小于45岁的人数是:2
*/
public static void main(String[] args) {
List<Student> students = new ArrayList<>(3);
students.add(new Student("路飞", 22, 175));
students.add(new Student("红发", 40, 180));
students.add(new Student("白胡子", 50, 185));
long count = students.stream().filter(s1 -> s1.getAge() < 45).count();
System.out.println("年龄小于45岁的人数是:" + count);
}
案例九:
/**
* 常用的流:reduce
* 功能:reduce 操作可以实现从一组值中生成一个值。前面案例用到的 count 、 min 和 max 方法,因为常用而被纳入标准库中。事实上,这些方法都是 reduce 操作。及早求值。
* 示例:reduce接收了一个初始值为0的累加器,依次取出值与累加器相加,最后累加器的值就是最终的结果
* 结果:10
*/
public static void main(String[] args) {
Integer reduce = Stream.of(1, 2, 3, 4).reduce(0, (acc, x) -> acc+ x);
System.out.println(reduce);
}
案例十:
/**
* 收集器,一种通用的、从流生成复杂值的结构。只要将它传给 collect 方法,所有
* 的流就都可以使用它了。标准类库已经提供了一些有用的收集器,以下示例代码中的收集器都是从 java.util.stream.Collectors 类中静态导入的。
*
*
* 结果:人数最多的班级是:一班 一班平均年龄是:37.666666666666664
*/
public static void main(String[] args) {
List<Student> students1 = new ArrayList<>(3);
students1.add(new Student("路飞", 23, 175));
students1.add(new Student("红发", 40, 180));
students1.add(new Student("白胡子", 50, 185));
OutstandingClass ostClass1 = new OutstandingClass("一班", students1);
//复制students1,并移除一个学生
List<Student> students2 = new ArrayList<>(students1);
students2.remove(1);
OutstandingClass ostClass2 = new OutstandingClass("二班", students2);
//将ostClass1、ostClass2转换为Stream
Stream<OutstandingClass> classStream = Stream.of(ostClass1, ostClass2);
OutstandingClass outstandingClass = biggestGroup(classStream);
System.out.println("人数最多的班级是:" + outstandingClass.getName());
System.out.println("一班平均年龄是:" + averageNumberOfStudent(students1));
} /**
* 获取人数最多的班级
* 无论选择哪种返回值语句都可以
* 区别是 Optional中对null做了许多封装,可以进行空值的校验
* orElseGet方法 如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值
*/
private static OutstandingClass biggestGroup(Stream<OutstandingClass> outstandingClasses) {
// return outstandingClasses.max(Comparator.comparing(stu -> stu.getStudents().size())).get();
return Optional.of(outstandingClasses.max(Comparator.comparing(stu -> stu.getStudents().size())).get()).orElseGet(OutstandingClass:: new );
}
/**
* 计算平均年龄
*/
private static double averageNumberOfStudent(List<Student> students) {
return students.stream().collect(Collectors.averagingInt(Student::getAge));
}
案例十一:
/**
* 常用的流:Predicate
* 功能:将流分解成两个集合,接收一个Predicate函数式接口。
* 示例:按照会sing的和不会sing对学生进行分拆
* 结果:{
* false=[Student(name=红发, age=40, length=180, specialisies=swimming), Student(name=白胡子, age=50, length=185, specialisies=dance)],
* true=[Student(name=路飞, age=23, length=175, specialisies=sing)]
* }
* 和Collectors.groupingBy() 分组类似
*/
List<Student> students = new ArrayList<>(3);
Student stu1 = new Student("路飞", 23, 175);
stu1.setSpecialisies("sing");
students.add(stu1);
Student stu2 = new Student("红发", 40, 180);
stu2.setSpecialisies("swimming");
students.add(stu2);
Student stu3 = new Student("白胡子", 50, 185);
stu3.setSpecialisies("dance");
students.add(stu3);
Map<Boolean, List<Student>> listMap = students.stream().collect(
Collectors.partitioningBy(stu ->
stu.getSpecialisies().
contains(SpecialityEnum.SING.name)));
System.out.println(listMap); //使用Collectors.groupingBy()也可完成同样的功能
Map<Boolean, List<Student>> li = students.stream().collect(Collectors.groupingBy(student -> student.getSpecialisies().contains(SpecialityEnum.SING.name)));
System.out.println(li);
案例十二:
/**
* 常用的流:数据分组groupingBy 分组条件通常会被作为Map的key
* 功能:数据分组是一种更自然的分割数据操作,与将数据分成 ture 和 false 两部分不同,可以使用任意值对数据分组。Collectors.groupingBy接收一个Function做转换。
* 示例:按照会特长对学生进行分组
* 结果:{
* swimming=[Student(name=红发, age=40, length=180, specialisies=swimming)],
* sing=[Student(name=路飞, age=23, length=175, specialisies=sing)],
* dance=[Student(name=白胡子, age=50, length=185, specialisies=dance)]
* }
* 分组条件可以拼接多个 但是要和声明的类型(Map的key)一致
* 示例:声明类型是String
* 分组条件:特长***名字 stu.getSpecialisies()+"***"+stu.getName()
* 结果:{
* dance***白胡子=[Student(name=白胡子, age=50, length=185, specialisies=dance)],
* sing***路飞=[Student(name=路飞, age=23, length=175, specialisies=sing)],
* swimming***红发=[Student(name=红发, age=40, length=180, specialisies=swimming)]
* }
*/
List<Student> students = new ArrayList<>(3);
Student stu1 = new Student("路飞", 23, 175);
stu1.setSpecialisies("sing");
students.add(stu1);
Student stu2 = new Student("红发", 40, 180);
stu2.setSpecialisies("swimming");
students.add(stu2);
Student stu3 = new Student("白胡子", 50, 185);
stu3.setSpecialisies("dance");
students.add(stu3);
Map<String, List<Student>> listMap =
students.stream().collect(
Collectors.groupingBy(stu -> stu.getSpecialisies()));
System.out.println(listMap);
Map<String, List<Student>> lis =
students.stream().collect(
Collectors.groupingBy(stu -> stu.getSpecialisies()+"***"+stu.getName()));
System.out.println(lis);
案例十三:
/**
* 常用的流:拼接joining 有三个参数,第一个是分隔符,第二个是前缀符,第三个是后缀符。也可以不传入参数Collectors.joining(),这样就是直接拼接。
* 功能:类似stringbuilder这样循环append("a") append("b") append("c")拼接
* 示例:将所有学生的名字拼接起来
* 结果:[路飞,红发,白胡子]
*/
List<Student> students = new ArrayList<>(3);
students.add(new Student("路飞", 22, 175));
students.add(new Student("红发", 40, 180));
students.add(new Student("白胡子", 50, 185)); String names = students.stream()
.map(Student::getName).collect(Collectors.joining(",","[","]"));
System.out.println(names);
案例十四:
/**
* 接口:Consumer 顾名思义,它是“消费者的含义”,接受参数而不返回值
* 示例:打印消息
* 结果:hello world
* hello java
* hhhhh
* hhhhh
* hhhhh
*/
Consumer c = System.out::println;
c.accept("hello world");//打印hello world
c.accept("hello java");//打印hello java
c.andThen(c).andThen(c).accept("hhhhh");//连续打印三次hhhhh 而不是hello java hello java hhhhh
案例十五:
/**
* 接口:Function 代表的含义是“函数”,其实和上面的 Consumer有点像,不过 Function既有输入,也有输出,使用更加灵活
* 示例:对一个整数先乘以 2,再计算平方值
* 结果:36 5184
* 过程:先走apply传递参数3 然后执行f1=3*2得到6 然后执行f2=6*6得到36
* 先走apply传递参数3 然后执行f1=3*2得到6 然后执行f2=6*6得到36 然后执行f1=36*2得到72 然后执行f2=72*72得到5184
* andThen的参数就是 Function类型的after 即接下里执行的函数
*/
Function<Integer,Integer> f1 = i -> i*2;
Function<Integer,Integer> f2 = i -> i*i;
Consumer c = System.out::println; c.accept(f1.andThen(f2).apply(3));
c.accept(f1.andThen(f2).andThen(f1).andThen(f2).apply(3));
案例十六:空值校验
/**
* 接口:Optional 本质是个容器,你可以将你的变量交由它进行封装,这样我们就不用显式对原变量进行 null值检测,防止出现各种空指针异常
* 示例:获取学生科目的成绩
*/
public static Integer getScore(Student stu){
return Optional.ofNullable(stu).map(Student::getSubject).map(Subject::getScore).orElse(null);
}
//常规做法 判断学生是否为空,不为空得到学科,判断学科是否为空,不为空取值 如果有很多层包着 简直是俄罗斯套娃 惨不忍睹
public static Integer getScore(Student stu){
if(stu != null){
Subject sub = stu.getSubject();
if (sub != null){
return sub.getScore();
}
}
return null;
}
lambda之美的更多相关文章
- 感受lambda之美,推荐收藏,需要时查阅
一.引言二.java重要的函数式接口1.什么是函数式接口1.1 java8自带的常用函数式接口.1.2 惰性求值与及早求值2.常用的流2.1 collect(Collectors.toList())2 ...
- 来探讨一下最近面试问的ThreadLocal问题
中高级阶段开发者出去面试,应该躲不开ThreadLocal相关问题,本文就常见问题做出一些解答,欢迎留言探讨. ThreadLocal为java并发提供了一个新的思路, 它用来存储Thread的局部变 ...
- JAVA8中Predicate,Consumer,UnaryOperator,Function接口的应用
笔者平时时间有限,直接贴代码,关于几个接口的差别,可以查看这两篇文章 感受lambda之美,推荐收藏,需要时查阅 https://juejin.im/post/5ce66801e51d455d850d ...
- java代码之美(1)---Lambda
Lambda 一.概述 1.什么是Lambda表达式 Lambda 表达式是一种匿名函数,简单地说,它是没有声明的方法,也即没有访问修饰符.返回值声明和名字. 它可以写出更简洁.更灵活的代码.作为一种 ...
- Delegate &&Lambda
匿名函数及委托的使用: public delegate void NoReturnNoParaOutClass();//delegate can be defined in class or out ...
- Lambda in Java VS in C#
核心+变化 “凡是钱能解决的问题,就不是大问题.有很多问题是钱无法解决的,比如生老病死,比如不再相爱.”,看过<蜗居>的朋友一眼就能认出来.虽然这部电视剧讲的是chugui,但是毫无违和感 ...
- 泛化之美--C++11可变模版参数的妙用
1概述 C++11的新特性--可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数.任意类型的参数.相比C++98/03 ...
- 20155326刘美岑 2016-2017-2 《Java程序设计》第5周学习总结
20155326刘美岑 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 使用 try.catch (1)java中所有的错误都会被打包为对象,如果愿意,可以尝 ...
- [转]C# 指针之美
将C#图像库的基础部分开源了(https://github.com/xiaotie/GebImage).这个库比较简单,且离成熟还有一段距离,但它是一种新的开发模式的探索:以指针和非托管内存为主的C ...
随机推荐
- 上位机面试必备——TCP通信灵魂二十问【下】
上篇文章跟大家介绍了TCP通信常见的前10个面试题,没看过的小伙伴可以点击下方链接进行查看: 上位机面试必备——TCP通信灵魂二十问[上] 今天就后面的10个面试题接着做下说明:欢迎关注[dotNet ...
- C# 9.0 终于来了, Top-level programs 和 Partial Methods 两大新特性探究
一:背景 1. 讲故事 .NET 5 终于在 6月25日 发布了第六个预览版,随之而来的是更多的新特性加入到了 C# 9 Preview 中,这个系列也可以继续往下写了,废话不多说,今天来看一下 To ...
- 入门大数据---Scala学习
Scala是什么? Scala是一种基于函数式编程和面向对象的高级语言.它开发了Spark等大型应用.它和Java有效集成,底层也是支持JVM的. 它有六大特性: 无缝JAVA互操作 Scala在JV ...
- yum只下载不安装
1 修改/etc/yum.conf的keepcache=1 [root@136 packages]# vi /etc/yum.conf keepcache=1 2 安装yum-utils包 [root ...
- Hystrix入门教程
Hystrix入门教程 一·什么是Hystrix?Hystrix有什么作用?使用Hystrix有哪些适用场景 Hystrix是springCloud的组件之一,Hystrix 可以让我们在分布式系统中 ...
- 平时自己常用的git指令
增删改查 创建标签 $ git tag -a v1.4 -m 'my version 1.4' 用 -a (译注:取 annotated 的首字母)指定标签名字即可 -m 选项则指定了对应的标签说明 ...
- Asp.net Core AOP实现(采用Autofac)
引用正确的库来实现AOP 新的.NET Core是基于.NET Standard的..所以我们在引用库的时候特别要注意相关的兼容问题. 在传统的ASP.NET中,使用过Autofac来进行AOP操作的 ...
- VS2017配置PCL1.9.1 for win10
安装链接 https://www.jianshu.com/p/463f54c91ab7 1.9.1 安装包下载 官网路径: https://github.com/PointCloudLibrary/p ...
- Cache写策略(Cache一致性问题与骚操作)
写命中 写直达(Write Through) 信息会被同时写到cache的块和主存中.这样做虽然比较慢,但缺少代价小,不需要把整个块都写回主存.也不会发生一致性问题. 对于写直达,多出来%10向主存写 ...
- 手把手教你玩转Git
文章已托管到GitHub,大家可以去GitHub查看下载!并搜索关注微信公众号 码出Offer 领取各种学习资料! 微信公众号码出Offer Git应用 一.初识Git 1.1 Git的简史 同生活中 ...