目录
前言:
在学习Stream流之前,你需要先学习 匿名内部类和lambda表达式;
匿名内部类:是继承了该类(子类)或者 实现了该接口的(实现类)匿名对象。
lambda表达式:是对匿名内部类的简写。
1、Stream流概述
Stream 流 jdk1.8引入的新特性;
Stream API 可以极大提高 Java 程序员的生产力,让程序员写出更高效率、干净、简洁的代码;
这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行更改处理,比如筛选,排序,聚合等。
2、获取Stream流的方式
获取方式 | 方法名 | 说明 |
单列集合 | default Stream<E>stream() | Collection中的默认方法 |
双列集合 | 无 | 无法直接使用stream流,需要使用KeySet(),entrySet() |
数组 | public static<T>Stream<T>stream(T[]array) | Array工具类中的静态方法 |
一堆零散数据 | public static<T>Stream<T>of(T... values) | Stream接口中的静态方法 |
2.1 单列集合获取Stream流
public static void main(String[] args) {
// 单列集合
List<String> list = new ArrayList<>();
Collections.addAll(list, "张三", "李四", "王五", "赵六");
// 匿名内部类
//void forEach(Consumer action) 遍历
//Consumer的泛型:表示流中的数据类型
//accept方法的形参s:依次表示流里的每一个数据
//方法体:对每一个数据的处理操作(打印)
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("===========================");
/**
* lambda 表达式
* s 为 集合中的每一个元素
* ->为 lambda表达式 标识符
*/
list.stream().forEach(s -> System.out.println(s));
}
2.2 双列集合获取Stream流
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("赵芸", 22);
map.put("张非", 24);
map.put("刘蓓", 27);
map.put("关雨", 18);
// KeySet() 键
map.keySet().stream().forEach(result -> System.out.println(result));
//entrySet() 键值对
map.entrySet().stream().forEach(result -> System.out.println(result));
}
2.3 数组获取Stream流
public static void main(String[] args) {
//基本数据类型
int arr1[] = {1, 3, 4, 5, 6};
Arrays.stream(arr1).forEach(result -> System.out.println(result));
//引用数据类型
String arr2[] = {"a", "b", "c", "d"};
Arrays.stream(arr2).forEach(result -> System.out.println(result));
}
2.4 零散数据获取Stream流
public static void main(String[] args) {
//零散数据
Stream.of(1, 2, 4, "a").forEach(result -> System.out.println(result));
}
/**
* Stream接口中静态方法 of 的细节
* 方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
* 但是数组必须是引用数据类型,如果传递基本数据类型,是会把整个数组
* 当作成一个元素,放到Stream当中
*/
3、Stream流的中间方法
名称 | 说明 |
Stream<T> filter (Predcate<? super T>predicate) | 过滤 |
Stream<T> limit (long maxSize) | 获取前几个元素 |
Stream<T> skip | 跳过前几个元素 |
Stream<T> distinct() | 元素去重,依赖(hashCode和equals方法) |
Static<T>Stream<T>concat(Stream a,Stream b) | 合并两个流为一个流 |
Stream<R> map(Function<T,R>mapper) | 转换流中的数据类型 |
方法实现:
public static void main(String[] args) {
// 单列集合
List<String> list = new ArrayList<>();
Collections.addAll(list, "张三", "李四", "王五", "赵六");
//1、过滤
// startWith 检测某字段是否以指定的前缀开始的
System.out.println("===============filter过滤====================");
list.stream()
.filter(s -> s.startsWith("张"))
.forEach(result -> System.out.println(result));
//2、skip 跳过
System.out.println("===============skip跳过====================");
list.stream().skip(2).forEach(result -> System.out.println(result));
//3、limit 获取前几个元素
System.out.println("===============limit获取前几个元素====================");
list.stream().limit(2).forEach(result -> System.out.println(result));
//4、concat 合并流
System.out.println("===============concat合并流====================");
Stream<String> oneStream = Stream.of("a", "b", "c");
Stream<Integer> twoStream = Stream.of(1, 2, 3);
Stream.concat(oneStream, twoStream).forEach(result -> System.out.print(result));
//5、map转换流中的数据类型
System.out.println("===============map转换流中的数据类型====================");
List<String> list2 = new ArrayList<>();
Collections.addAll(list2, "1", "2", "3", "4");
list2.stream()
.map(s -> Integer.parseInt(s)).filter(s -> s > 2)
.forEach(result -> System.out.println(result));
}
4、Stream 流的终结方法
名称 | 说明 |
void forEach(Consumer action) | 遍历 |
long count() | 统计 |
toArray | 收集流中的数据,放到数组中 |
collect(Collector collector) | 收集流中的数据,放到集合中 |
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "张三-12", "李四-13", "王五-20");
System.out.println("========终结方法:forEach遍历=========");
/**
* 匿名内部类语法
* Consumer 的泛型:表示流中的数据类型
* accept 方法的形参s:依次表示流里的每一个数据
* 方法体:对每一个数据的处理操作(打印)
*/
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//统计
System.out.println("======终结方法:count======");
long count = list.stream().count();
System.out.println(count);
/**
* 匿名内部类语法
* toArray 收集流中的数据,放到数组中
* toArray 方法参数的作用:会依次得到流里面的每一个数据,并把数据放到数组当中
* toArray 方法的返回值:是一个装着流里面所有数据的数组
*
* InterFunction的泛型:具体类型的数组
* apply 的形参:流中数据的个数,要跟数组的长度保持一致
* apply 的返回值具体类型的数组
*/
System.out.println("=====终结方法:toArray========");
list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
}
5、Stream练习题
(1)收集流中所有男性的数组
//收集流中,男性的数据
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
Collections.addAll(list1, "张飞-男-45", "刘备-男-50", "关羽-男-47", "孙尚香-女-34", "貂蝉-女-28");
// split:分割
list1.stream().filter(s -> "男".equals(s.split("-")[1]))
.forEach(s -> System.out.println(s));
// collect 收集
System.out.println("=== 将List集合中的男性收集到set集合中 ===");
List<String> list2 = new ArrayList<>();
Collections.addAll(
list2,
"张飞-男-45", "张飞-男-45", "刘备-男-50", "关羽-男-47", "孙尚香-女-34", "貂蝉-女-28");
list2.stream().filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toSet()).forEach(s -> System.out.println(s));
/** 回顾集合知识
* list 收集数据有序、可重复
* set 收集数据无序、不可重复
*/
// collect
System.out.println("将ArrayList集合中的男性收集到Map集合中");
Map<String, String> map = list1.stream().filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s -> s.split("-")[0]
,
s -> s.split("-")[2]
));
map.entrySet().forEach(result -> System.out.println(result));
}
(2)List集合转map集合所遇到的问题
所分割后的数据,key重复,会报出异常
解决方法:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "张飞-男-45", "张飞-男-48", "刘备-男-50", "关羽-男-47", "孙尚香-女-34", "貂蝉-女-28");
Map<String, String> map = list.stream().collect(Collectors.toMap(
s -> s.split("-")[0]
,
s -> s.split("-")[2]
// 如果转换map集合的key重复,则后面的value替换掉前面的value
// 也可替换顺序(s1,s2)-> s1,前面的key不变
, (s1, s2) -> s2
));
map.entrySet().forEach(result -> System.out.println(result));
}