Java8中Stream、Function、Opotions特性使用案例

所有数据都基于UserInfo类,其中包含了 userId、userName、course、score 等字段,下面是如何使用Options、 Stream 、Function来处理 UserInfo 对象列表的一些示例

List<UserInfo> userInfoList = Arrays.asList(
                new UserInfo(1L, "Alice", "Math", 90),
                new UserInfo(2L, "Bob", "Physics", 85),
                new UserInfo(3L, "Charlie", "Chemistry", 88),
                new UserInfo(4L, "Diana", "Math", 92),
                new UserInfo(5L, "Eve", "Physics", 89)
        );

@Data
public static class UserInfo {
        private Long userId;
        private String userName;
        private String course;
        private int score;

        public UserInfo(Long userId, String userName, String course, int score) {
            this.userId = userId;
            this.userName = userName;
            this.course = course;
            this.score = score;
        }

        public String getCourse() {
            return course;
        }
}

所有数据都基于UserInfo类,其中包含了 userId、userName、course、score 等字段,下面是如何使用 Java Stream API 来处理 UserInfo 对象列表的一些示例

  List<UserInfo> userInfoList = List.of(
                new UserInfo(1L, "Alice", "Math", 90),
                new UserInfo(2L, "Bob", "Physics", 85),
                new UserInfo(3L, "Charlie", "Chemistry", 88),
                new UserInfo(4L, "Diana", "Math", 92),
                new UserInfo(5L, "Eve", "Physics", 89)
        );

一、Stream用法

    Stream是Java 8中引入的全新API,可以极大地方便我们对集合、数组等数据源进行连续操作

 

1.1 流的创建

通过集合 Collection.stream() 创建 Stream,一般开发中常用这种方式创建流

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Stream<String> streamFromCollection = names.stream();

通过数组 Arrays.stream 创建 Stream

String[] names = {"Alice", "Bob", "Charlie"};
Stream<String> streamFromArray = Arrays.stream(names);

通过 Stream.of() 方法创建 Stream

Stream<String> streamFromOf = Stream.of("Alice", "Bob", "Charlie");

使用 Stream.iterate() 创建无限流

 Stream<Long> infiniteStream = Stream.iterate(0L, n -> n + 2)
                                             .limit(5); // 限制元素数量

⚠️注意:Stream.iterate() 方法可以用来创建无限流,但在实际使用时通常会配合limit()方法来限制流中的元素数量,以避免无限循环

1.2 流的使用

1.2.1 foreach遍历

 🌰示例 : 打印所有用户的信息

userInfoList.stream().forEach(System.out::println);

1.2.2 filter过滤

🌰示例:找出所有学数学的学生

List<UserInfo> userList = userInfoList.stream()
               .filter(user -> "Math".equals(user.getSubject()))
               .collect(Collectors.toList());

1.2.3 sorted排序

sorted支持两种方式:

//自然排序,元素须实现 Comparable 接口,并且 compareTo 方法将被用于确定排序顺序
Stream<T> sorted();
//自定义排序,使用 Comparator
Stream<T> sorted(Comparator<? super T> var1);

🌰示例:按照分数升序排序

List<UserInfo> userList = userInfoList.stream()
               .sorted(Comparator.comparing(UserInfo::getScore))
               .collect(Collectors.toList());

1.2.5 map/flatMap映射

🌰示例 : 获取所有用户的名字userName

List<String> userNameList = userInfoList.stream()
             .map(UserInfo::getUserName)
             .collect(Collectors.toList());

1.2.4 distinct 去重

 🌰示例 :获取所有学科名称

List<String> courseList = userInfoList.stream()
             .map(UserInfo::getCourse)
             .distinct()
             .collect(Collectors.toList());

1.2.6 reduce规约

 🌰示例 : 计算总分

int totalScore = userInfoList.stream()
                .map(UserInfo::getScore)
                .reduce(Integer::sum)
                .orElse(0); //流中没有任何元素时返回默认值0

                //或者默认初始值为0 
                //.reduce(0, Integer::sum)

1.2.7 collect收集

1.2.7.1 toList/toSet/toMap归集

toList/toSet

🌰示例 :将用户收集到新的集合中

List<UserInfo> userList = userInfoList.stream()
                           .collect(Collectors.toList());

Set<UserInfo> userList = userInfoList.stream()
                           .collect(Collectors.toSet());

toMap有一点特殊

🌰示例2:获取userInfoList的映射集合Map<userId,UserInfo>

Map<String, UserInfo> userInfoMap = userInfoList.stream()
                .collect(Collectors.toMap(UserInfo::getUserId, userInfo -> userInfo));
Map<String, UserInfo> userInfoMap = userInfoList.stream()
                .collect(Collectors.toMap(UserInfo::getUserId, Function.identity()));

 lambda 表达式 userInfo -> userInfo 作为第二个参数传递给 Collectors.toMap()。这与使用 Function.identity() 的效果相同,因为 Function.identity() 本质上就是返回一个函数,该函数接收一个参数并返回相同的参数

⚠️:可能会出现Duplicate Key

因此:

Map<Long, UserInfo> userInfoMap = userInfoList.stream()
                .collect(Collectors.toMap(
                             UserInfo::getUserId,
                             Function.identity(), 
                             (newVal,oldVal)->newVal));

🌰示例:按照userInfoList的插入顺序转为集合Map<userId,UserInfo>

Map<Long, UserInfo> userInfoMap = userInfoList.stream()
                .collect(Collectors.toMap(
                             UserInfo::getUserId,
                             Function.identity(), 
                             (newVal,oldVal)->newVal),
                             LinkedHashMap::new
);
1.2.7.2 groupingBy分组

🌰示例:将所有用户按课程分组

Map<String, List<UserInfo>> usersByCourse = userInfoList.stream()
                .collect(Collectors.groupingBy(UserInfo::getCourse));
1.2.7.3 joining拼接

🌰示例:将所有的用户名使用“,”拼接成字符串返回

 String allName = userInfoList.stream()
                  .map(UserInfo::getName)
                  .collect(Collectors.joining(", "));
1.2.7.4 counting/summingInt/averagingInt/summarizingInt聚合

计数:counting

最值:maxBy、minBy

求和:summingInt、summingLong、summingDouble

平均值:averagingInt、averagingLong、averagingDouble

统计以上所有:summarizingInt、summarizingLong、summarizingDouble,其中包含了流中元素的计数、总和、平均值、最小值和最大值

                        

 🌰示例 : 计算总分

 使用 .collect 和 Collectors.summingInt

int totalScore = userInfoList.stream().collect(Collectors.summingInt(UserInfo::getScore));

1.2.7.4 reducing 规约

 🌰示例 : 计算总分

Integer toatlScore = userInfoList.stream()
                .collect(Collectors.reducing(0, UserInfo::getScore, Integer::sum));
1.2.7.5  max/min/sum/count聚合

🌰示例 :获取最高分

int maxScore = userInfoList.stream()
               .mapToInt(UserInfo::getScore)
               .max()
               .orElse(0);

⚠️:此处如果使用.map(UserInfo::getScore) 会错误,由于于StreamIntStream的区别,以及它们各自提供的max()方法的不同

Stream的max()需要实现Comparator来比较元素

Optional<T> max(Comparator<? super T> comparator)

而IntStream的max()

OptionalInt max();

 🌰示例 : 计算总分

reduce求和的结果是一样,但sum方法通常会更快一些,因为它直接针对IntStream进行了优化

int totalScore = userInfoList.stream()
                 .mapToInt(UserInfo::getScore)
                 .sum()
1.2.7.6 peek查看

1.2.7 limit/skip

🌰示例:按分数排序


serName

List<String> userNames = userInfoList.stream().map(UserInfo::getUserName).collect(Collectors.toList());

1.2

🌰示例:将所有用户按课程course分组

Map<String, List<UserInfo>> usersByCourse = userInfoList.stream()
                .collect(Collectors.groupingBy(UserInfo::getCourse));

🌰示例:将所有用户的分数求和

📌方法1:使用 .map 和 .reduce

int totalScore = userInfoList.stream().map(UserInfo::getScore).reduce(0, Integer::sum);

📌方法2:使用 .collect 和 Collectors.summingInt

int totalScore = userInfoList.stream().collect(Collectors.summingInt(UserInfo::getScore));

📌方法3:使用 .mapToInt 和 .sum

int totalScore = userInfoList.stream() .mapToInt(UserInfo::getScore) .sum();

Lambda使用了函数式编程,在jdk1.8中内置了四个常用的函数式编程的接口,分别是:Function、Predicate、Supplier、Consumer。下面我们来分别介绍下这些类

java -Function、Predicate、Supplier、Consumer及自定义实现

二、Optional

不使用Optional的示例:需要手动检查列表是否为空,并处理空值情况。
使用Optional的示例:简化了代码,通过Optional自动处理空值情况

1. 创建Optional对象
Optional.of(T value):创建一个包含非空值的Optional对象。
Optional.ofNullable(T value):创建一个包含非空值的Optional对象,如果值为null则返回一个空的Optional对象

Map<Long, Map<String, Long>> meterTypeMap = Optional.ofNullable(meterTypeList)
.orElse(Collections.emptyList()).stream()
.collect(Collectors.groupingBy(
    DeviceMeterTypeEntity::getProjectId,         
    Collectors.toMap(
        DeviceMeterTypeEntity::getMeterSign, 
        DeviceMeterTypeEntity::getDeviceTypeId)));

通过这些示例,我们可以看到Optional如何帮助我们安全地处理可能为空的情况,并提供默认值。这样可以避免空指针异常,使代码更加健壮。Optional的主要用法包括:
创建Optional对象:使用Optional.of或Optional.ofNullable。
检查Optional是否为空:使用isPresent或isEmpty。
获取Optional中的值:使用get或orElse。
处理Optional中的值:使用ifPresent或ifPresentOrElse。
转换Optional中的值:使用map或flatMap。

二、Function用法

在Java中,Function<T,R>接口是Java 8引入的函数式接口之一,它代表了一个将一个类型的参数映射到另一个类型的返回值的函数。下面通过UserInfo类的例子来展示Function的几种常见用法:

Function函数有三个主要的方法:apply、compose、andThen
apply:该方法意义是执行当前函数的方法体。
compose(before):先执行before函数方法体,使用其返回参数,再执行调用者函数的方法体。
andThen (after):先执行调用者方法,将其返回值作为参数调用after函数方法体

使用Function

  Function<UserInfo, Long> getUserId = UserInfo::getUserId;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值