Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

0%

# 记录下 Java Stream 的一些高效操作

发表于 2022-05-15 分类于 java 阅读次数： 阅读次数： Disqus：

我们日常在代码里处理一些集合逻辑的时候用到 Stream 其实还挺多的，普通的取值过滤集合一般都是结合 ide 的提示就能搞定了，但是有些不太常用的就在这记录下，争取后面都更新记录下来。

### 自定义 distinctByKey 对结果进行去重

stream 中自带的 distinct 只能对元素进行去重
比如下面代码

    public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(1);
            list.add(2);
            list = list.stream().distinct().collect(Collectors.toList());
            System.out.println(list);
        }

结果就是去了重的

    [1, 2]

但是当我的元素是个复杂对象，我想根据对象里的某个元素进行过滤的时候，就需要用到自定义的 `distinctByKey` 了，比如下面的想对 userId 进行去重

    public static void main(String[] args) {
            List<StudentRecord> list = new ArrayList<>();
            StudentRecord s1 = new StudentRecord();
            s1.setUserId(11L);
            s1.setCourseId(100L);
            s1.setScore(100);
            list.add(s1);
            StudentRecord s2 = new StudentRecord();
            s2.setUserId(11L);
            s2.setCourseId(101L);
            s2.setScore(100);
            list.add(s2);
            StudentRecord s3 = new StudentRecord();
            s3.setUserId(12L);
            s3.setCourseId(100L);
            s3.setScore(100);
            list.add(s3);
            System.out.println(list.stream().distinct().collect(Collectors.toList()));
        }
        @Data
        static class StudentRecord {
            Long id;
            Long userId;
            Long courseId;
            Integer score;
        }

结果就是

    [StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=11, courseId=101, score=100), StudentRecord(id=null, userId=12, courseId=100, score=100)]

因为对象都不一样，所以就没法去重了，这里就需要用

    public static <T> Predicate<T> distinctByKey(
                Function<? super T, ?> keyExtractor) {

            Map<Object, Boolean> seen = new ConcurrentHashMap<>();
            return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
        }

然后就可以用它来去重了

    System.out.println(list.stream().filter(distinctByKey(StudentRecord::getUserId)).collect(Collectors.toList()));

看下结果

    [StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=12, courseId=100, score=100)]

但是说实在的这个功能感觉应该是 stream 默认给实现的

### 使用 java.util.stream.Collectors#groupingBy 对 list 进行分组

这个使用场景还是蛮多的，上面的场景里比如我要对 userId 进行分组，就一行代码就解决了

    System.out.println(list.stream().collect(Collectors.groupingBy(StudentRecord::getUserId)));

#### 结果

    {11=[StudentRecord(id=null, userId=11, courseId=100, score=100), StudentRecord(id=null, userId=11, courseId=101, score=100)], 12=[StudentRecord(id=null, userId=12, courseId=100, score=100)]}

很方便的变成了以 `userId` 作为 `key`，以相同 `userId` 的 `StudentRecord` 的 `List` 作为 `value` 的 `map` 结构