前言
我们在开发中会大量的用到集合,少不了对集合进行一些操作,如何优雅的遍历集合,操作集合,不仅能体现出代码的质量,更能体现出程序员本身对自我的要求。
文章目录
- 前言
- 一、Stream初体验
- 二、Stream流的使用
- 2.1 获取流水线
- 2.2 Stream流的中间方法
- 2.3 Stream流的终结方法
一、Stream初体验
例如我们此时有这样的一个需求:把所有已“邓”字开头的元素,并且长度超过3的打印出来。
- 常规方法实现
public class StreamDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list,"鹿晗","邓紫棋","吴青峰","邓超","许嵩");
// 1.把所有以“邓”为开头的元素存储到新集合中
List<String> list1 = new ArrayList<>();
for (String name : list) {
if (name.startsWith("邓")){
list1.add(name);
}
}
// 2.把邓开头的,长度为3的元素再存储到新集合中
List<String> list2 = new ArrayList<>();
for (String name : list1) {
if (name.length() == 3){
list2.add(name);
}
}
// 3.遍历打印最终结果
for (String s : list2) {
System.out.println(s);
}
}
}
- 使用Stream流实现
public class StreamDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list,"鹿晗","邓紫棋","吴青峰","邓超","许嵩");
list.stream().filter(name->name.startsWith("邓")).filter(name->name.length()==3).forEach(name-> System.out.println(name));
}
}
经过对比,是不是眼前一亮,原本那么多行的代码,一下被删减了好多!其实我在刚参加工作的时候,就真的惊了,也确实感受到了和别人差距。我就是第一种方法实现的,而看到别人写的代码甚至都不理解!
那么接下来,我们就好好学习一下吧~
二、Stream流的使用
- 先得到一条Stream流(流水线),并把数据放上去
- 使用中间方法对流水线上的数据进行操作
- 使用终结方法对流水线上的数据进行操作
2.1 获取流水线
数据类型 | 方法 | 说明 |
---|---|---|
单列集合 | default Streamstream() | Collection中的默认方法 |
双列集合 | 无 | 无法直接使用Stream流 |
数组 | public staticStreamstream(T[]array) | Arrays工具类中的静态方法 |
一堆零散数据 | public staticStreamof(T…values) | Stream接口中的静态方法 |
// 1.单列集合获取Stream流
List<String> list = new ArrayList<>();
Collections.addAll(list,"张三","李四","王五","张三丰");
// 获取一条流水线,并把集合中的数据放到流水线上
Stream<String> stream = list.stream();
// 2.双列集合获取Stream流
Map<String,Integer> hm = new HashMap<>();
// 2.1 添加数据
hm.put("aaa",111);
hm.put("bbb",222);
hm.put("ccc",333);
// 2.2 获取stream流——键
Stream<String> stream = hm.keySet().stream();
// 2.3 第二种获取stream流——键值对
Stream<Map.Entry<String, Integer>> stream1 = hm.entrySet().stream();
// 3.数组获取Stream流
int[] arr = {1,2,3,4,5,6};
String[] arr2 = {"a","b","c"};
// 3.1获取stream流
IntStream stream = Arrays.stream(arr);
Stream<String> stream1 = Arrays.stream(arr2);
// 4.一堆零散数据获取Stream流
// 注意:方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组,但是数组必须是引用数据类型。如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream中。
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
2.2 Stream流的中间方法
- filter:过滤
- limit:获取前几个元素
- skip:跳过前几个元素
- distinct:元素重复,依赖(hashcode和equals方法)
- concat:合并a和b两个流为一个流
- map:转换流中的数据类型
注意:
1.中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程。
2.修改Stream流中的数据,不会影响原来集合或者数组中的数据。
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
List<String> list2 = new ArrayList<>();
Collections.addAll(list2,"张无忌","周芷若","赵敏");
// 过滤
list1.stream().filter(s -> s.startsWith("张")).forEach(s-> System.out.println(s));
// 获取前几个
list1.stream().limit(3).forEach(s-> System.out.println(s));
// 跳过
list1.stream().skip(4).forEach(s-> System.out.println(s));
// 去重
list1.stream().distinct().forEach(s -> System.out.println(s));
// 合并
Stream.concat(list1.stream(),list2.stream()).forEach(s -> System.out.println(s));
}
}
map:转换流中的数据类型
List<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-15","周芷若-20","赵敏-14","宋青书-19","张三丰-90","独孤求败-101");
/**
* map 转换流中的数据类型
* String->int
* apply的形参s:依次表示流里面的每一个数据
* 返回值:表示转换之后的数据
*/
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
String[] split = s.split("-");
int age = Integer.parseInt(split[1]);
return age;
}
}).forEach(s-> System.out.println(s));
// lambda表达式书写
list.stream().map(s ->
Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.println(s));
2.3 Stream流的终结方法
- forEach:遍历
- count:统计
- toArray:收集流中的数据,放到数组中
- collect:收集流中的数据,放到集合中(List、Set、Map)
我们先创建一个User类,方便我们后续的操作
public class User implements Serializable {
private String name;
private Integer age;
private String sex;
public User() {
}
public User(String name, Integer age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
List<User> userList = new ArrayList<>();
Collections.addAll(userList,new User("张无忌",15,"男"),
new User("张无忌",15,"男"),
new User("张三丰",90,"男"),
new User("赵敏",16,"女"),
new User("周芷若",20,"女"));
// forEach:遍历
userList.stream().forEach(new Consumer<User>() {
@Override
public void accept(User user) {
System.out.println(user.toString());
}
});
userList.stream().forEach(user -> System.out.println(user.toString()));
// count:统计
long count = userList.stream().count();
收集流中的数据,放到数组中
/**
* IntFunction的泛型:具体类型的数组
* apply的形参:流中数据的个数,要跟数组的长度保持一致
* apply的返回值:具体类型的数组
* 方法体:就是创建数组
*/
User[] userArray = userList.stream().toArray(new IntFunction<User[]>() {
@Override
public User[] apply(int value) {
return new User[value];
}
});
// lambda表达式简化上述代码
User[] userArray = userList.stream().toArray(value -> new User[value]);
System.out.println(Arrays.toString(userArray));
toArray方法的参数作用:负责创建一个指定类型的数组。底层:会依次得到流里面的每一个数据,并把数据放到数当中。返回值:是一个装着流里面所有数据的数组
收集流中的数据,放到List集合中
// 获取姓张的用户
List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
List<String> stringList = list1.stream().filter(s -> s.startsWith("张")).collect(Collectors.toList());
System.out.println(stringList);
收集流中的数据,放到Set集合中
List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
Set<String> stringSet = list1.stream().filter(s -> s.startsWith("张")).collect(Collectors.toSet());
因为Set是不可重复的,所以会自动去重
收集流中的数据,放到Map集合中
List<User> userList = new ArrayList<>();
Collections.addAll(userList,new User("张无忌",15,"男"),
new User("张三丰",90,"男"),
new User("赵敏",16,"女"),
new User("周芷若",20,"女"));
/**
* toMap:
* 参数一表示键的生成规则
* 参数二表示值得生成规则
*
* 参数一:Function泛型一:表示流中每一个数据的类型
* 泛型二:表示Map集合中键的数据类型
* 方法apply形参:依次表示流中的每一个数据
* 方法体:生成键的代码
* 返回值:已经生成的键
* 参数二:Function泛型一:表示流中每一个数据的类型
* 泛型二:表示Map集合中值的数据类型
* 方法apply形参:依次表示流中的每一个数据
* 方法体:生成值的代码
* 返回值:已经生成的值
*/
Map<String, Integer> map = userList.stream().filter(user -> "男".equals(user.getSex())).collect(Collectors.toMap(new Function<User, String>() {
@Override
public String apply(User user) {
return user.getName();
}
}, new Function<User, Integer>() {
@Override
public Integer apply(User user) {
return user.getAge();
}
}));
// lambda表达式简化上述代码
Map<String, Integer> map = userList.stream().filter(user -> "男".equals(user.getSex()))
.collect(Collectors.toMap(user -> user.getName(), user -> user.getAge()));
System.out.println(map);
OK,以上内容就是Stream流的一些主要使用方法,当然还有很多实用的方法,例如Order By排序,Group By分组等。
小伙伴们自行去研究学习一下吧~
✨ 原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
👍 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!