lambda表达式
在Java8中引入了一个新的操作符“->”,该操作符称为箭头操作符或Lambda操作符。
左侧:Lambda表示式的参数列表
右侧:Lambda表达式中所要执行的功能
语法格式
1.无参数,无返回值()-> System.out.print(“Hello Word”);
1 |
|
2.一个参数,无返回值(x)-> System.out.print(x);
1 |
|
如果只有一个参数,无返回值可以省略小括号不写。
3.两个参数,有返回值,并且有多条执行语句
1 |
|
4.如果只有一条返回语句
1 |
|
注意说明
lambda表达式中的参数类型可以省略不写,JVM可以根据上下文推断出类型
Lambda表达式需要函数式接口的支持。
函数式接口
接口中只有一个抽象方法的接口,就叫函数式接口。可以使用注解@FunctionalInterface检查是否为函数式接口。
1 |
|
函数式接口示例
1.定义一个函数式接口
1 |
|
2.定义一个方法,方法的参数为函数式接口
1 | public Integer operation(Integer num,MyFun mf){ |
3.使用Lambda表达式
1 |
|
Lambda表达式左侧是函数式接口的参数,右侧是函数式接口的实现。
Lambda练习
练习一
将集合中的员工排序,按照年龄从小到大排序,如果年龄相同就按照名称排序
1 | public class TestLambda { |
练习二
对字符串进行处理
1.申明一个函数式接口,用于处理字符串
1 |
|
2.申明一个处理字符串的方法,返回处理后的结果
1 | public String strHandle(String str,MyFunction mf){ |
3.调用处理方法,使用Lambda表达式实现字符串的不同处理
1 |
|
练习三
计算两个long型参数做处理
1.声明一个函数式接口
1 |
|
2.定义处理方法
1 | public void operator(Long l1,Long l2,MyFunction2<Long,Long> mf){ |
3.使用Lambda表达式
1 |
|
lambda表达式总结
从上述代码中,我们可以看出Lambda表达式的好处,但是我们会发现,每次使用都会新建一个函数式接口,增加了很多麻烦,所以,Java8给我们增加了很多函数式接口,
四大核心函数接口
- Consumer
消费型接口: 参数类型 T 返回类型 void 对类型T的对象应用操作 - Supplier
供给型接口: 参数类型 无 返回类型 T 返回类型为T的对象 - Function<T,R>函数型接口: 参数类型 T 返回类型 R 对了类型为T的对象应用操作,并返回结果
- Predicate
断言型接口: 参数类型 T 返回类型 boolean 确定类型为T的对象是否满足某约束,并返回布尔值。
Consumer示例
1 |
|
Supplier示例
1 |
|
上述使用Lambda表达式就是产生10个100以内的随机数。
Function示例
1 |
|
Predicate示例
将满足条件的字符串添加到集合中
1 |
|
函数接口总结
- Consumer消费型是传入一个参数,进行处理
- Supplier供给型是得到一些结果
- Function函数型是传入一个参数,处理后返回一个结果
- Predicate断言型就是做一些判断操作
- 有无参数和返回值是指Predicate
per等调用的方法需不需要参数和有无返回值,例如:per.test(str)、fun.apply(str)、sup.get()等。
方法引用
当要传递给Lambda体的操作,已经有了实现的方法,可以使用方法引用.
(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致)。
方法引用:使用操作符“::”将方法名和对象或类的名字分割开,例如:
- 对象::实例方法
- 类::静态方法
- 类::实例方法
对象::实例方法示例
1 |
|
例如打印一个字符串:
1 |
|
注意:con.accept()中的accept的参数类型和返回值和println参数类型和返回值一致
类::静态方法
方法引用的实质就是使用更简单的方式代替Lambda表达式。下述代码就是类::静态方法的一个实例。
1 |
|
类::实例方法如下
1 |
|
构造器引用
1 |
|
其中构造器方法调用哪一个构造器取决与接口Supplier中的方法参数,Supplier就是调用的无参构造器,例如Function函数接口就是传入一个参数,并返回一个结果。如下
1 |
|
Function<String,Employee>中的String是传入参数类型,Employee是返回结果类型。
如果我们想传入两个参数,并返回一个结果,就必须要在Employee中创建两个含两个参数的构造器,如下
1 |
|
注意:Employee中构造器参数列表和接口中的方法fun.apply(“赵六”,123);参数列表保持一致。
数组引用
数组引用格式
type[]::new
1 |
|
上述代码就是使用Lambda表达式传入一个数组大小,从而创建一个指定大小和类型的数组。
使用数组引用为:
1 | Function<Integer,String[]> fun2 = String[]::new; |
StreamAPI
Stream简介
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行测操作,可以执行非常复杂的查找,过滤和映射数据的操作,使用Stream API对集合数据进行操作就类似于使用SQL执行的数据库查询查询,Stream API提供了一种高效且易于使用的处理数据的方式。
流(Stream)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列,“集合讲的是数据,流讲的是计算”,需要注意的是以下三点
- Stream自己不会存储元素
- Stream不会改变源对象,相会,他们会返回一个持有结果的新的Stream
- Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。
Stream使用方法
- 创建Stream:一个数据源(集合、数组)获取一个流
- 中间操作:一个中间操作链,对数据源的数据进行处理
- 终止操作:一个终止操作,执行中间操作链,并产生结果。
创建Stream的方法
- 通过Collection系列提供的stream()或parallelStream(),如下:
- 通过Arrays中的静态方法stream()方法获取流
- 通过Stream类中的静态方法of()
- 创建无限流
创建Stream的方法示例
1 |
|
中间操作
- filter—-接受lambda,从流中排除某一些元素
- limit—-截断流,使其元素不超过给定的数量
- skip(n)—-跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流
- distinct—-筛流,通过流生成元素的hashcode()和equals()去除重复元素
filter示例
1 |
|
惰性求值和内部迭代
- 如果没有终止操作,是不会打印中间操作的,这就是流只有需要结果的时候才会被调用,这就是惰性求值。
- 上述打印是Stream自己给我们迭代输出的,这个就是内部迭代。
筛选和切片示例如下
1 |
|
说明:由于distinct是根据hashcode()和equals()去重,所以Employee中要重写equals和hashCode方法。
映射
- map(Function f) 接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
- mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
- mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
- flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
map示例
1 |
|
flatMap示例
1 |
|
排序
sorted()-自然排序(comparable)
1 |
|
sorted(Comparator com)-定制排序(Comparator)
1 |
|
终止操作
终止操作会从流的流水线生成结果,该结果可以是任何不是流的值,例如:List、Integer、void。
查找和匹配
- allMatch(Predicate p) 检查是否匹配所有的元素
- anyMatch(Predicate p) 检查是否至少匹配一个元素
- noneMatch(Predicate p) 检查是否没有匹配所有的元素
- findFirst() 返回第一个元素
- findAny() 返回当前流中的任意元素
- count() 返回流中元素个数
- max(Comparator c) 返回流中最大值
- min(Comparator c) 返回流中最小值
- forEach(Consumer c) 内部迭代
示例如下:
1 | public class TestStreamAPI { |
归约
reduce(T iden,BinaryOperator b)可以将流中元素反复结合起来,得到一个值,返回T,示例如下:
1 |
|
上述代码中使用map得到所有的工资,再有reduce将所有的工资累加,map和reduce配合使用情况比较多。
收集
collect(Collector c)将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
Colletor接口中的方法实现决定了如何对流执行收集操作(如收集到List,Set,Map),但是Collectors实用类提供了很多静态的方法,可以方便的创建常用收集器实例,具体方法与实例如下:
- toList 返回List
将流中元素搜集到List - toSet 返回Set
将流中元素手机到Set - toCollection 返回Collection
把流中元素收集到创建的集合中 - counting 返回Long 计算流中元素的个数
- summinglnt 返回Integer 对流中元素的整数属性求和
- averaginglnt 返回Double 计算流中元素Integer属性的平均值
- summarizinglnt 返回IntSummaryStatistics 计算流中Integer属性的统计值,如平均值。
- joining 返回String 连接流中每一个字符串
- maxBy 返回Optional
根据比较器选择最大值 - minBy 返回Optional
根据比较器选择最小值 - reducing 归约产生的类型
- collectionAndThen 转换函数返回的类型
实例如下:
1 |
|
StreamAPI练习
1.给定一个数字列表,返回一个由每一个数的平方构成的列表。
1 |
|
2.使用map和reduce方法数一数流中有多少个Employee
1 |
|
交易员类
1 | public class Trader { |
交易类
1 | public class Transaction { |
练习
1 | public class TestTransaction { |
LocalDateTime
LocalDateTime是一个不可变的日期时间对象,代表日期时间,通常被视为年 - 月 - 日 - 时 - 分 - 秒。
方法摘要
1 | Temporal adjustInto(Temporal temporal) 调整指定的时间对象与此对象具有相同的日期和时间。 |