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.