Stream類全路徑為:java.util.stream.Stream
對Stream的描述,引用其他文章中覺得比較好的介紹:
Java 8 中的 Stream 是對集合(Collection)對象功能的增強,它專注於對集合對象進行各種非常便利、高效的聚合操作(aggregate operation),或者大批量數據操作 (bulk data operation)。Stream API 借助於同樣新出現的 Lambda 表達式,極大的提高編程效率和程序可讀性。
即Stream的原理:
這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 並且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等。元素流在管道中經過中間操作(intermediate operation)的處理,最后由最終操作(terminal operation)得到前面處理的結果。
集合有兩種方式生成流:
- stream() − 為集合創建串行流。
- parallelStream() − 為集合創建並行流。
並發模式(parallelStream)能夠充分利用多核處理器的優勢,使用 fork/join 並行方式來拆分任務和加速處理過程。java中也提供了多種並行處理的方式,看到一片文章對各幾種並行的方式性能進行了測試,可以參考下:java中幾種並行方式的性能分析。
Stream的的中間操作(intermediate)和最終操作(terminal)都包含哪些方法可以從類結構中看到:
上面截圖基本包含了Strram的所有方法。
中間操作(intermediate)主要有以下方法(此類型的方法返回的都是Stream對象):
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered終端操作(terminal)主要有以下方法:
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
此處按照類結構(截圖)中的方法的順序(以下例子中使用了Lambda表達式及方法引用,不了解的請戳:Lambda介紹,方法引用),進行介紹:
- filter:通過設置條件來過濾元素。
List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");
list.stream()
.filter((s)->s.contains("a"))
.forEach(s -> System.out.println(s));
以上代碼使用filter方法過濾出只包含”a”的元素,然后通過forEach將滿足條件的元素遍歷出來。輸出如下:
aaa
a2a
a3a
- map:就是將對應的元素使用給定方法進行轉換。
list.stream()
.filter((s)->s.contains("a"))
.map((s)-> s + "---map")
.forEach(s -> System.out.println(s));
在filter的基礎上,給每個元素后面添加字符串”—map”,輸出如下:
aaa—map
a2a—map
a3a—map
- mapToInt:和map方法進行一樣的操作,但是轉換函數必須返回int類型
- mapToLong:和map方法進行一樣的操作,但是轉換函數必須返回long類型
- mapToDouble:和map方法進行一樣的操作,但是轉換函數必須返回double類型
此處以mapToInt進行演示:
list.stream()
.filter((s)->s.contains("a"))
.mapToInt((s)-> s.hashCode())
.forEach(s -> System.out.println(s));
在filter的基礎上,將每個元素轉換為其hashCode。輸出為:
96321
94864
94895
- flatMap:如果流的元素為數組或者Collection,flatMap就是將每個Object[]元素或Collection<Object>元素都轉換為Object元素,如下:
Stream<String[]> 轉換為 Stream<String>
Stream<Set> 轉換為 Stream<String>
Stream<List> 轉換為 Stream<String>
Stream<List> 轉換為 Stream<Object>
看下例子:
List<String[]> setList = new ArrayList<>();
setList.add(new String[]{"aa","bb"});
setList.add(new String[]{"cc","dd"});
setList.add(new String[]{"ee","ff"});
//使用map方法
setList.stream()
.map(s->Arrays.stream(s))
.forEach(s-> System.out.println("map==" + s));
//使用flatMap方法
setList.stream()
.flatMap(s->Arrays.stream(s))
.forEach(s-> System.out.println("flatMap==" + s));
輸出如下:
map==java.util.stream.ReferencePipeline&Head@50040f0c
map==java.util.stream.ReferencePipeline&Head@2dda6444
map==java.util.stream.ReferencePipeline&Head@5e9f23b4
flatMap==aa
flatMap==bb
flatMap==cc
flatMap==dd
flatMap==ee
flatMap==ff
可以看出map就是將數組流直接返回,flatMap是將數組流中的每個元素都返回。flatMapToInt,flatMapToLong,flatMapToDouble類似,只不過返回的是對應的類型的流,此處不做演示。
- distinct:將集合中的元素去重。
List<String> disList = Arrays.asList("aaa","ddd","bbb","ddd","aaa");
disList.stream()
.distinct()
.forEach(s-> System.out.println(s));
輸出如下:
aaa
ddd
bbb
- sorted:將集合中的元素排序。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream()
.sorted()
.forEach(s-> System.out.println(s));
輸出如下:
1
2
3
4
可以按照自定義排序:
integerList.stream()
.sorted((s1,s2)->s2.compareTo(s1))
.forEach(s-> System.out.println(s));
輸出如下:
4
3
2
1
- peek:生成一個包含原Stream的所有元素的新Stream,同時會提供一個消費函數即引用的方法A,當Stream每個元素被消費的時候都會先執行新Stream給定的方法A。peek是中間操作,如果pee后沒有最終操作,則peek不會執行。
integerList.stream()
.peek(s-> System.out.println("peek = "+s));
此時沒有輸出,代碼改為:
integerList.stream()
.peek(s-> System.out.println("peek = "+s))
.forEach(s-> System.out.println("forEach = "+s));
輸出如下:
peek = 1
forEach = 1
peek = 2
forEach = 2
peek = 3
forEach = 3
peek = 4
forEach = 4
- limit:返回Stream的前n個元素。
integerList.stream()
.limit(1)
.forEach(s-> System.out.println(s));
輸出為:
1
- skip:刪除Stream的前n個元素。
integerList.stream()
.skip(1)
.forEach(s-> System.out.println(s));
輸出如下:
2
3
4
- forEach:遍歷Stream中的每個元素,前面每個例子都有使用,此處不再演示。
- forEachOrdered:遍歷Stream中的每個元素。
區別:
在串行流(stream)中沒有區別,在並行流(parallelStream)中如果數據源是有序集合,forEachOrdered輸出順序與數據源中順序一致,forEach則是亂序。
看下使用forEach:
integerList.stream()
.forEach(s-> System.out.println(s));
輸出(多次測試,每次結果都不一樣):
3
1
4
2
再看使用forEachOrdered:
integerList.parallelStream()
.forEachOrdered(s-> System.out.println(s));
輸出(測試多次,每次都是這個結果,與integerList中的元素順序一致):
2
1
3
4
- toArray:將流轉換為Object[]或者指定類型的數組。
Object[] array = integerList.stream().toArray();
String[] strArr = integerList.stream().toArray(String[]::new);
- reduce:將集合中的每個元素聚合成一條數據。有三種情況:
- reduce(BinaryOperator accumulator):此處需要一個參數,返回Optional對象:
Optional<Integer> reduce = integerList.stream().reduce((a, b) -> a + b);
- 1
- reduce(T identity, BinaryOperator accumulator):此處需要兩個參數,第一個參數為起始值,第二個參數為引用的方法。從起始值開始,每個元素執行一次引用的方法(方法引用的中的兩個參數:第一個參數為上個元素執行方法引用的結果,第二個參數為當前元素)。
int integer = integerList.stream().reduce(5,(a, b) -> a + b);
System.out.println(integer);
輸出為:
15
此例中使用起始值為5,對集合中每個元素求和,可以理解為:5+2+1+3+4=15。
- reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner):此處需要三個參數。此方法用在並發流(parallelStream)中,啟動多個子線程使用accumulator進行並行計算,最終使用combiner對子線程結果進行合並,返回identity類型的數據,看到有篇文章對這個解釋比較清楚:java8中3個參數的reduce方法怎么理解?
- collect:將流轉換成集合或聚合元素。有兩種情況。接受一個參數和接受三個參數(三個參數在並發流parallelStream中使用),此處介紹一個參數的情況,單個參數接受的參數類型為Collector,Collectors 類實現了很多歸約操作,詳見:java8之collector
List<Integer> collects = integerList.stream()
.filter(a -> a > 1)
.collect(Collectors.toList());
System.out.println(collects);
此處統計集合中大於1的元素並最終返回list。輸出如下:
[2, 3, 4]
- min:獲取集合中最小值。
Integer min = integerList.stream()
.filter(a -> a > 1)
.min((Integer a, Integer b) -> a.compareTo(b))
.get();
System.out.println(min);
輸出為:
2
- max:獲取集合中最大值。
Integer max = integerList.stream()
.filter(a -> a > 1)
.max((Integer a, Integer b) -> a.compareTo(b))
.get();
System.out.println(max);
輸出為:
4
- count:獲取集合中元素個數
long count = integerList.stream()
.filter(a -> a > 1)
.count();
System.out.println(count);
輸出為:
3
- anyMatch: Stream 中任意一個元素符合傳入的 predicate,返回 true
- allMatch:Stream 中全部元素符合傳入的 predicate,返回 true
- noneMatch:Stream 中沒有一個元素符合傳入的 predicate,返回 true
boolean b = integerList.stream()
.anyMatch(s -> s > 0);
boolean b1 = integerList.stream()
.allMatch(s -> s > 0);
boolean b2 = integerList.stream()
.noneMatch(s -> s > 0);
System.out.println("anyMatch = " + b);
System.out.println("allMatch = " + b1);
System.out.println("noneMatch = " + b2);
輸出:
anyMatch = true
allMatch = true
noneMatch = false
- findFirst:如果數據源是有序集合,返回Stream 中第一個元素的Optional對象,如果是無序集合,則返回Stream 中任意一個元素的Optional對象。
Integer first = integerList.stream()
.findFirst()
.get();
System.out.println(first);
輸出為:
2
- findAny:返回Stream 中任意一個元素的Optional對象。
Integer any = integerList.stream()
.findAny()
.get();
System.out.println(any);
輸出為:
2
Stream還有幾個靜態方法,返回都是Stream對象。
靜態方法如下:builder(返回Builder對象)、empty、of、iterate、generate、concat。
builder:返回一個Builder對象,Builder對象在調用build()返回Stream對象。
empty:返回一個空的有序的Stream對象。
of:返回包含單個元素的有序的Stream對象。
iterate:返回一個無限元素的有序的Stream對象。需要兩個參數,第一個參數為初始值,第二個參數為要引用的方法,然后會通過遞歸循環調用引用的方法。
Stream.iterate(2,s->s+s)
.limit(10)
.forEach(s-> System.out.println(s));
輸出為:
2
4
8
16
32
64
128
256
512
1024
generate:返回一個無限元素的無序的的Stream對象。需要一個參數,參數為引用的方法,然后會通過循環調用引用的方法來生成元素,常用於生成常量Stream和隨機元素Stream。
concat:將兩個Stream連接成一個Stream。需要兩個Stream作為參數,如果兩個Stream都是有序的並且無論參數Stream是否是並行Stream,得到的都是有序的Stream。輸出元素順序為先輸出第一個Stream的元素,然后輸出第二個Stream的元素。當結果Stream關閉時候,兩個參數Stream同時關閉。
Stream.concat(integerList.stream(),disList.stream())
.forEach(s-> System.out.println(s));
輸出為:
原文地址:https://blog.csdn.net/bluuusea/article/details/799670392
1
3
4
11
aaa
ddd
33
bbb
ddd
aaa