Stream流

1 引言

  • I/O流是用于读写,Stream用于对数组和集合进行简化操作。我们可以将集合和数组转换成Stream流,使用Stream流中的方法对其中的元素进行操作。
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hxx");
list.add("hq");
list.add("qzy");
//使用Stream流的方式遍历集合,对集合中的数据进行过滤
list.stream()
.filter(name->name.startsWith("h"))
.filter(name->name.length()==3)
.forEach(name->System.out.println(name));
}

2 流式思想概述

  • Stream流是一个集合元素的函数模型,并不是集合,也不是数据结构,其本身并不存储任何元素或其地址值

  • Stream是一个来自数据源的元素队列

    • 元素是特定类型的对象,形成一个队列。
    • 数据源可以是集合、数组
  • 和之前的Collection相比,Stream操作还有两个基础的特征:

    • Pipelining:中间操作都会返回流对象本身。这样多个操作可以串联成一个管道,如同流式风格。这样可以对操作进行优化,比如延迟执行和短路

    • 内部迭代:以前对集合遍历都是通过iterator或者增强for的方式,显式的在集合外部进行迭代,即外部迭代。Stream提供了内部迭代的方式,流可以直接调用遍历方法

  • Stream属于管道流,只能使用一次。第一个Stream流调用完毕,数据会流转到下一个Stream上。而这时第一个Stream流已经使用完毕并且关闭。

  • 使用流的步骤:

    • 获取一个数据源
    • 数据转换:每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换)。
    • 执行操作获取想要的结果

3 获取流

  • 获取流的方式:

    • 所有的Collection都可以通过stream默认方法获取流
    • Stream接口的静态方法of 可以获取数组对应的流
  • java.util.Collection 接口中加入了default方法 stream 来获取流,所以其所有实现类都可获取流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String[] args) {		
//将集合转换为stream
List<String> list1 = new ArrayList<>();
Stream<String> stream1 = list1.stream();

Set<String> set = new HashSet<>();
Stream<String> stream2 = set.stream();

Map<String,String> map = new HashMap<>();
//获取键,存储到一个set集合中
Set<String> set1 = map.keySet();
Stream<String> stream3 = set1.stream();
//获取值,存储到Collection集合中
Collection<String> values = map.values();
Stream<String> stream4 = values.stream();
//获取键值对
Set<Map.Entry<String, String>> entryset = map.entrySet();
Stream<Map.Entry<String, String>> stream5 = entryset.stream();

//将数组转换为stream流
Stream<Integer> integerStream = Stream.of(1, 2, 3);
Integer[]arr = {1,2,3};
Stream<Integer> arr1 = Stream.of(arr);
}

4 常用方法

  • 延迟方法:返回值类型仍然是Stream接口自身类型的方法,支持链式调用
  • 终结方法:返回值类型不再是Stream自身类型的方法,不咋支持类似于StringBuilder那样的链式调用。比如有countforeach方法

forEach

  • 该方法接收一个Consumer接口函数,将每一个硫元素交个该函数进行处理
1
void forEach(Consumer<? super T> action);
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
//获取stream流
Stream<String> stringStream = Stream.of("hxx", "qzy");
//调用forEach
stringStream.forEach(
(String name)->{
System.out.println(name);
}
);
}

过滤方法filter

1
Stream<T> filter(Predicate<? super T> predicate);

该函数接收一个Predicate函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
Stream<String> stream = Stream.of("hxx", "qzy");
Stream<String> h = stream.filter(
(String name) -> {
return name.startsWith("h");
}
);
System.out.println(h);
stream.forEach(name-> System.out.println(name));//报错,使用完stream之后转换到了h流,stream已经关闭
}

映射:map

  • 如果需要将流中的元素映射到另一个流中,可以使用map方法,方法签名:
1
2
3
4
5
6
7
8
//<R> Stream <R> map(Function<? siper T,? extends R> maper);
public static void main(String[] args) {
Stream<String> stream = Stream.of("1","2");
Stream<Integer> integerStream = stream.map((String s) -> {
return Integer.parseInt(s);
});
integerStream.forEach(i-> System.out.println(i));
}

count、limit、skip、contact

1
2
3
4
5
6
7
8
9
10
//long count(); 终结方法
public static void main(String[] args) {
Stream<String> stream = Stream.of("1","2","3","4","5");
/*Stream<String> limit = stream.limit(3);
System.out.println(limit.count());
Stream<String> skip = stream.skip(3);*/
Stream<String> stream1 = Stream.of("hxx");
Stream<String> concat = Stream.concat(stream, stream1);//保证流没有关闭
concat.forEach(i-> System.out.println(i));
}