目录
[3.2:中间方法 用于过滤、排序、聚合](#3.2:中间方法 用于过滤、排序、聚合)
0:在学习stream流之前回顾知识点
下图是容器的类图,可以看到最上层的接口是迭代器,我们这里为什么了解迭代器呢?
接着往下看,我们遍历数组一般使用两种方式,一种是传统方式,一种是迭代器方式。当我们了解到了这两种方式的优缺点之后,我们再来学习流

0.1:传统方式遍历集合
传统遍历元素:直接通过索引遍历集合(如数组),客户端需要知道集合的内部结构(如数组长度),不推荐在里边删除元素。
java
/**
* 传统遍历元素
*/
@Test
public void T1(){
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("c");
list.add("d");
//list的传统方式遍历 我们需要知道数组的长度
for (int i = 0; i < list.size(); i++) {
System.out.println("传统遍历list:"+list.get(i));
}
}
/**
* 传统for遍历元素删除,这种方法不推荐
*/
@Test
public void T11(){
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("c");
list.add("d");
//list的传统方式遍历 我们需要知道数组的长度
for (int i = 0; i < list.size(); i++) {
//在for循环中删除元素c,会导致后边的元素前移,从而漏掉下一个元素,所以输出结果还有c
if (list.get(i).equals("c")){
list.remove(i);
//list.remove(s); 错误方法 ConcurrentModificationException
}
}
System.out.println(list);
}
0.2:迭代器遍历集合
1:我们先看一下迭代器的方法,Java 的集合框架(如 List、Set)均实现了 Iterator 接口,通过iterator() 方法返回迭代器。迭代器被归类java设计模式里面的 行为型设计模式 (Behavioral Design Pattern),定义了 对象之间的交互方式。
它的核心思想是:解耦遍历逻辑,我们不关心他们具体的数据结构
适用于set、list、map。也就是说我们不关心他们的数据结构,只管用迭代器遍历就行,可以删除数据。
它通常包含以下核心方法:
hasNext():判断是否还有下一个元素。
next():获取下一个元素。
remove()(可选):删除当前元素。

2:迭代器遍历元素
删除元素的强制模数(修改次数)=预期模数,删除数据的时候回判断模数是否等于预期模数。保证了删除是数据安全。
0.3:这两种方式的有优缺点
传统方式遍历:需要根据索引下标遍历集合,需要知道集合的长度数据
迭代器方式遍历:解耦数据结构,通用迭代器遍历。不关心数据结构,提供了同一的访问接口,都是迭代器,缺点即使增加了额外的迭代器类
1:stream流的含义
stream流就像一种更高阶的迭代器,与传统的迭代器不一样,流不存储数据,只是代表了一个计算过程,在这个过程中对数据进行操作。比如过滤、排序、聚合操作。流就像一个管道,在这个管道中对数据操作、按照一定的规则流动。比传统迭代器多了过滤、排序、聚合等操作,功能更丰富。
2:stream流的优点
流的作用主要体现在以下几个方面:
函数式编程风格:流API提供了一套丰富的函数式编程特性,使得代码更简洁、可读性更强。我们可以用非常少的代码处理复杂的逻辑。
无状态操作:流的操作不会改变原始数据集合,它们是无状态的。这就像是音乐家们的乐器,演奏结束后,乐器仍然是原始的状态,没有被改变。
3:stream流使用
3.1:获取流
java
/**
* 在使用Stream流过程中
* 1:获取流
* 2:处理流
* 2.1:中间方法
* 2.2:终结方法
*/
public class Steam获取流1 {
//1:list获取流 list.stream()
@Test
public void t1() {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
list.add("");
list.add(null);
Stream<String> stream = list.stream();
stream.forEach(System.out::println);//终结方法
}
//2:set获取流 set.stream()
@Test
public void t2() {
Set<String> set = new HashSet<>();
set.add("1");
set.add("2");
set.add("3");
set.add("1");
set.add("4");
set.add("5");
Stream<String> stream = set.stream();
stream.forEach(System.out::println);
}
//3:map获取流 map.keySet().stream()
@Test
public void t3() {
Map<String, Integer> map = new HashMap<>();
map.put("11", 1);
map.put("22", 2);
map.put("33", 3);
map.put("44", 4);
System.out.println("=======");
Stream<String> stream = map.keySet().stream();
stream.forEach(System.out::println);
System.out.println("=======");
Stream<Map.Entry<String, Integer>> stream1 = map.entrySet().stream();
stream1.forEach(entry -> System.out.println(entry.getKey() + ":" + entry.getValue()));
}
//4:数组获取流 Arrays.stream()
@Test
public void t4() {
int[] ints = new int[]{1, 2, 3, 4, 5};
Arrays.stream(ints).forEach(System.out::println);
System.out.println("================");
String[] strings = {"1", "2", "3", "4"};
Stream<String> stream = Arrays.stream(strings);
stream.forEach(System.out::println);
}
//5:stream流直接创建 Stream.of()
@Test
public void t5() {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
stream.forEach(System.out::println);
System.out.println("==============");
Stream<String> stream1 = Stream.of("a","b","c","d");
stream1.forEach(System.out::println);
Integer[] ints = {1, 2, 3, 4, 5};
String[] strings = {"1", "2", "3", "4"};
Stream.of(ints).forEach(System.out::println);
System.out.println("=============");
Stream.of(strings).forEach(System.out::println);
}
}
3.2:中间方法 用于过滤、排序、聚合
java
/**
* stream流体验 过滤
* 代码简单,不改变原始流
*/
@Test
public void t1(){
List<Person> peoples = List.of(
new Person("北京", 15, "Jack1"),
new Person("洛阳", 18, "Jack2"),
new Person("深圳", 30, "Jack3"),
new Person("杭州", 45, "Jack4"),
new Person("青岛", 50, "Jack5")
);
//传统for循环,需要过滤age大于18的,代码比较多
List<Person> people18=new ArrayList<>();
for (Person people : peoples) {
System.out.println("增强for:"+people);
if (people.getAge()>18){
people18.add(people);
}
}
//Stream流初体验,filter过滤年龄大于18的person,函数式编程
//代码简单,返回新的集合,原来的集合不变,这就是无状态,不改变原始数据
List<Person> newlist = peoples.stream()
.filter(person -> person.getAge() > 18)
.toList();
newlist.forEach(System.out::println);//新的集合
System.out.println("=====");
peoples.forEach(System.out::println);//原始集合不变
}
//1.1:filter 中间方法 过滤
@Test
public void filter1() {
List<Person> people = List.of(
new Person("北京", 15, "Jack1"),
new Person("洛阳", 18, "Jack2"),
new Person("深圳", 30, "Jack3"),
new Person("杭州", 45, "Jack4"),
new Person("青岛", 50, "Jack5"),
new Person("青岛", 50, "Jack5")
);
List<Person> list = people.stream().filter(new Predicate<Person>() {
@Override
public boolean test(Person person) {
//返回值为true,数据留下,否则抛弃
return person.getAge() > 30;
}
}).toList();
list.forEach(System.out::println);
System.out.println("========简化写法========");
people.stream()
.filter(p -> p.getAge() > 30)
.filter(person -> person.getName().contains("Jack5"))
.forEach(System.out::println);
}
//1.2:filter 中间方法 过滤
@Test
public void filter2() {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三丰");
list.add("张三丰");
list.add("张强");
list.add("周芷若");
list.add("赵敏");
Stream<String> stringStream = list.stream()
.filter(name -> name.startsWith("张"));
stringStream.forEach(System.out::println);
//报错,一旦使用了终结方法,stream就会被关闭
//stringStream.filter(name->name.startsWith("张三")).forEach(System.out::println);
}
//2:limit 中间方法 指定范围
@Test
public void limit() {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三丰");
list.add("张三丰");
list.add("张强");
list.add("周芷若");
list.add("赵敏");
list.stream().limit(3).forEach(System.out::println);
//forEach 是终结方法
}
//3:skip 中间方法 跳过2个元素
@Test
public void spip() {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三丰1");
list.add("张三丰2");
list.add("张强");
list.add("周芷若");
list.add("赵敏");
list.stream().skip(2).forEach(System.out::println);
System.out.println("===============");
list.stream().limit(3).skip(2).forEach(System.out::println);
}
//4:distinct 中间方法 去重复元素
@Test
public void distinct() {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张三丰");
list.add("张三丰");
list.add("张强");
list.add("周芷若");
list.add("赵敏");
list.stream().distinct().forEach(System.out::println);
}
//5:concat 中间方法 合并两个流的数据
@Test
public void concat() {
Stream<String> stringStream1 = Stream.of("1", "2", "3", "a");
Stream<String> stringStream2 = Stream.of("a", "b", "c");
Stream<String> concat = Stream.concat(stringStream1, stringStream2);
concat.distinct().forEach(System.out::println);
//.distinct().forEach(System.out::println);
}
//6:map 中间方法 转换流的数据类型
@Test
public void map() {
List<String> list = new ArrayList<>();
Collections.addAll(list, "张三1-21", "张三2-22", "张三3-23", "张三4-24", "张三5-25");
System.out.println("========分割线=======");
list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
System.out.println("传递得到:"+s);
String[] split = s.split("-");
String name=split[0];
String age=split[1];
return age;
}
}).forEach(System.out::println);
System.out.println("========分割线,简化写法=======");
list.stream()
.map(s -> Integer.parseInt(s.split("-")[1]))
.forEach(System.out::println);
}
3.3:终结方法
java
/**
* 在使用Stream流过程中
* 1:获取流
* 2:处理流
* 2.1:中间方法
* 2.2:终结方法
*/
public class Steam终结方法3 {
//1:forEach 终结方法,
@Test
public void forEach() {
List<Person> people = List.of(
new Person("北京", 15, "Jack1"),
new Person("洛阳", 18, "Jack2"),
new Person("深圳", 30, "Jack3"),
new Person("杭州", 45, "Jack4"),
new Person("青岛", 50, "Jack5"),
new Person("青岛", 50, "Jack5")
);
people.stream().forEach(new Consumer<Person>() {
@Override
public void accept(Person person) {
System.out.println(person);
}
});
System.out.println("======终结方法======");
people.stream().forEach(person -> System.out.println(person));
System.out.println("======终结方法======");
people.stream().forEach(System.out::println);
}
//2:count 终结方法,
@Test
public void count() {
List<Person> people = List.of(
new Person("北京", 15, "Jack1"),
new Person("洛阳", 18, "Jack2"),
new Person("深圳", 30, "Jack3"),
new Person("杭州", 45, "Jack4"),
new Person("青岛", 50, "Jack5"),
new Person("青岛", 50, "Jack5")
);
long count = people.stream().count();
System.out.println("长度:"+count);
}
//2:toArray 终结方法 准换成数组
@Test
public void toArray() {
List<Person> people = List.of(
new Person("北京", 15, "Jack1"),
new Person("洛阳", 18, "Jack2")
);
Object[] array = people.stream().toArray();
System.out.println("长度:"+array.length);
for (Object o : array) {
System.out.println(o);
}
}
//3:toList toSet toMap
//map的
// 终结方法 转换成list
@Test
public void toList(){
List<String> list = new ArrayList<>();
Collections.addAll(list, "张三1-男-21", "张三1-男-21","张三2-男-22", "丽丽3-女-23", "张三4-男-24", "丽丽5-女-25");
System.out.println("======toList=====");
List<String> list1 = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.toList();
list1.forEach(System.out::println);
System.out.println("======toSet=====");
Set<String> set = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("======toMap=====");
Map<String, String> map = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.distinct() //必须去重,key不能重复
.collect(Collectors.toMap(n -> n.split("-")[0], n -> n.split("-")[1]));
map.forEach((k, v) -> System.out.println(k + "=" + v));
}
}
