精華筆記: package:聲明包 作用:避免類的命名衝突 同包中的類不能同名,但不同包中的類可以同名 類的全稱:包名.類名,包名常常有層次結構 建議:包名所有字母都小寫 import:導入類 同包中的類可以直接訪問 不同包中的類不能直接訪問,若想訪問: 先import導入類再使用類 建議 類的全稱 ...
目錄
一、什麼是Stream
Stream是java8的新增特性,表示數據流。
二、Stream的特點
- 不存儲數據:流是基於數據源的對象,本身不存儲數據。
- 函數式編程:流的操作不會修改數據源。
- 延遲操作:流的很多操作如
filter
、map
是延遲執行的,只有到了終點操作才會將操作順序執行。 - 可以解綁:對於無線數量的流,有些操作(如
limit(n)
、findFirst()
)可以實現“短路操作”,訪問到有限的元素後就可以返回。 - 純消費:流只能被消費一次。如果使用完了一次流,仍然用這個流對象來操作時,會報異常。
串並行
所有的流操作都可以串列執行或者並行執行。除非顯示的創建並行流,否則預設創建串列流。
串列:Collection.stream()
、IntStream.range(int, int)
並行:Collection.parallelStream()、
通過
parallel()
方法可以將串列流轉換為並行流,sequential()
方法將流轉換為串列流
干擾數據源
流可以從非線程安全的集合中創建。當流執行時,非併發的數據源不應該改變,否則會拋出java.util.ConcurrentModificationException
異常。
無狀態
大部分流的操作的參數都是函數式介面,可以使用Lambda表達式實現。它們用來描述用戶的行為,稱之為行為參數(behavioral parameters)。
如果這些行為參數有狀態,則流的操作的結果可能是不確定的,比如下麵的代碼:
下麵代碼在並行執行時,由於執行順序的不確定性,state.s的改變時機可能不同,導致多次執行時的結果不同
List<String> l = new ArrayList(Arrays.asList("one", "two", ……));
class State {
boolean s;
}
final State state = new State();
Stream<String> sl = l.stream().map(e -> {
if (state.s)
return "OK";
else {
state.s = true;
return e;
}
});
sl.forEach(System.out::println);
排序
某些流的返回元素是有確定順序的。這取決於它的數據源和中間操作。
比如List和Array創建的流是有序的,而HashSet創建的流是無序的。
sort()
方法可以將流變得有序,而unordered()
可以將流無序(不會打散元素)
當流有序時,如果用戶並不關心順序,可以使用unordered
顯示的去掉流的有序約束,可以改善某些情況下的並行性能
三、創建Stream
常見創建流的方法:
- 通過集合Collection的
Stream()
或parallelStream()
:如list.parallelStream()、Arrays.asList(1,2,3).stream()。 - 通過數組
Arrays.stream(Object[])
方法:如Arrays.stream(new int[]{1,2,3})。 - 流的靜態方法:如:
Stream.of(Object[])
、IntStream.range(int, int)
、Stream.iterate(Object, UnaryOperator)。
- 隨機數流
Random.ints()
。
四、中間操作
中間操作是延遲執行的,不會修改原始數據流,在終點操作開始時才會開始執行
1. distinct
根據流中元素的hashCode()
和equals()
方法去除重覆元素
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().distinct().forEach(System.out::print); // 123456
System.out.println();
list.forEach(System.out::print); // 12344456
2. filter
接收predicate
,過濾數據
// 篩選出偶數
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().filter(e -> e % 2 == 0).forEach(System.out::print); // 24446
3. map
接收一個Function
實例,重新印射數據
// 加1
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().map(e -> e + 1).forEach(System.out::print); // 23455567
4. mapToDouble
類似map,不過結果一定要是Double類型。
類似的方法還有mapToInt()
,mapToLong()
// 加1.1
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().mapToDouble(e -> e + 1.1).forEach(System.out::println);
/*
2.1
3.1
4.1
5.1
5.1
5.1
6.1
7.1
*/
// 加1
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().mapToDouble(e -> e + 1).forEach(System.out::println);
/*
2.0
3.0
4.0
5.0
5.0
5.0
6.0
7.0
*/
4. flatmap
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
將映射後的元素放在一個新的流中。
類似的方法還有flatMapToDouble
、flatMapToInt
、flatMapToLong
List<String> list = Arrays.asList("1233", "2444", "562","78");
list.stream()
.flatMap(e -> Arrays.stream(e.split("2")))
.forEach(System.out::println);
/*
1
33
444
56
78
*/
5. limit
限制流中元素的數量。對於有序並行流,性能消耗更高
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().limit(5).forEach(System.out::print); // 12344
6. skip
丟棄前n個元素,返迴流。
System.out.println("-----------------------");
list.stream().skip(6).forEach(System.out::println);
System.out.println("-----------------------");
list.stream().skip(8).forEach(System.out::println);
/*
7
5
-----------------------
-----------------------
*/
7. peek
接收一個Consumer,對元素做某些操作,但是並不會修改數據(對象數據可能會被修改)。一般用於debug
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
list.stream().peek(System.out::print).count(); // 810975
8. sorted
將流中的元素按自然順序排序。可以自定義比較器。
System.out.println("升序: ");
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
list.stream().sorted().forEach(System.out::print);
System.out.println();
System.out.println("降序: ");
list.stream().sorted((x, y) -> y - x).forEach(System.out::print);
/*
升序:
015789
降序:
987510
*/
五、終點操作
1. Match
有allMatch(Predicate p)
、anyMatch(Predicate p)
、noneMatch(Predicate p)
三種方法。
返回boolean。
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
// allMatch 是否全部符合
System.out.println(list.stream().allMatch(x -> x > -1)); // true
System.out.println(list.stream().allMatch(x -> x > 1)); // false
// anyMatch 是否至少有一個符合
System.out.println(list.stream().anyMatch(x -> x == -1)); // false
System.out.println(list.stream().anyMatch(x -> x == 1)); // true
// noneMatch 是否全部不符合
System.out.println(list.stream().noneMatch(x -> x > 5)); // false
System.out.println(list.stream().noneMatch(x -> x > 9)); // true
2. count
返迴流中元素的數量。返回long
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
System.out.println(list.stream().count()); // 6
3. collect
傳入Collectors中的介面實現,將流轉化為其他形式的數據。部分介面:
toList
、toSet
轉化為list或setcounting
計數reducing
化簡maxBy
、minBy
最大值最小值summingInt
求和joining
字元串連接
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
// 轉化為list格式
List<Integer> res1 = list.stream().collect(Collectors.toList());
// 轉化為set格式
Set<Integer> res2 = list.stream().collect(Collectors.toSet());
4. find
有findFirst()和findAny()兩種。返回Optional對象
Optional<T> findFirst();
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
Optional<Integer> integer = list.stream().findFirst();
System.out.println(integer.get()); // 8
// findAny()對於串列流:一般返回第一個結果
integer = list.stream().findAny();
System.out.println(integer.get()); // 8
// findAny()對於並行流,多次執行會隨機返回結果
integer = list.parallelStream().findAny();
System.out.println(integer.get()); // 隨機列印
5. forEach
遍歷流中元素,執行指定操作
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
List<Integer> res = new ArrayList<>();
list.stream().forEach(e -> res.add(e + 2));
System.out.println(list.toString());
// [10, 3, 2, 11, 9, 7]
6. max、min
最大值、最小值。返回Optional對象
將元素按比較器排序,然後min返回第一個數,max返回最後一個數
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
// 升序排序 015789
System.out.println(list.stream().min((x, y) -> x - y).get()); // 0
System.out.println(list.stream().max((x, y) -> x - y).get()); // 9
// 降序排序 987510
System.out.println(list.stream().min((x, y) -> y - x).get()); // 9
System.out.println(list.stream().max((x, y) -> y - x).get()); // 0
7. reduce
將元素數據結合後返回。
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
// 預設返回Optional類型數據
Optional<Integer> res1 = list.stream().reduce(Integer::sum);
System.out.println(res1.get());
// 指定返回數據類型為Integer
Integer res2 = list.stream().reduce(0, Integer::sum);
System.out.println(res2);
8. toArray()
將流中的元素保存到數組中
<A> A[] toArray(IntFunction<A[]> generator);
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
Integer[] ints = list.stream().map(e -> e + 1).toArray(Integer[]::new);
for (Integer integer : ints) {
System.out.println(integer);
}
/*
9
2
1
10
8
6
*/