一文掌握Lambda表达式(下)

本文介绍了Java 8中的Optional对象及其用法,包括建造Optional、检查值存在性、获取值、过滤映射,以及Collectors工具在流操作中的应用,如计数、平均值计算、最值求解和分组收集。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一文掌握Lambda表达式(上)icon-default.png?t=M5H6https://mp.youkuaiyun.com/mp_blog/creation/editor/125460693

目录

一、Optional

1.1 建造Optional

1.2 是否有值 

1.3 获取值 

1.4 过滤与映射 

二、Collectors

2.1 计数

2.2 平均值 

2.3 最值计算

2.4 递归计算 

2.5 收集并转换

2.6 收集到集合

2.5 分组收集


一、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='四'}]}}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈脩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值