一文掌握Lambda表达式(上)https://mp.youkuaiyun.com/mp_blog/creation/editor/125460693
目录
一、Optional
Optional是JDK1.8引入的一个对象容器,主要用作方法返回类型,如果存在值则isPresent()方法返回true否则返回false。下面我们看看具体方法如何使用
1.1 建造Optional
optional提供了两个静态建造方法of()和ofNullable;下面看看两者有什么区别
方法 | 说明 |
of(T value) | value不能为null,如果value是null则会抛出 NullPointerException |
ofNullable(T value) | value可以为null |
try {
//of方法value不允许为null,如果为null 则抛出NullPointerException
Optional.of(null);
} catch (NullPointerException npe) {
npe.printStackTrace();
}
//ofNullable允许值为null
Optional<Object> nonValueOptional = Optional.ofNullable(null);
1.2 是否有值
Optional中提供了连个静态方法判断是否有值,分别是isEmpty()和isPresent;两者语义相反
方法 | 说明 |
isEmpty() | 如果值为null则返回true,否则返回false;JDK 11以后提供 |
isPresent() | 如果值不为null则返回true,否则返回false,JDK8只能使用这个方法 |
1.3 获取值
Optional中获取值的方法如下表所示
方法 | 说明 |
get() | 值不能为null,如果为null则抛出一个NoSuchElementException |
orElse(T other) | 如果值不为null就返回值,否则返回默认值 value != null ? value : other |
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X | 如果值为null就抛出指定异常 |
T orElseGet(Supplier<? extends T> supplier) | 如果值为null,就返回supplier提供的值 |
orElseThrow() | 等价于get()方法,JDK10新增 |
1.4 过滤与映射
Optional除了上文的方法外还提供了类似Stream一样的操作,filter,map以及flatMap
方法 | 说明 |
filter(Predicate<? super T> predicate) | 如果值满足指定条件则不处理,否则就返回一个empty |
<U> Optional<U> map(Function<? super T, ? extends U> mapper) | 将值映射为另外一个值,并构建一个Optional返回 |
<U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) | flatMap与map相似,区别就是映射方法返回的就是Optional,直接使用该值返回 |
Optional<Integer> a= Optional.ofNullable(2).filter(Objects::nonNull).map(p -> 2*p);
Optional<Integer>b=Optional.of(2).filter(Objects::nonNull).flatMap(p->Optional.ofNullable(2*p));
二、Collectors
收集是流操作中很重要的处理,在Collectors中提供了一些辅助工具方法帮助我们更加方法处理流
2.1 计数
Collectors中提供了counting()方法用户统计流中元素的数量,如下文所示代码结果是5
Long collect = Stream.of(1, 2, 3, 4, 5).collect(Collectors.counting());
2.2 平均值
Collectors中提供了三个分别针对Integer,Double,Long求平均值的方法,不管是哪个方法返回数据类型都是double
Double average = Stream.of(1, 2, 3, 4, 5).collect(Collectors.averagingInt(p -> p));
average = Stream.of(1, 2, 3, 4, 5).collect(Collectors.averagingLong(p ->p));
average = Stream.of(1, 2, 3, 4, 5).collect(Collectors.averagingDouble(p ->p));
2.3 最值计算
Collectors也提供了求最大值和最小值的方法,具体示例如下文代码所示:
Integer max = Stream.of(1, 2, 3, 4, 5).collect(Collectors.maxBy(Integer::compareTo)).orElse(0);
Integer min = Stream.of(1, 2, 3, 4, 5).collect(Collectors.minBy(Integer::compareTo)).orElse(0);
System.out.println("max value is " + max + ", min value is " + min);
2.4 递归计算
Collectors提供了reducing方法用于递归计算,通过递归可以计算流中元素的和,乘积等如
方法 | 说明 |
reducing(BinaryOperator<T> op) | 没有初始值的递归处理返回结果为Optional, |
reducing(T identity, BinaryOperator<T> op) | 有初始值的递归处理,直接返回递归结果 |
reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) | 有初始值,对流中元素进行映射处理后进行递归 |
代码示例如下:
Integer sum = Stream.of(1, 2, 3, 4, 5).collect(Collectors.reducing((x, y) -> x + y)).orElse(0);
Integer sum2 = Stream.of(1, 2, 3, 4, 5).collect(Collectors.reducing(100, (x, y) -> x + y));
Integer sum3 = Stream.of(1, 2, 3, 4, 5).collect(Collectors.reducing(100, p -> 2 * p, (x, y) -> x + y));
System.out.println(sum + " , " + sum2 + " , " + sum3);
2.5 收集并转换
有时候我们在收集完成还需要对收集的结果进行一次处理,此时collectingAndThen方法就特别适合此场景;比如在计算出平均值以后,构造一个平均值是:xxx的字符串,就可以这样处理
String result = Stream.of(1, 2, 3, 4, 5).collect(Collectors.collectingAndThen(Collectors.averagingInt(p -> p), p -> "平均值是:" + p));
2.6 收集到集合
收集到集合是我们最常用的方法,主要的方法如下:
方法 | 说明 |
Collectors.toList() | 收集到List |
Collectors.toSet() | 收集到Set |
Collectors.toMap | 收集到Map |
Collectors.toUnmodifiableList() | 收集到不可变List |
Collectors.toUnmodifiableSet() | 收集到不可变Set |
Collectors.toUnmodifiableMap | 收集到不可变Map |
Collectors.toConcurrentMap | 收集到并发Map |
代码示例
Stream.of(1, 2, 3, 4, 5).collect(Collectors.toList());
Stream.of(1, 2, 3, 4, 5).collect(Collectors.toSet());
Stream.of(1, 2, 3, 4, 5).collect(Collectors.toUnmodifiableList());
Stream.of(1, 2, 3, 4, 5).collect(Collectors.toUnmodifiableSet());
Stream.of(1, 2, 3, 4, 5).collect(Collectors.toMap(p->"key_"+p,p->p,(k,v)->v));
Stream.of(1, 2, 3, 4, 5).collect(Collectors.toUnmodifiableMap(p->"key_"+p,p->p,(k,v)->v));
Stream.of(1, 2, 3, 4, 5).collect(Collectors.toConcurrentMap(p->"key_"+p,p->p,(k,v)->v));
2.5 分组收集
分组收集是流处理中比较复杂但是也是非常有用的处理。我们在工作中常常会遇到根据属性分组。比如有这样一组学生数据,我们需要按照性别分组,还有需要按照性别和姓进行多重分组我们就可以这样做:
public class StreamDemo {
public static void main(String[] args) {
Map<String, List<Student>> genderGroup = Stream.of(new Student("男", "张", "三")
, new Student("男", "李", "四"),
new Student("男", "王", "五")
, new Student("女", "李", "小草"),
new Student("女", "王", "小花")
).collect(Collectors.groupingBy(p -> p.getGender(), Collectors.toList()));
Map<String, Map<String,List<Student>>> multiGroup = Stream.of(new Student("男", "张", "三")
, new Student("男", "李", "四"),
new Student("男", "王", "五")
, new Student("女", "李", "小草"),
new Student("女", "王", "小花")
).collect(Collectors.groupingBy(p -> p.getGender(), Collectors.groupingBy(p->p.getFirstName())));
System.out.println(genderGroup);
System.out.println(multiGroup);
}
public static class Student {
/**
* 性别
*/
private String gender;
/**
* 姓
*/
private String firstName;
/**
* 名称
*/
private String lastName;
public Student(String gender, String firstName, String lastName) {
this.gender = gender;
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return "Student{" +
"gender='" + gender + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
}
输出的结果是:
{女=[Student{gender='女', firstName='李', lastName='小草'}, Student{gender='女', firstName='王', lastName='小花'}], 男=[Student{gender='男', firstName='张', lastName='三'}, Student{gender='男', firstName='李', lastName='四'}, Student{gender='男', firstName='王', lastName='五'}]}
{女={王=[Student{gender='女', firstName='王', lastName='小花'}], 李=[Student{gender='女', firstName='李', lastName='小草'}]}, 男={张=[Student{gender='男', firstName='张', lastName='三'}], 王=[Student{gender='男', firstName='王', lastName='五'}], 李=[Student{gender='男', firstName='李', lastName='四'}]}}