java-doc-数据流

流是数据的渠道,因此,流代表了一个对象序列。流操作数据源,如数组或集合。流本身不存储数据,而只是移动数据,在移动过程中可能会堆数据执行过滤、排序或其他操作。然而,一般来说,流操作本身不修改数据源。

BaseStream

BaseStream定义了所有流都可以使用的基本功能。它是一个泛型接口。

  • 声明
方法 描述
interface BaseStream<T, S extends BaseStream<T, S>> T指定流中元素的类型,S指定扩展了BaseStream的流的类型。
  • BaseStream声明的方法
方法 描述
void close() 调用注册的关闭处理程序,关闭调用流(如前所述,很少有流需要被关闭)
boolean isParallel() 如果调用流失并行流,返回true;如果调用流是顺序流,就返回false
Iterator iterator() 获得流的一个迭代器,并返回对该迭代器的引用(终端操作)
S onClose(Runnable handler) 返回一个新流,handler指定了该流的关闭处理程序。当关闭该流时,将调用这个处理程序(中间操作)
S paralle() 基于调用流,返回一个并行流。如果调用流已经是并行流,就返回该流(中间操作)
S sequential() 基于调用流,返回一个顺序流。如果调用流已经是顺序流,就返回该流(中间操作)
Spliterator spliterator() 获得流的spliterator,并返回其引用(终端操作)
S unordered() 基于调用流,返回一个无序流。如果调用流已经是无序流,就返回该流(中间操作)

在流的方法中,终端操作会消耗流,这种操作用于产生结果,例如找出流中最小值等,这种流被消费以后,就不能被重用。中间操作会产生另一个流,因此,中间操作可以用来创建执行一系列动作的管道。另外,中间操作不是立即发生的,相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生。这种机制称为延迟行为,所以称中间操作为延迟发生的,延迟行为让流能够更加高效地执行。

流的另外一个关键点是,一些中间操作是无状态的,另外一些是有状态的。在无状态操作中,独立于其他元素处理每个元素。在有状态操作中,某个元素的处理可能依赖于其他元素。例如,排序是有状态操作,因为元素的顺序依赖于其他元素的值,因此,sorted()方法是有状态的。然而,基于无状态谓词的元素过滤是无状态的,因为每个元素都是被单独处理的,因此,filter()方法是无状态的。当需要并行处理流时,无状态与有状态的区别尤其重要,因为有状态操作可能需要几次处理才能完成。

Stream

Stream是BaseStream的子接口。

  • Stream接口声明的方法
方法 描述
<R,A>R collect(Collector<? super T, A, R> collectorFunc) 将元素收集到一个可以修改的容器中,并返回该容器,这被称为可变缩减操作。R指定结果容器的类型,T指定调用流的元素类型,A指定内部累加的类型,collectorFunc指定收集过程的工作方式(终端操作)
long count() 统计流中的元素数,并返回结果(终端操作)
Stream<T> filter(Predicate<? super T> pred) 产生一个流,其中包含调用流中满足pred指定的元素(中间操作)
void forEach(Consumer<? super T> action) 对于调用流中的每个元素,执行由action指定的动作(终端操作)
<R>Stream<R> map(Function<? super T, > extends R> mapFunc) 对调用流中的元素应用mapFunc,产生包含这些元素的一个新流(中间操作)。R指定新流的元素类型,T指定调用流的元素类型,mapFunc是完成映射的Function实例。映射函数必须是无状态和不干预的。
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapFunc) 对调用流中的元素应用mapFunc,产生包含这些元素的一个新的DoubleStream流(中心操作)
IntStream mapToInt(ToIntFunction<? super T> mapFunc) 对调用流中的元素应用mapFunc,产生包含这些元素的一个新的IntStream流(中间操作)
LongStream mapToLong(ToLongFunction<? super T> mapFunc) 对调用流中的元素应用mapFunc,产生包含这些元素的一个新的LongStream流(中间操作)
Optional<T> max(Comparator<? super T> comp) 使用由comp指定的排序,找出并返回调用流中最大元素(终端操作)
Optional<T> min(Comparator<? super T> comp) 使用由comp指定的排序,找出并返回调用流中最小元素(终端操作)
T reduce(T identityVal, BinaryOperator<T> accumulator) 基于调用流中的元素返回结果,identityVal会对流中任意元素进行操作,例如加法便是identity+x,乘法是identity*x,这是缩减操作(终端操作)
Optional<T> reduce(BinaryOperator<T> accumulator) 基于accumulator的操作后,返回结果
Stream<T> sorted() 产生一个新流,其中包含按自然顺序排序的调用流的元素(中间操作)
Object[] toArray() 使用调用流的元素创建数组(终端操作)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import java.util.ArrayList;
import java.util.Optional;
import java.util.stream.Stream;

public class LearnStream1
{
public static void main(String args[])
{
ArrayList<Integer> myList = new ArrayList<>();
myList.add(7);
myList.add(18);
myList.add(10);
myList.add(24);
myList.add(17);
myList.add(5);

System.out.println("Original list: " + myList);

Stream<Integer> myStream = myList.stream();

Optional<Integer> minVal = myStream.min(Integer::compare);
if(minVal.isPresent()) {
System.out.println("Minimum values : " + minVal.get());
}

myStream = myList.stream();
Optional<Integer> maxVal = myStream.max(Integer::compare);
if(maxVal.isPresent()) {
System.out.println("Maximum value: " + maxVal.get());
}

Stream<Integer> sortedStream = myList.stream().sorted();

System.out.print("Sorted stream:");
sortedStream.forEach((n)->System.out.print(n + " "));
System.out.println();

Stream<Integer> oddVals = myList.stream().sorted().filter((n)->(n%2)==1);
System.out.print("Odd values: " );
oddVals.forEach((n)->System.out.print(n + " "));
System.out.println();

oddVals = myList.stream().filter((n)->(n % 2) == 1).filter((n)->n>5);
oddVals.forEach((n)->System.out.print(n + " "));
System.out.println();

Optional<Integer> productObj = myList.stream().reduce((a, b)->a*b);
if(productObj.isPresent()) {
System.out.println("Product as Optional:" + productObj.get());
}

int product = myList.stream().reduce(2, (a, b)->a*b);
System.out.println("Product as int :" + product);

// 并行流
double productOfSqrRoots = myList.parallelStream().reduce(1.0, (a,b)->a*Math.sqrt(b), (a,b)->a*b);
System.out.println("Product of square roots: " + productOfSqrRoots);
}
}

映射

将一个流的元素映射到另一个流中,通常使用方法map();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.util.ArrayList;
import java.util.stream.Stream;

class NamePhoneEmail
{
String name;
String phonenum;
String email;

NamePhoneEmail(String n, String p, String e)
{
this.name = n;
this.phonenum = p;
this.email = e;
}
}

class NamePhone
{
String name;
String phonenum;

NamePhone(String n, String p)
{
this.name = n;
this.phonenum = p;
}
}

public class LearnStream2
{
public static void main(String args[])
{
ArrayList<NamePhoneEmail> myList = new ArrayList<>();
myList.add(new NamePhoneEmail("One", "555-1111", "One@HelloWorld.com"));
myList.add(new NamePhoneEmail("Two", "555-2222", "Two@HelloWorld.com"));
myList.add(new NamePhoneEmail("Three", "555-3333", "Three@HelloWorld.com"));

System.out.println("Original values in myList:");
myList.stream().forEach((a)->{
System.out.println(a.name + " " + a.phonenum + " " + a.email);
});

System.out.println();
Stream<NamePhone> nameAndPhone = myList.stream().map((a)->new NamePhone(a.name, a.phonenum));

System.out.println("List of names and phone numbers");
nameAndPhone.forEach((a)->{
System.out.println(a.name + " " + a.phonenum);
});
}
}
  • 基本流使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.ArrayList;
import java.util.stream.IntStream;

public class LearnStream3
{
public static void main(String args[])
{
ArrayList<Double> myList = new ArrayList<>();

myList.add(1.1);
myList.add(3.6);
myList.add(9.2);
myList.add(4.7);
myList.add(12.1);
myList.add(5.0);

System.out.print("Original values in myList:");
myList.stream().forEach((a)->{
System.out.print(a + " ");
});

System.out.println();

IntStream cStr = myList.stream().mapToInt((a)->(int)Math.ceil(a));
System.out.print("The ceilings of the values in myList:");

cStr.forEach((a)->{
System.out.print(a + " ");
});
}
}

集合

很多时候,我们都是从集合中获得流,但是,有时候我们需要执行反操作,从流中获得集合,为此我们需要使用流的<R,A> R collectio(Collector<? super T, A, R> collectorFunc)方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;



class NamePhoneEmail
{
String name;
String phonenum;
String email;

NamePhoneEmail(String n, String p, String e)
{
this.name = n;
this.phonenum = p;
this.email = e;
}
}

class NamePhone
{
String name;
String phonenum;

NamePhone(String n, String p)
{
this.name = n;
this.phonenum = p;
}
}

public class LearnStream4
{
public static void main(String[] args)
{
ArrayList<NamePhoneEmail> myList = new ArrayList<>();
myList.add(new NamePhoneEmail("One", "555-1111", "One@HelloWorld.com"));
myList.add(new NamePhoneEmail("Two", "555-2222", "Two@HelloWorld.com"));
myList.add(new NamePhoneEmail("Three", "555-3333", "Three@HelloWorld.com"));

Stream<NamePhone> nameAndPhone = myList.stream().map((a)->new NamePhone(a.name, a.phonenum));

List<NamePhone> npList = nameAndPhone.collect(Collectors.toList());
System.out.println("Names and phone numbers in a List:");
for(NamePhone e : npList) {
System.out.println(e.name + " : " + e.phonenum);
}

nameAndPhone = myList.stream().map((a)->new NamePhone(a.name, a.phonenum));

Set<NamePhone> npSet = nameAndPhone.collect(Collectors.toSet());

System.out.println("\nNames and phone numbers in ad Set:");
for(NamePhone e : npSet) {
System.out.println(e.name + " : " + e.phonenum);
}
}
}

迭代器

虽然流不是数据存储对象,但是仍然可以使用迭代器来遍历其元素,就如果使用迭代器遍历集合中的元素一样。流支持两类迭代器,一类是传统的Iterator,另一类是新增的Spliterator。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.stream.Stream;

public class LearnStream5
{
public static void main(String[] args)
{
ArrayList<String> myList = new ArrayList<>();
myList.add("one");
myList.add("two");
myList.add("three");
myList.add("four");
myList.add("five");

// Iterator
Stream<String> myStream = myList.stream();
Iterator<String> it = myStream.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}

System.out.println();

// Spliterator
myStream = myList.stream();
Spliterator<String> splIt = myStream.spliterator();
while(splIt.tryAdvance((n)->System.out.println(n)));

// Spliterator2
myStream = myList.stream();
Spliterator<String> splIt2 = myStream.spliterator();
Spliterator<String> splIt3 = splIt2.trySplit();

// 必须先处理拆分的迭代器
if(splIt3 != null) {
splIt3.forEachRemaining((n)->System.out.println("splIt3:" + n));
}

splIt2.forEachRemaining((n)->System.out.println("splIt2:" + n));
}
}