您的位置:

Java Stream去重详解

Stream是Java 8引入的一款新特性,它支持函数式编程,可以使用Lambda表达式来对集合进行操作,使代码更简洁、优雅。而去重是Stream中常见的操作之一,那么Stream如何去重呢?本文将从多个方面对Stream去重做详细的阐述。

一、Stream去重字段

如果我们要对一个对象的某个字段进行去重,可以使用Stream的distinct()方法来实现。例如我们有一个Person对象,包含id和name两个属性,我们要根据name来去重:


List<Person> list = getList();
list.stream().map(Person::getName).distinct().forEach(System.out::println);

在上述代码中,我们首先将List转换为Stream,然后使用map方法获取每个Person对象的name属性,使用distinct()方法来去重,最后使用forEach打印每个不同的name。

二、Stream去重list元素方法

如果我们需要对一个List对象的元素进行去重,可以使用Stream的distinct()方法结合Collector的toCollection()方法来实现。例如我们有一个List<Integer>对象,要对其中的元素进行去重:


List<Integer> list = Arrays.asList(1, 2, 3, 1, 2, 4);
List<Integer> distinctList = list.stream().distinct().collect(Collectors.toCollection(ArrayList::new));
System.out.println(distinctList);

在上述代码中,我们首先将List转换为Stream,然后使用distinct()方法来去重,最后使用Collector的toCollection()方法将结果转换为ArrayList。

三、Stream去重源码

如果我们需要查看Stream去重的源码,可以查看Java API文档,或者在IDE中进入Stream的distinct()方法进行查看。以下是官方API对distinct()方法的定义:


default Stream<T> distinct() {
    return this.<T, T, HashSet<T>>collect(Collectors.toSet()).stream();
}

可以看到,stream的distinct()方法实际上是调用了Collectors.toSet()方法来生成一个HashSet对象,然后再将HashSet转换为Stream对象。

四、Stream去重的四种方法

除了使用distinct()方法来进行去重外,我们还有其他几种方法可以实现Stream的去重:

1.使用HashSet去重

我们可以使用HashSet对象来进行Stream的去重,其实现逻辑与distinct()方法类似:


List<Person> list = getList();
List<Person> distinctList = new ArrayList<>(new HashSet<>(list));
System.out.println(distinctList);

2.使用TreeSet去重

我们还可以使用TreeSet对象来进行Stream的去重,其可以根据元素的自然排序进行去重:


List<Integer> list = Arrays.asList(1, 2, 3, 1, 2, 4);
List<Integer> distinctList = new ArrayList<>(new TreeSet<>(list));
System.out.println(distinctList);

3.使用HashMap去重

我们可以使用HashMap来进行Stream的去重,其利用Object的hashCode()和equals()方法来判断元素是否重复:


List<String> list = Arrays.asList("apple", "banana", "orange", "banana", "pear");
List<String> distinctList = new ArrayList<>(new HashMap<>().values());
System.out.println(distinctList);

4.使用Stream.collect(Collectors.groupingBy())方法去重

我们还可以使用groupingBy()方法来进行Stream的去重,其利用Map的键的唯一性来去重:


List<String> list = Arrays.asList("apple", "banana", "orange", "banana", "pear");
List<String> distinctList = list.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                .entrySet().stream().filter(entry -> entry.getValue() == 1L).map(Map.Entry::getKey)
                .collect(Collectors.toList());
System.out.println(distinctList);

五、Stream去重的字段获取

在使用Stream进行去重时,我们需要注意获取去重字段。如果是List对象,则可以直接获取每个对象,如果是Map对象,则需要获取Map中的value,并转换为List对象;如果是对象集合,则需要获取对象属性,例如:


List<Person> list = getList();
List<String> nameList = list.stream().map(Person::getName).distinct().collect(Collectors.toList());

在上述代码中,我们首先将List转换为Stream,然后使用map方法获取每个Person对象的name属性,使用distinct()方法来去重,最后使用Collectors.toList()方法将去重结果转换为List对象。

六、Stream去重保留最后一条

有时候我们需要对重复元素进行去重,但是保留最后一条元素,可以使用Stream的collect()方法来实现:


List<Person> list = getList();
List<Person> distinctList = list.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName).reversed())),
                ArrayList::new));
System.out.println(distinctList);

在上述代码中,我们使用Comparator.comparing()方法来根据name属性逆序排序,然后使用collectingAndThen()方法来将去重结果转换为ArrayList。

七、Stream去重后分组排序

如果我们需要对去重后的元素进行分组排序,可以先进行去重,然后再使用Stream的sorted()方法来实现分组排序:


List<Person> list = getList();
List<Person> distinctList = list.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName).reversed())),
                ArrayList::new));
Map<String, List<Person>> groupMap = distinctList.stream().sorted((p1, p2) -> p2.getAge() - p1.getAge())
                .collect(Collectors.groupingBy(Person::getName));
System.out.println(groupMap);

在上述代码中,我们首先使用collectingAndThen()方法将去重结果转换为ArrayList,然后使用sorted()方法按照age属性对去重后的元素进行逆序排序,最后使用groupingBy()方法进行分组。

八、Stream去重复后limit返回

如果我们只需要去重后的前几个元素,可以使用limit()方法来限制返回数量:


List<Person> list = getList();
List<Person> distinctList = list.stream().distinct().limit(3).collect(Collectors.toList());
System.out.println(distinctList);

在上述代码中,我们使用limit()方法限制去重后的元素数为3,并使用toList()方法将结果转换为List对象。

九、Stream去重根据多个条件

如果我们是需要根据多个属性进行去重,可以使用distinct()方法结合Comparator来实现。例如我们有一个Person对象,包含id、name和age三个属性,我们要根据name和age来去重:


List<Person> list = getList();
List<Person> distinctList = list.stream().distinct().sorted(
                Comparator.comparing(Person::getName).thenComparingInt(Person::getAge))
                .collect(Collectors.toList());
System.out.println(distinctList);

在上述代码中,我们首先使用distinct()方法去重,然后使用sorted()方法按照name和age属性进行排序,最后使用Collectors.toList()方法将结果转换为List对象。

结语

通过本文的介绍,我们已经掌握了Stream的去重操作,包括使用distinct()方法、HashSet、TreeSet、HashMap、groupingBy()方法、collect()方法等多种方式,同时还介绍了多属性排序、限制返回数量等高级用法。希望本文能帮助大家更好地使用Stream进行开发。