一、Stream流
说到Stream便容易想到I/O Stream,而实际上,谁规定“流”就一定是“IO流”呢?
在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。
1.1 引言
几乎所有的集合(如 Collection 接口或 Map 接口等)都支持直接或间接的遍历操作。而当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。例如:
import java.util.ArrayList;
import java.util.List;
/*
使用传统的方式,遍历集合,对集合中的数据进行过滤
*/
public class Demo01List {
public static void main(String[] args) {
//传进啊一个List集合,存储姓名
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
//对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合中
List<String> listA = new ArrayList<>();
for(String s : list){
if(s.startsWith("张")){
listA.add(s);
}
}
//对listA集合进行过滤,只要姓名长度为3的人,存储到一个新的集合中
List<String> listB = new ArrayList<>();
for (String s : listA){
if(s.length() == 3){
listB.add(s);
}
}
//遍历listB集合
for (String s : listB) {
System.out.println(s); //张无忌 张三丰
}
}
}
这段代码中含有三个循环,每一个作用不同:
1. 首先筛选所有姓张的人;
2. 然后筛选名字有三个字的人;
3. 最后进行对结果进行打印输出。
每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是!循环是做事情的方式,而不是目的。另一方面,使用线性循环就意味着只能遍历一次。如果希望再次遍历,只能使用另一个循环从头开始。
解决方案:Lambda的衍生物Stream能给我们带来更加优雅的写法!
1.2 Stream流初体验
import java.util.ArrayList;
import java.util.List;
/*
使用Stream流的方式,遍历集合,对集合中的数据进行过滤
Stream流是JDK1.8之后出现的,
关注的是做什么,而不是怎么做
*/
public class Demo02Stream {
public static void main(String[] args) {
//创建一个List集合,存储姓名
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
//对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合中
//对listA集合进行过滤,只要姓名长度为3的人,存储到一个新的集合中
//遍历listB集合
list.stream()
.filter(name->name.startsWith("张"))
.filter(name->name.length()==3)
.forEach(name-> System.out.println(name));
}
}
1.3 两种获取Stream流的方式
* java.util.stream.Stream<T>是Java 8 新加入的最常用的流接口。(这并不是一个函数式接口。)
* 获取一个流非常简单,有以下两种常用的方式:
- 所有的Collection集合都可以通过stream默认方法获取流;
default Stream<T> stream ()
- Stream 接口的静态方法of可以获取数组对应的流。
static <T> Stream <T> of (T...values)
参数是一个可变参数,那么我们就可以传递一个数组
import java.util.*;
import java.util.stream.Stream;
public class Demo02GetStream {
public static void main(String[] args) {
//定义List、Set集合,利用stream默认方法把集合转换为Stream流
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stream2 = set.stream();
Map<String,String> map = new HashMap<>();
//获取键,存储到一个Set集合中
Set<String> keySet = map.keySet();
Stream<String> stream3 = keySet.stream(); //把获取到键的Set集合转换为stream流
//获取值,存储到一个Collection集合中
Collection<String> values = map.values();
Stream<String> stream4 = values.stream(); //把获取到值的map集合转换为stream流
//获取键值对(键与值的映射关系 entrySet)
Set<Map.Entry<String,String>> entries = map.entrySet(); //利用entrySet获取键值对
Stream<Map.Entry<String,String>> stream5 = entries.stream(); //把键值对转换为stream流
//把数组转换为Stream流
Stream<Integer> stream6 = Stream.of(1,2,3,4,5);
//可变参数可以传递数组
Integer[] arr = {
1,2,3,4,5};
Stream<Integer> stream7 = Stream.of(arr);
String[] arr2 = {
"a","bb","ccc"};
Stream<String> stream8 = Stream.of(arr2);
}
}
1.4 Stream流中的常用方法
forEach() 用于遍历流中的数据
* void forEach(Consumer<? super T> action);
该方法接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理。
Consumer接口是一个消费型的函数式接口,可以传递Lambda表达式,消费数据
* 简单记:
forEach方法,用来遍历流中的数据
是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法
import java.util.stream.Stream;
public class Demo02Stream_forEach {
public static void main(String[] args) {
//获取一个Stream流
Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六", "田七");