Java8 Streams流
自从java8 引入了streams的方略,我就爱不释手,总结下以前开发中用到的情况。
前提把备用java类准备好:
性别用枚举表示
public enum Gender {
MALE("男"), FEMALE("女"), UNKNOWN("未知");
private final String gender;
private Gender(String gender) {
this.gender = gender;
}
public String getGender() {
return gender;
}
}
用户类:
/**
* @author dgm
* @describe "用户类"
* @date 2020年11月28日
*/
public class User implements java.io.Serializable {
private static final long serialVersionUID = 1L;
/**
* 编号(唯一标识)
*/
protected Long id;
/**
* 登录名
*/
private String username;
/**
* 昵称
*/
private String nickname;
/**
* 密码
*/
private String password;
/**
* 手机号码
*/
private String phone;
/**
* 邮箱地址
*/
private String email;
/**
* 所属身份
*/
private String province;
/**
* 年龄
*/
private int age;
/**
* 性别
*/
private Gender gender;
/**
* 头像
*/
private String icon;
/**
* 账户是否锁定
*/
private Boolean locked;
public User(Long id, String username, String nickname, String password,
String phone, String email, String province, int age, Gender gender/*, String icon,
Boolean locked*/) {
super();
this.id = id;
this.username = username;
this.nickname = nickname;
this.password = password;
this.phone = phone;
this.email = email;
this.province = province;
this.age = age;
this.gender = gender;
//this.icon = icon;
//this.locked = locked;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", nickname="
+ nickname + ", password=" + password + ", phone=" + phone
+ ", email=" + email + ", province=" + province
+ ", gender=" + gender.getGender() + ", age=" + age+ "]";
}
}
//用户订单
public class Order implements java.io.Serializable, Comparable<Order> {
/**
*
*/
private static final long serialVersionUID = 1L;
private Long orderId;//订单id号
private String username;//顾客名(方便演示,对应user里username)
private int amount;//此订单消费总额
public Order(Long orderId, String username, int amount) {
this.orderId = orderId;
this.username = username;
this.amount = amount;
}
。。。。。。略
}
数据构造,组装成数据集合(特别注意实际上是从数据库检索出来的,如下:select * from user,映射成User数据列表),出于演示,就人为构造数据
public class StreamTest {
public static void main(String args[]) {
//手工构造数据
User dgm = new User(1L,"dgm","董广明","123456","15850669069","1056764180@qq.com","河南", 32,Gender.MALE);
//System.out.println(dgm);
User wangwu = new User(2L,"wangwu","王五","12345678","13850669069","21056764180@qq.com","河南",22,Gender.MALE);
User maliu = new User(3L,"maliu","马六","123456","14850669069","3056764180@qq.com","河南", 18,Gender.UNKNOWN);
User zhangsan = new User(4L,"zhangsan","张三","123456000","16850669069","4056764180@qq.com","江苏",24,Gender.MALE);
User masi = new User(5L,"nasi","马四","123456789","17850669069","5056764180@qq.com","江苏",31,Gender.FEMALE);
User gaoba = new User(6L,"gaoba","高八","654321","18850669069","6056764180@qq.com","安徽",40,Gender.MALE);
User dongguangming = new User(7L,"dongguangming","董","65432111","19850669069","9056764180@qq.com","河南",31,Gender.MALE);
//组装成数据集合(特别注意实际上是从数据库检索出来的,如下:select * from user,映射成User数据列表)
List<User> userList = Arrays.asList(dgm,wangwu,zhangsan,maliu,masi,gaoba,dongguangming);
for(User user: userList) {
System.out.println(user);
}
}
}
打印输出:
下面就列举几种情况:
1. 按条件返回数据给前端,转list
1.1 早期实现,基于for循环
在没有java8之前,我们是循环列表加判断条件,然后组装数据,比如
//过滤出id大于5的数据集合
//(注意也可以通过定制sql:select * from user where id>5)
//实际根据情况在sql还是通过java处理组装
List<User> idUserList = new ArrayList<>();
for(User user: userList) {
if(user.getId()>5) {
idUserList.add(user);
}
}
for(User user: idUserList) {
System.out.println("只要用户id大于5的用户:" +user);
}
注意也可以通过定制sql:select * from user where id>5,实际根据情况在sql中还是通过java处理组装数据集合,回到了现状(数据处理计划在数据库端还是java端还是前端处理的问题)
此时打印输出
1.2 java8实现,基于streams
//转换流成list
List<User> filterList = userList.stream()
.filter((user) -> user.getId()>5)
.collect(Collectors.toList());
System.out.println("java8 之后");
filterList.forEach((user) ->
{
System.out.println("只要用户id大于5的用户:" +user);
});
打印输出
2. Stream转Map
比如只要是河南的用户(注意filter过滤条件依实际情况而写)
//stream流转map
Map<Long,User> idFilteredMap = userList
.stream()
.filter((user) -> user.getProvince().equalsIgnoreCase("河南"))
.collect(Collectors.toMap(User::getId, user->user));
System.out.println("用户id和用户: "+idFilteredMap);
idFilteredMap.values().forEach(user ->
{
System.out.println("只要省份是河南的用户:" +user);
});
打印输出
有时候我们只需要用户名列表
//只获得用户名
List<String> userNamesByLambda = userList
.stream()
.map(user -> user.getUsername())
.collect(Collectors.toList());
System.out.println("只要用户名(map通过Lambda expression): "+userNamesByLambda);
List<String> userNamesByMethod = userList
.stream()
.map(User::getUsername)
.collect(Collectors.toList());
System.out.println("只要用户名(map通过method refrence): "+userNamesByMethod);
输出结果:
3. Stream转set
比如只要是31岁的用户(注意filter过滤条件依实际情况而写)
//Converting Stream to Set
Set<User> filterSet = userList
.stream()
.filter((user) -> user.getAge()==31)
.collect(Collectors.toSet());
filterSet.forEach(user ->
{
System.out.println("只要年龄是31的用户:" +user);
});
打印输出
4. Stream转数组
有的时候,我们需要把流转换成数组
//Converting Stream to Array
User[] filteredArray = userList
.stream()
.filter((user) -> user.getGender()==Gender.FEMALE)
.toArray(User[] :: new);
//.collect(Collectors.toSet());
for(User user: filteredArray) {
System.out.println("只要性别是女的用户:" +user);
}
执行结果
5. 统计函数
根据filter做统计计数
5.1 计算总数量
//统计
long count = userList
.stream()
.filter(user -> user.getUsername().startsWith("d"))
.count();
System.out.println("用户名以d开头的用户数量是: "+count);
打印输出
5.2 计算最大最小值
//统计id最大最小
Optional<User> maxIdUser = userList
.stream()
.max(Comparator.comparing(User::getId));
System.out.println("ID最大的用户是: "+maxIdUser);
Optional<User> minIdUser = userList
.stream()
.min(Comparator.comparing(User::getId));
System.out.println("ID最小的用户是: "+minIdUser);
输出结果:
5.3 分组
按条件分组,类似于sql里group by
// Grouping people by 省份
Map<String, List<User>> userByProvince = userList.stream()
.collect(Collectors.groupingBy(
User::getProvince,
Collectors.toList()));
System.out.println("按省份分组用户: "+userByProvince);
输出结果更多详情(虽然不一定都用到)参看oracle java官方文档 https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
附图:
还记得数据库sql的语法吗
[ [SELECT] WITH vname AS (select_statement) [,vname AS...] ]
SELECT [TOP row_count] [ALL | DISTINCT] {* | select_list}
FROM { { {table | view [{TABLESAMPLE [method] (percentage) [REPEATABLE (arg)]}] }
| joined_table
| derived_table
| literal }
[correlation] }
, ...
[WHERE search_condition]
[GROUP BY { column_name | column_number | GROUPING SETS (column_list), ... } ]
[HAVING search_condition]
[ORDER BY { {column_name | column_number}
[ASC | DESC]
[NULLS {FIRST | LAST | MAX | MIN}], ... }]
[{AT {NOW | FULL_HISTORY | at_mode }]
[FETCH FIRST row_count ROWS ONLY | LIMIT row_count ]
相当于把数据库sql里的where、distinct、order by 、 group by、max()、avg()等放到java层处理,数据库只负责捞数据。
总结:数据组装过程,看实际情况需要,酌情考虑(实在不行把数据库人员、java码农、前端开发者主要是JavaScript,聚到议事堂公开讨论下)在哪层(数据库层、java中间层还是前端js)处理。
参考文献:
-
Java 8 Central https://www.oracle.com/java/technologies/java8.html
-
Java 8 Stream https://www.runoob.com/java/java8-streams.html
-
Java 8 特性 – 终极手册 http://ifeve.com/java-8-features-tutorial/
-
Java 8 中的 Streams API 详解
https://developer.ibm.com/zh/articles/j-lo-java8streamapi/
-
Java 8 数据流教程 http://blog.didispace.com/books/java8-tutorial/ch2.html
-
java-8-streamcollect-example https://www.java67.com/2018/06/java-8-streamcollect-example.html?m=1#.X2gbYwe9xIs.twitter
-
JAVA8十大新特性详解(精编)https://www.jianshu.com/p/0bf8fe0f153b
8. Java 8 正式发布,新特性全搜罗 https://www.iteye.com/news/28870-java-8-release
9. 专题:Java8 新特性探究_51CTO.COM https://developer.51cto.com/art/201404/435591.htm
10. Java™ Platform, Standard Edition 8
API Specification https://docs.oracle.com/javase/8/docs/api/
11. Java Stream API https://soshace.com/java-stream-api/
12.
Converting stream to collections and Arrays https://javagoal.com/java-stream-collect/
13
Collect Data to Map http://www.java2s.com/Tutorials/Java_Streams/Tutorial/Streams/Collect_Data_to_Map.htm
14
10 Examples of Stream API in Java 8 - count + filter + map + distinct + collect
https://www.java67.com/2014/04/java-8-stream-examples-and-tutorial.html#ixzz6f1PBYO48
15
Stream in Java 8 https://javagoal.com/java-8-stream/
16 .
17.
Practical Guide to Java Stream API https://praveergupta.in/practical-guide-to-java-stream-api-7aadc02908f7
18
Java 8 中的 Streams API 详解
https://developer.ibm.com/zh/languages/java/articles/j-lo-java8streamapi/
19
Functional Programming in Java: Stream API
https://www.cognizantsoftvision.com/blog/functional-programming-in-java-stream-api/
20
A Complete Tutorial on Java Streams https://pdf.co/blog/java-streams
21.
Java 8 Stream API https://howtodoinjava.com/java8/java-streams-by-examples/
22
A In-Depth guide to Java 8 Stream API https://java2blog.com/java-8-stream/
23.
Functional Programming With Java: Streams https://belief-driven-design.com/functional-programming-with-java-streams-190eda591a5/
24.
A Guide to Java Streams in Java 8: In-Depth Tutorial With Examples
https://stackify.com/streams-guide-java-8/
25
4 Examples of Stream.collect() method in Java 8
https://www.java67.com/2018/06/java-8-streamcollect-example.html#ixzz6f1lmX200
26 A Beginner’s Guide to Complete Analysis of Apache Spark RDD and Java 8 Streams https://www.msystechnologies.com/blog/a-beginners-guide-to-complete-analysis-of-apache-spark-rdds-and-java-8-streams/
27
6 Most Useful Java 8 Stream Functions with Real-time Examples https://www.javachinna.com/2020/08/21/java-8-stream-functions-with-examples/?utm_source=rss&utm_medium=rss&utm_campaign=java-8-stream-functions-with-examples
28