Java8的流特性

本文详细介绍了Java8的流特性,包括filter、distinct、collect和map等操作,并通过实例展示了如何在Person对象上应用这些操作,如属性映射、去重、过滤等。强调了在使用流操作时,需要重写equals()和hashCode()方法以确保正确性。最后,讨论了distinct方法的底层实现,涉及到HashSet和HashMap的原理。

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

今天和大家聊聊Java8的流特性。
1、java8的流能做什么?
(1)filter:从集合中筛选出符合条件的数据。
(2)distinct:对集合中重复的元素去重。
(3)collect:对集合进行的一系列关系映射。
(4)map:获取集合中某类数据的集合
使用过Java8流特性的伙伴们都知道,它在很大程度上简化了我们的代码。
那么,上面提到的作用,具体怎么实现呢?
2、具体使用方式:
2.1. 创建一个类Person,如下:

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Objects;

/**
 * @Author: Max
 * @Date: 2021/8/3
 * @Function: 实体类-人
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    // 编号
    private String code;
    // 姓名
    private String name;
    // 生日
    private Date birthday;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(code, person.code) &&
                Objects.equals(name, person.name) &&
                Objects.equals(birthday, person.birthday);
    }

    @Override
    public int hashCode() {
        return Objects.hash(code, name, birthday);
    }
}

2.2. 具体使用方式:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.Date;

/**
 * @Author: Max
 * @Date: 2021/8/3
 * @Function: 流特性使用测试
 */
public class Test {

    /**
     *@author: Max
     *@time: 2021/8/3
     *@description: 测试主方法
     *@param: [args]
     *@return: void
     */
    public static void main(String[] args) {
        // 测试流特性
        testStream();
    }

    /**
     *@author: Max
     *@time: 2021/8/3
     *@description: 测试流特性
     *@param: []
     *@return: void
     */
    private static void testStream() {
        // 造点数据
        List<Person> personList = getPersons();
        // Person对象中的属性间映射  id -> name
        Map<String, String> idToNameMap = personList.stream().collect(Collectors.toMap(Person::getCode, Person::getName));
        System.out.println(idToNameMap);
        // Person对象中的某个属性映射对象  id -> Person
        Map<String, Person> idToPersonMap = personList.stream().collect(Collectors.toMap(Person::getCode, p -> p, (k1, k2) -> k1));
        System.out.println(idToPersonMap);
        // 获取Person对象中某个属性的集合
        List<String> nameList = personList.stream().map(Person::getName).collect(Collectors.toList());
        System.out.println(nameList);
        // 过滤掉name属性的值不为A2的数据、筛选出name属性的值为A2的数据
        List<Person> filterNameList = personList.stream().filter(x -> "A2".equals(x.getName())).collect(Collectors.toList());
        System.out.println(filterNameList);
        // Person对象中的属性映射对象的集合  id -> List<Person>
        Map<String, List<Person>> idToListMap = personList.stream().collect(Collectors.groupingBy(Person::getCode));
        System.out.println(idToListMap);
        // Person对象中的多个属性映射对象的集合  id + name  ->   List<Person>
        Map<String, List<Person>> strToListMap = personList.stream().collect(Collectors.groupingBy(p -> p.getCode() + "#" + p.getName()));
        for (Map.Entry<String, List<Person>> stringListEntry : strToListMap.entrySet()) {
            if (stringListEntry.getValue().size() >= 2) {
                //截取"#"之前的字符串
                String beforeStr = stringListEntry.getKey().substring(0, stringListEntry.getKey().indexOf("#"));
                System.out.println(beforeStr);
                //截取"#"之后的字符串
                String afterStr = stringListEntry.getKey().substring(beforeStr.length() + 1);
                System.out.println(afterStr);
            }
        }
        System.out.println(strToListMap);
        // Person对象中的多个属性映射对象  id+name -> Person
        //eg1:
        Map idAndNameToPersonMap1 = personList.stream().collect(Collectors.toMap(p -> p.getCode() + p.getName(), Function.identity()));
        System.out.println(idAndNameToPersonMap1);
        //eg1:
        Map idAndNameToPersonMap2 = personList.stream().collect(Collectors.toMap(p -> p.getCode() + p.getName(), ClassName -> ClassName));
        System.out.println(idAndNameToPersonMap2);
        List<Person> listSortedByBirthday = personList.stream().sorted(Comparator.comparing(Person::getBirthday)).collect(Collectors.toList());
    }

    /**
     *@author: Max
     *@time: 2021/8/3
     *@description: 造数
     *@param: []
     *@return: java.util.List<com.ymt.foundcore.base.domain.dto.Person>
     */
    private static List<Person> getPersons() {
        List<Person> personList = new ArrayList<>();
        Person person1 = Person.builder()
                .code("1")
                .name("A1")
                .birthday(new Date());
                .build();
        personList.add(person1);
        Person person2 = Person.builder()
                .code("2")
                .name("A2")
                .birthday(new Date());
                .build();
        personList.add(person2);
        Person person3 = Person.builder()
                .code("3")
                .name("A3")
                .birthday(new Date());
                .build();
        personList.add(person3);
        Person person4 = Person.builder()
                .code("4")
                .name("A4")
                .birthday(new Date());
                .build();
        personList.add(person4);
        return personList;
    }
}

运行结果如下:

{1=A1, 2=A2, 3=A3, 4=A4}
{1=Person(code=1, name=A1), 2=Person(code=2, name=A2), 3=Person(code=3, name=A3), 4=Person(code=4, name=A4)}
[A1, A2, A3, A4]
[Person(code=2, name=A2)]
{1=[Person(code=1, name=A1)], 2=[Person(code=2, name=A2)], 3=[Person(code=3, name=A3)], 4=[Person(code=4, name=A4)]}
{1#A1=[Person(code=1, name=A1)], 3#A3=[Person(code=3, name=A3)], 2#A2=[Person(code=2, name=A2)], 4#A4=[Person(code=4, name=A4)]}

我们可以看到,流操作的对象是集合。使用流时注意重写equals()和hashCode()方法。使用stream流的distinct()方法去重时,如果没有重写这两个方法,会调用Object类的equals()和hashCode()方法。
注意:例子”Person对象中的多个属性映射对象 id+name -> Person“ 由于是后面添加的笔记,所以没有输出结果。
有些博客说:
stream流的distinct去重的底层使用的hashSet去重,而hashSet实际上是HashMap,所以distinct去重实际上是用了HashMap的key去重的方法,因为hashMap在put元素的时候的代码是先使用hashCode(key)方法得到这个key的hashCode值,然后通过indexFor()方法对hashCode值和table.length数组长度做与运算进而确定要添加的元素放在哪个桶中,然后for循环拿到桶的hashCode值(for循环是因为桶下可能有长度为8的链表,1.8之后还可能有红黑树)来判断这个元素的hashCode值是否和已经存在的桶中元素的hashCode值相等,如果hashCode值相等的话,再去使用equals()方法判断这个值是否和已经存在的桶中的值相等,如果想等,那么原来的key对应的value就会被新的key对应的value代替掉,所以Stream.distinct()去重也要去重写实体类的hashCOde()和distinct()方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

徐先生Paul

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

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

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

打赏作者

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

抵扣说明:

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

余额充值