1. 程式人生 > >JDK8 Stream 初識

JDK8 Stream 初識

點這裡
Stream作為jdk8的一種重要特性,我們應該瞭解多一些。

為什麼會有Stream?

在Stream出現之前,我們對集合中的元素進行一些操作需要先遍歷每個元素再進行操作。如:

	  LinkedHashMap<String, Integer> linkedHashMap =  new LinkedHashMap<String, Integer>();
	  linkedHashMap.put("1", 1);
	  linkedHashMap.put("2", 2);
	  linkedHashMap.put("3", 3);
	  linkedHashMap.put("4", 4);
	  LinkedHashMap<String, Integer> linkedHashMap2 =  new LinkedHashMap<String, Integer>();	  
	  for (Entry entry : linkedHashMap.entrySet()) {
		  int v = (int)entry.getValue();
		linkedHashMap2.put((String)entry.getKey(), v*2);
	}
	//結果:
	//[1=1, 2=2, 3=3, 4=4]
	//[1=2, 2=4, 3=6, 4=8]

在1.8我們怎麼實現呢?

HashMap<String, Integer> hashMap = (HashMap<String, Integer>) linkedHashMap
				.entrySet()
				.stream()
				.collect(
						Collectors.toMap(a -> a.getKey(), a -> a.getValue() * 2));
System.out.println(hashMap.entrySet());
//[1=2, 2=4, 3=6, 4=8]

當你熟練掌握stream用法時,對集合的操作就很方便簡單了。

什麼是Stream?

點這裡
Stream 是用函數語言程式設計方式在集合類上進行復雜操作的工具,其集成了Java 8中的眾多新特性之一的聚合操作,開發者可以更容易地使用Lambda表示式,並且更方便地實現對集合的查詢、遍歷、過濾以及常見計算等。

集合講的是資料,流講的是計算

1> Stream 自己不會儲存元素
2> Stream 不會改變源物件。相反,他們會返回一個持有結果的新Stream
3> Stream 操作是延遲執行的。這意味著他們會等到需要結果的時候才執行

Stream 的操作三個步驟
1> 建立 Stream : 一個數據源 (如 : 集合、陣列), 獲取一個流
2> 中間操作 : 一箇中間操作鏈,對資料來源的資料進行處理
3> 終止操作(終端操作) : 一個終止操作,執行中間操作鏈,併產生結果

建立流:

  1. collection中擴充套件了default 方法
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
collection.stream()
collection.parallelStream()
  1. Arrays 類中增加了 stream() 靜態方法
    public static <T> Stream<T> stream(T[] array) {
        return stream(array, 0, array.length);
    }
	Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5, 6);
	int [] a = {1,2,3};
	IntStream aStream= Arrays.stream(a);

還有幾種建立方法我沒有掌握,讀者可以點選上面的連線檢視。

Stream的操作

操作型別 介面方法
中間操作 concat() distinct() filter() flatMap() limit() map() peek()skip() sorted() parallel() sequential() unordered()
結束操作 allMatch() anyMatch() collect() count() findAny() findFirst() forEach() forEachOrdered() max() min() noneMatch() reduce() toArray()
  • 1 中間操作
方 法 描 述
切片
filter(Predicate p) 接收 Lambda , 從流中排除某些元素
distinct() 篩選,通過流所生成元素的 hashCode() 和 equals() 去除重複元素
limit(long maxSize) 保留前n個
skip(long n) 去掉前n個
對映
map(Function f) 接收一個函式作為引數,該函式會被應用到每個元素上,並將其對映成一個新的元素
mapToDouble(ToDoubleFunction f) 接收一個函式作為引數,該函式會被應用到每個元素上,產生一個新的 DoubleStream
mapToInt(ToIntFunction f) 接收一個函式作為引數,該函式會被應用到每個元素上,產生一個新的 IntStream
mapToLong(ToLongFunction f) 接收一個函式作為引數,該函式會被應用到每個元素上,產生一個新的 LongStream
flatMap(Function f) 接收一個函式作為引數,將流中的每個值都換成另一個流,然後把所有流連線成一個流
排序
sorted() 產生一個新流,其中按自然順序排序
sorted(Comparator comp) 產生一個新流,其中按比較器順序排序

我們來寫一些例子加深印象,由於是中間方法所以在結尾加了foreach(終止方法)

//原資料
List<String> arrayList =Arrays.asList("1","2","3","3","4","5");
List<String> arrayList2 = Arrays.asList("a", "b", "c", "d", "e", "f");
  • 切片型

過濾filter

arrayList.stream().filter(e->e.equals("3")).forEach(System.out::println);
//3 3

刪除重複distinct

arrayList.stream().distinct().forEach(System.out::println);
//1 2 3 4 5

篩選limit

arrayList.stream().limit(3).forEach(System.out::println);
//1 2 3

跳過skip

arrayList.stream().skip(4).forEach(System.out::println);
//4 5 
  • 對映型

map

arrayList.stream().map(e->e+"A").forEach(System.out::println);
//1A 2A 3A 3A 4A 5A

mapToInt/mapToDouble/mapToLong

arrayList.stream().mapToInt(e -> Integer.parseInt(e))
	.filter(e -> e==3).forEach(System.out::println);
//3 3

flatMap

Stream.of(arrayList, arrayList2).flatMap(u -> u.subList(0, 2).stream())
				.forEach(System.out::println);
//1 2 a b
  • 排序型

sorted

List<String> arrayList3 = Arrays.asList("9", "2", "3", "3", "4", "1");
arrayList3.stream().sorted().forEach(System.out::println);
// 1 2 3 3 4 9
arrayList3.stream().sorted((x, y) -> {
			return x.compareTo(y);
		}).forEach(System.out::println);
// 1 2 3 3 4 9

我好像對compareto,compareable,comparetor 是不是很懂,明天整理下

  • 2 終止操作
方 法 描 述
allMatch(Predicate p) 檢查是否匹配所有元素
anyMatch(Predicate p) 檢查是否至少匹配一個元素
noneMatch(Predicate p) 檢查是否沒有匹配所有元素
findFirst() 返回第一個元素
findAny() 返回當前流中的任意元素
count() 返回流中元素總數
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
forEach(Consumer c) 內部迭代(使用 Collection 介面需要使用者去做迭代,稱為外部迭代。相反, Stream API 使用內部迭代)
歸納
reduce(T iden, BinaryOperator b) 可以將流中元素反覆結合起來,得到一個值,返回 T
reduce(BinaryOperator b) 可以將流中元素反覆結合起來,得到一個值,返回 Optional
收集
collect(Collector c) 將流轉換為其他形式。接收一個 Collector介面的實現,用於給Stream中元素做彙總的方法

我們再來對終止操作進行舉例:

reduce 將元素值結合起來

String sum =  arrayList.stream().reduce( "",(x,y)->(x+y) );
Optional<String> sum2 =  arrayList.stream().reduce((x,y)->(x+y) );
System.out.println( "Sum:  "+sum+"  Sum2:   "+ sum2 );
//Sum:  123345  Sum2:   Optional[123345]

anymatch/allmatch/nomatch

boolean flag = arrayList.stream().anyMatch(e->e.equals("1"));
System.err.println(flag);
// true

count

long num = arrayList.stream().count();
System.err.println("num: "+num+"  size: "+arrayList.size());

collection

		Map<String, List<String> > resultmap=arrayList.stream().collect(Collectors.groupingBy(e->{
			if ( e.equals("1") ) {
				return "ok";				
			}
			else {
				return e;
			}
			
		}));
						
		for (Entry entry : resultmap.entrySet()) {
			System.out.println(entry.getKey()+"   "+entry.getValue());
		}
		
//2   [2]
//3   [3, 3]
//4   [4]
//5   [5]
//ok   [1]