Java的Stream流
感受 Stream 流的作用
需求:按照下面的要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
- 把所有以“张”开头的元素存储到新集合中
- 把“张”开头的,长度为3的元素再存储到新集合中
- 遍历打印最终结果
package com.faxont.stream;
import java.util.ArrayList;
public class StreamDemo1 {
public static void main(String[] args) {
/*
创建集合添加元素,完成以下需求:
1. 把所有以“张”开头的元素存储到新集合中
2. 把“张”开头的,长度为3的元素再存储到新集合中
3. 遍历打印最终结果
*/
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
// stream 流
list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3).forEach(System.out::println);
// // 1. 把所有以“张”开头的元素存储到新集合中
// ArrayList<String> list2 = new ArrayList<>();
// for (String name : list) {
// if(name.startsWith("张")){
// list2.add(name);
// }
// }
//
// // 2. 把“张”开头的,长度为3的元素再存储到新集合中
// ArrayList<String> list3 = new ArrayList<>();
// for (String name : list2) {
// if(name.length() == 3){
// list3.add(name);
// }
// }
//
// // 3. 遍历打印最终结果
// for (String name : list3) {
// System.out.println(name);
// }
}
}
Stream 流的作用:结合了 Lambda 表达式,简化集合、数组的操作
Stream 流的使用步骤:
-
先得到一条 Stream 流(流水线),并把数据放上去
-
利用 Stream 流中的 API 进行各种操作-
中间方法(过滤、转换):方法调用完毕之后,还可以调用其它方法
-
终结方法(统计、打印):最后一步,调用完毕之后,不能调用其它方法
-
-
使用中间方法对流水线上的数据进行操作
-
使用终结方法对流水线上的数据进行操作
| 获取方式 | 方法名 | 说明 |
|---|---|---|
| 单列集合 | default Stream |
Collection 中的默认方法 |
| 双列集合 | 无 | 无法直接使用 stream 流 |
| 数组 | public static |
Arrays 工具类中的静态方法 |
| 一堆零散数据 | public static |
Stream 接口中的静态方法 |
注:双列集合无法直接使用 stream 流,需要先用 keySet() 或 entrySet() 转成单列**集合
package com.faxont.stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;
public class StreamDemo2 {
public static void main(String[] args) {
/*
单列集合 default Stream<E> stream() Collection 中的默认方法
双列集合 无 无法直接使用 stream 流
数组 public static <T> Stream<T> stream(T[] array) Arrays 工具类中的静态方法
一堆零散数据 public static <T> Stream<T> of(T... values) Stream 接口中的静态方法
*/
// 1. 单列集合获取 Stream 流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a", "b", "c", "d", "e");
// // 获取一条流水线,并将集合中的元素放到流水线上
// Stream<String> stream = list.stream();
// // 使用终结方法 forEach 遍历打印流水线中的元素
// stream.forEach(System.out::println);
list.stream().forEach(System.out::println);
}
}
package com.faxont.stream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class StreamDemo3 {
public static void main(String[] args) {
/*
双列集合 无 法直接使用 stream 流
*/
// 1. 创建双列集合
HashMap<String, Integer> hm = new HashMap<>();
// 2. 添加数据
hm.put("aaa", 111);
hm.put("bbb", 222);
hm.put("ccc", 333);
hm.put("ddd", 444);
// 3. 获取 Stream 流
Set<Map.Entry<String, Integer>> entries = hm.entrySet();
Set<String> keySet = hm.keySet();
entries.stream().forEach(System.out::println);
System.out.println("-----------------------");
keySet.stream().forEach(System.out::println);
}
}
package com.faxont.stream;
import java.util.Arrays;
import java.util.stream.Stream;
public class StreamDemo4 {
public static void main(String[] args) {
/*
数组 public static <T> Stream<T> stream(T[] array) Arrays 工具类中的静态方法
*/
// 1. 创建数组
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
String[] arr2 = {"a", "b", "c"};
// 2. 获取 Stream 流
Arrays.stream(arr).forEach(System.out::println);
System.out.println("-----------------------");
Arrays.stream(arr2).forEach(System.out::println);
System.out.println("-----------------------");
// 注意:
// Stream 接口中静态方法 of 的细节
// 方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
// 但是数组必须是引用数据类型的,如果传递基本数据类型,会把整个数组当作一个元素,放到 Stream 流当中
Stream.of(arr).forEach(System.out::println);// [I@7cca494b
System.out.println("-----------------------");
Stream.of(arr2).forEach(System.out::println);
}
}
package com.faxont.stream;
import java.util.stream.Stream;
public class StreamDemo5 {
public static void main(String[] args) {
/*
一堆零散数据 public static <T> Stream<T> of(T... values) Stream 接口中的静态方法
*/
Stream.of(1, 2, 3, 4, 5).forEach(System.out::println);
System.out.println("-----------------------");
Stream.of("a", "b", "c", "d", "e").forEach(System.out::println);
}
}
Stream 流的中间方法
| 名称 | 说明 |
|---|---|
| Stream |
过滤 |
| Stream |
获取前几个元素 |
| Stream |
跳过前几个元素 |
| Stream |
元素去重,依赖(hashCode 和 equals 方法) |
| static |
合并 a 和 b 两个流为一个流 |
| Stream |
转换流中的数据类型 |
注意1:中间方法,返回新的 Stream 流,原来的 Stream 流只能使用一次,建议使用链式编程
注意2:修改 Stream 流中的数据,不会影响原来集合或者数组中的数据
package com.faxont.stream;
import java.util.ArrayList;
import java.util.Collections;
public class StreamDemo6 {
public static void main(String[] args) {
/*
Stream<T> filter(Predicate<? super T> predicate) 过滤
Stream<T> limit(long maxSize) 获取前几个元素
Stream<T> skip(long n) 跳过前几个元素
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
// 1. 过滤 把张开头的留下,其余的过滤
list.stream().filter(name -> name.startsWith("张")).forEach(System.out::println);
System.out.println(list);// [张无忌, 周芷若, 赵敏, 张强, 张三丰, 张翠山, 张良, 王二麻子, 谢广坤] 集合本身没有改变
System.out.println("-----------------------");
// 2. 获取前几个元素
list.stream().limit(3).forEach(System.out::println);
System.out.println("-----------------------");
// 3. 跳过前几个元素
list.stream().skip(3).forEach(System.out::println);
System.out.println("-----------------------");
// 练习 张强, 张三丰, 张翠山
list.stream().skip(3).limit(3).forEach(System.out::println);
System.out.println("-----------------------");
list.stream().limit(6).skip(3).forEach(System.out::println);
}
}
package com.faxont.stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;
public class StreamDemo7 {
public static void main(String[] args) {
/*
Stream<T> distinct() 元素去重,依赖(hashCode 和 equals 方法)
static <T> Stream<T> concat(Stream a, Stream b) 合并 a 和 b 两个流为一个流
*/
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "张无忌", "张无忌", "张无忌", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, "周芷若", "赵敏");
// 1. 元素去重,依赖(hashCode 和 equals 方法)
list1.stream().distinct().forEach(System.out::println);
System.out.println("-----------------------");
// 2. 合并 a 和 b 两个流为一个流
Stream.concat(list1.stream().distinct(), list2.stream()).forEach(System.out::println);
}
}
package com.faxont.stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
public class StreamDemo8 {
public static void main(String[] args) {
/*
Stream<R> map(Function<T, R> mapper) 转换流中的数据类型
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-15", "周芷若-14", "赵敏-13", "张强-20",
"张三丰-100", "张翠山-40", "张良-35", "王二麻子-37", "谢广坤-41");
// 只获取年龄并进行打印
// 第一个类型:流中原本的数据类型
// 第二个类型:要转成之后的数据类型
// 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(System.out::println);
System.out.println("-----------------------");
// 简化
list.stream()
.map(s -> Integer.parseInt(s.split("-")[1]))
.forEach(System.out::println);
}
}
Stream 流的终结方法
| 名称 | 说明 |
|---|---|
| void forEach(Consumer action) | 遍历 |
| long count() | 统计 |
| toArray() | 收集流中的数据,放到数组中 |
| collect(Collector collector) | 收集流中的数据,放到集合中 |
package com.faxont.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.IntFunction;
public class StreamDemo9 {
public static void main(String[] args) {
/*
void forEach(Consumer action) 遍历
long count() 统计
toArray() 收集流中的数据,放到数组中
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
// 1. 遍历
// Consumer 的泛型:表示流中数据的类型
// accept 方法的形参 s:依次表示流里面的每一个数据
// 方法体:对每一个数据的处理操作(打印)
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("-----------------------");
list.stream().forEach(System.out::println);
System.out.println("-----------------------");
// 2. 统计
long count = list.stream().count();
System.out.println(count);
System.out.println("-----------------------");
// 3. 收集流中的数据,放到数组中
// IntFunction<String[]> 泛型:表示数组的具体类型
// apply 的形参:流中数据的个数,要跟数组的长度保持一致
// apply 的返回值:具体类型的数组
// 方法体:创建一个数组,并返回该数组
// toArray 方法的参数的作用:负责创建一个指定类型的数组
// toArray 方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
// toArray 方法的返回值,是一个装着流里面所有数据的数组
String[] array = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(array));
/**
* 这属于 构造方法引用:
* 语法:类名[]::new
* 作用:生成一个 “能创建该类型数组” 的函数对象
*/
String[] arr = list.stream().toArray(String[]::new);
for (String s : arr) {
System.out.println(s);
}
}
}
package com.faxont.stream;
import java.util.*;
import java.util.stream.Collectors;
public class StreamDemo10 {
public static void main(String[] args) {
/*
collect(Collector collector) 收集流中的数据,放到集合中(List, Set, Map)
注意:
如果我们要把流的数据收集到 Map 集合中,键不能重复,否则会报错
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-男-15", "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20",
"张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢广坤-男-41");
// 收集 List 集合当中
// 需求
// 把所有男性收集起来
List<String> l = list.stream()
.filter(s -> s.split("-")[1].equals("男"))
.collect(Collectors.toList());
System.out.println(l);
// 收集 Set 集合当中
// 需求
// 把所有男性收集起来
Set<String> set = list.stream()
.filter(s -> s.split("-")[1].equals("男"))
.collect(Collectors.toSet());
System.out.println(set);
// 收集 Map 集合当中
// 需求
// 把所有男性收集起来
// key:姓名
// value:年龄
Map<String, Integer> map = list.stream()
.filter(s -> s.split("-")[1].equals("男"))
.distinct()
.collect(Collectors.toMap(
s -> s.split("-")[0],
s -> Integer.parseInt(s.split("-")[2])));
System.out.println(map);
}
}
Stream 流练习
练习1:数据过滤
定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
过滤奇数,只留下偶数。
并将结果保存起来
package com.faxont.practice;
import java.util.ArrayList;
import java.util.Collections;
public class Practice1 {
public static void main(String[] args) {
/*
定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
过滤奇数,只留下偶数。
并将结果保存起来
*/
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.stream()
.filter(s -> s % 2 == 0)
.forEach(System.out::println);
}
}
练习2:数据操作
创建一个 ArrayList 集合,并添加以下字符串,字符串中前面是姓名,后面是年龄
"zhangsan, 23"
"lisi, 24"
"wangwu, 25"
保留年龄大于等于24岁的人,并将结果收集到 Map 集合中,姓名为键,年龄为值
package com.faxont.practice;
import java.util.ArrayList;
import java.util.Map;
import java.util.stream.Collectors;
public class Practice2 {
public static void main(String[] args) {
/*
创建一个 ArrayList 集合,并添加以下字符串,字符串中前面是姓名,后面是年龄
"zhangsan, 23"
"lisi, 24"
"wangwu, 25"
保留年龄大于等于24岁的人,并将结果收集到 Map 集合中,姓名为键,年龄为值
*/
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan, 23");
list.add("lisi, 24");
list.add("wangwu, 25");
Map<String, Integer> map = list.stream()
.filter(s -> Integer.parseInt(s.split(", ")[1]) >= 24)
.collect(Collectors.toMap(
s -> s.split(", ")[0],
s -> Integer.parseInt(s.split(", ")[1])
));
System.out.println(map);
}
}
练习3:数据操作
现在有两个 ArrayList 集合,
第一个集合中:存储6名男演员的名字和年龄。第二个集合中:存储6名女演员的名字和年龄。
姓名和年龄中间用逗号隔开。比如:张三,23
要求完成如下操作:
- 男演员只要名字为3个字的前两人
- 女演员只要姓杨的,并且不要第一个
- 把过滤后的男演员姓名和女演员姓名合并到一起
- 将上一步的演员信息封装成 Actor 对象
- 将所有的演员对象都保存到 List 集合中
备注:演员类 Actor,属性只要一个:name,age
package com.faxont.practice;
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Practice3 {
public static void main(String[] args) {
/*
现在有两个 ArrayList 集合,
第一个集合中:存储6名男演员的名字和年龄。第二个集合中:存储6名女演员的名字和年龄。
姓名和年龄中间用逗号隔开。比如:张三,23
要求完成如下操作:
1. 男演员只要名字为3个字的前两人
2. 女演员只要姓杨的,并且不要第一个
3. 把过滤后的男演员姓名和女演员姓名合并到一起
4. 将上一步的演员信息封装成 Actor 对象
5. 将所有的演员对象都保存到 List 集合中
备注:演员类 Actor,属性只要一个:name,age
男演员:"蔡坤坤,24","叶鞠咸,23","刘不甜,22","吴签,24","省嘉,30","肖滚滚,27"
女演员:"赵小颖,35","杨颖,36","高元元,43","张天天,31","刘诗,35","杨小幂,33"
*/
ArrayList<String> actorList = new ArrayList<>();
Collections.addAll(actorList, "蔡坤坤,24", "叶鞠咸,23", "刘不甜,22", "吴签,24", "省嘉,30", "肖滚滚,27");
ArrayList<String> actressList = new ArrayList<>();
Collections.addAll(actressList, "赵小颖,35", "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33");
// 1. 男演员只要名字为3个字的前两人
Stream<String> stream1 = actorList.stream()
.filter(s -> s.split(",")[0].length() == 3)
.limit(2);
// 2. 女演员只要姓杨的, 并且不要第一个
Stream<String> stream2 = actressList.stream()
.filter(s -> s.startsWith("杨"))
.skip(1);
// 3. 把过滤后的男演员姓名和女演员姓名合并到一起
Stream<String> stream3 = Stream.concat(stream1, stream2);
// 4. 将上步的演员信息封装成 Actor 对象
Stream<Actor> stream4 = stream3.map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1])));
// 5. 将所有的演员对象都保存到 List 集合中
ArrayList<Actor> list = stream4.collect(Collectors.toCollection(ArrayList::new));
System.out.println(list);
}
}
package com.faxont.practice;
import java.util.Objects;
public class Actor {
private String name;
private int age;
public Actor() {
}
public Actor(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Actor{name = " + name + ", age = " + age + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Actor actor = (Actor) o;
return age == actor.age && Objects.equals(name, actor.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}

浙公网安备 33010602011771号