Play with Java 8 Stream series one map, filter, collect, Collectors.toList, Collectors.groupingBy, sorted

cutting edge

When I wrote this article, the latest version of jdk is already jdk 18, and the version of jdk is really fast. When most Internet companies are still in jdk8, the official version has already reached 18, but the update of jdk8 is considered a relatively large version Falling down, a lot of convenient APIs have come out, such as the Steam series of operations we are going to talk about in this article, which makes it more convenient for users to operate on collections in terms of logic and writing, and at the same time reduces the occurrence of bugs

text

prepare data

Create a class: Member (member)

Member

@Data
public class Member {
   /**
     * ID
     */
    private Integer id;
    /**
     * 名称
     */
    private String memberName;
    /**
     * 性别
     */
    private String sex;
    /**
     * 积蓄
     */
    private BigDecimal totalMoney;
    /**
     * 属于哪个家庭
     */
    private Integer familyId;
    
}

Analysis: @Data helps us generate get, set and other methods to make the code look more concise

Initialization data

public static void main(String[] args) {
        Random random = new Random(10);

        List<Member> memberList = new ArrayList<>();
        for (int i = 0; i < 10;) {
            Member member = new Member();
            member.setId(++i);
            member.setMemberName("小花" + i);
            member.setMemberAmount(random.nextInt(50));
            member.setTotalMoney(new BigDecimal(random.nextInt(40) + 10));
            member.setSex(member.getId() % 2 == 0 ? "男" : "女");
            member.setFamilyId(random.nextInt(5) + 1);
            memberList.add(member);
        }
        System.out.println(JSONObject.toJSONString(memberList));
    }

memberList data is like

[{
    "familyId": 4,
    "id": 1,
    "memberAmount": 13,
    "memberName": "小花1",
    "sex": "女",
    "totalMoney": 30
}, {
    "familyId": 2,
    "id": 2,
    "memberAmount": 40,
    "memberName": "小花2",
    "sex": "男",
    "totalMoney": 16
}, {
    "familyId": 2,
    "id": 3,
    "memberAmount": 47,
    "memberName": "小花3",
    "sex": "女",
    "totalMoney": 18
}, {
    "familyId": 5,
    "id": 4,
    "memberAmount": 14,
    "memberName": "小花4",
    "sex": "男",
    "totalMoney": 13
}, {
    "familyId": 1,
    "id": 5,
    "memberAmount": 41,
    "memberName": "小花5",
    "sex": "女",
    "totalMoney": 18
}, {
    "familyId": 4,
    "id": 6,
    "memberAmount": 30,
    "memberName": "小花6",
    "sex": "男",
    "totalMoney": 16
}, {
    "familyId": 4,
    "id": 7,
    "memberAmount": 23,
    "memberName": "小花7",
    "sex": "女",
    "totalMoney": 48
}, {
    "familyId": 4,
    "id": 8,
    "memberAmount": 9,
    "memberName": "小花8",
    "sex": "男",
    "totalMoney": 45
}, {
    "familyId": 5,
    "id": 9,
    "memberAmount": 35,
    "memberName": "小花9",
    "sex": "女",
    "totalMoney": 39
}, {
    "familyId": 1,
    "id": 10,
    "memberAmount": 20,
    "memberName": "小花10",
    "sex": "男",
    "totalMoney": 38
}]

start

How to create a Steam?

If it is a list or setj collection like our memberList above, then use the member.stream() method directly, then the returned is a Stream, if it is an object, then you can use the Steam.of(Object ...values) method to generate a steam object. Some people may ask, what is the use of generating a steam? The answer is that it must be useful, because the latter methods are all based on steam operations.

forEach operation

Similar to traversal writing

for (Member member : memberList){
    //Operate the Member object
}

But passing forEach will make the code more concise, as shown below

memberList.forEach(k->{

//operate k

});

 2 differences:

1. The traditional writing method can use break to exit, but the stream cannot exit

2. The traditional writing method skips the current execution logic through continue and executes the next cycle, and the stream skips the current logic through return

3. In terms of efficiency, if the amount of data is small, the first type will be higher

map operation

Get the required field value, for example, there is a logic that needs to filter out the name field in the memberList collection

The first way of writing:

List<String> memberNameList = new ArrayList<>();
for (Member member : memberList){
    //Operate the Member object
    memberNameList.add(member.getMemberName());
}

second way of writing

List<String> memberNameList = memberList.stream().map(Member::getMemberName).collect(Collectors.toList());

If you still can’t see the convenience of using stream here, then look down

We want to filter out the names of members whose savings (memberAmount) is greater than 25

first way of writing

 List<String> memberNameList = new ArrayList<>();
for (Member member : memberList){
    //Operate the Member object
    if (member.getMemberAmount() > 20) {
        memberNameList.add(member.getMemberName());
    }
}

second way of writing

List<String> memberNameList = memberList.stream().filter(k->k.getMemberAmount() > 25).map(Member::getMemberName).collect(Collectors.toList());

It's still one line of code

filter operation

 The filtering operation is to filter out the data that does not meet our conditions, and the remaining data that meets our conditions has been used in the above,

We want to filter the data whose member savings are greater than 25, that is, filter out the data whose member savings are less than or equal to 20, and k represents the objects in the collection

List<String> memberNameList = memberList.stream().filter(k->k.getMemberAmount() > 25).map(Member::getMemberName).collect(Collectors.toList());

 collect operation

The name is just like its function, which means collection. Collect the previous operation data, which has been used in the above example, filter out the continuous data greater than 25, and then obtain the required fields through the map, such as the memberName above

The Collectors object is used in the brackets to further clarify the way the data is output, such as List collection, Set collection, Map collection, etc. The above is returned in the form of List collection.

distinct operation

To remove duplicates, we need to filter out the value of the memberName field, and there must be no duplicates

in a way

List<String> memberNameList = new ArrayList<>();
for (Member member : memberList){
    //Operate the Member object
    if (!memberNameList.contains(member.getMemberName())) {
        memberNameList.add(member.getMemberName());
    }
}

second way of writing

memberNameList = memberList.stream().map(Member::getMemberName).distinct().collect(Collectors.toList());

Use the distinct method to deduplicate the results

group by operation

Just like the group by of the sql statement, group by a certain field and group by familyId

first way of writing

Map<Integer, List<Member>> familyMap = new HashMap();
for (Member member : memberList) {
    //Operate the Member object
    List<Member> members = familyMap.get(member.getFamilyId());
    if (CollectionUtils.isEmpty(members)) {
        members = new ArrayList<>();
    }
    members.add(member);
    familyMap.put(member.getFamilyId(), members);
}

second way of writing

familyMap =  memberList.stream().collect(Collectors.groupingBy(Member::getFamilyId));

This time, I can feel the convenience of stream. The more complex the logic, the more convenience of steam can be reflected.

sorted

The first method is written with the help of the Collections tool class. For example, first sort the memberAmount from large to small, and if they are the same, sort according to familyId from small to large

Collections.sort(memberList, new Comparator<Member>() {
    @Override
    public int compare(Member o1, Member o2) {
        if (o2.getMemberAmount() - o1.getMemberAmount() == 0){
            return o1.getFamilyId() - o2.getFamilyId();
        }
        return o2.getMemberAmount() - o1.getMemberAmount();
    }
});

second way of writing 

memberList = memberList.stream().sorted(Comparator.comparingInt(Member::getMemberAmount).reversed().thenComparingInt(Member::getFamilyId)).collect(Collectors.toList());

reversed() is in reverse order

The basic operations on collections are almost the same. In the next article, we will introduce some advanced usages, such as accumulation, operations on List collections after grouping, etc.

Guess you like

Origin blog.csdn.net/zanpengfei/article/details/125042795