流
流是数据的渠道,因此,流代表了一个对象序列。流操作数据源,如数组或集合。流本身不存储数据,而只是移动数据,在移动过程中可能会堆数据执行过滤、排序或其他操作。然而,一般来说,流操作本身不修改数据源。
BaseStream
BaseStream定义了所有流都可以使用的基本功能。它是一个泛型接口。
方法 |
描述 |
interface BaseStream<T, S extends BaseStream<T, S>> |
T指定流中元素的类型,S指定扩展了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的子接口。
方法 |
描述 |
<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"); Stream<String> myStream = myList.stream(); Iterator<String> it = myStream.iterator(); while(it.hasNext()) { System.out.println(it.next()); } System.out.println(); myStream = myList.stream(); Spliterator<String> splIt = myStream.spliterator(); while(splIt.tryAdvance((n)->System.out.println(n))); 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)); } }
|