Java 8

Stream API

為什麼需要

Stream API

Steam API 的作用

  • Functional Prgroamming 的大力發展
  • Steam API 讓迴圈的循環能更寫得更優雅
  • Stream 的寫法會引導開發者降低程式的耦合度
  • Stream 讓平行擴展變的相當容易

Steam API 的缺點

  • 開發者需要調整開發的想法
  • 相較一個簡單的 for ,效能是會比較差的。
  • 除錯相對會比較困難一點

先來一段

Code 

這段 Code 的作用?

public class StreamDemo {

    public static void main(String[] args) throws IOException {

        String fileName = "C:\\temp\temp.txt";
        List<String> strings = Files.readAllLines(Paths.get(fileName));
        List<String> result = new ArrayList<>();

        for (String line : strings) {
            if(line.startsWith("2019.09")) {
                result.add(line);
            }
        }

        for (String s : result) {
            System.out.println(s);
        }
    }

}

比較

        
// 單純的 For 迴圈
List<String> result = new ArrayList<>();
for (String line : strings) {
    if(line.startsWith("2019.09")) {
        result.add(line);
    }
}

// Java 8 Stream API 的寫法
 List<String> streamResult = Files.lines(path)
      .filter(line -> line.startsWith("2019.09"))
      .collect(Collectors.toList());

Java Stream API 使用流程

  1. 取得 Stream
  2. 執行 0 到多個 中繼操作
  3. 執行 結束操作

Java Stream 圖解

取得 Stream 的方法 

建立 Collection 的 Stream

Collection<String> collection = Arrays.asList("a", "b", "c");

Stream<String> streamOfCollection = collection.stream();

建立 Array 的 Stream

String[] arr = new String[]{"a", "b", "c"};
Stream<String> streamOfArrayFull = Arrays.stream(arr);
Stream<String> streamOfArrayPart = Arrays.stream(arr, 1, 3);

建立 Files 的 Stream

Path path = Paths.get("C:\\file.txt");

Stream<String> streamOfStrings = Files.lines(path);

Steam 的中介動作

filter()

Stream<String> longStringsStream = stream.filter((value) -> {
    return value.length() >= 3;
});

map()

List<String> list = new ArrayList<String>();
Stream<String> stream = list.stream();

Stream<String> streamMapped = 
		stream.map((value) -> value.toUpperCase());

flatMap()

List<String> stringList = new ArrayList<String>();

stringList.add("One flew over the cuckoo's nest");
stringList.add("To kill a muckingbird");
stringList.add("Gone with the wind");

Stream<String> stream = stringList.stream();

stream.flatMap((value) -> {
    String[] split = value.split(" ");
    return (Stream<String>) Arrays.asList(split).stream();
}).forEach((value) -> System.out.println(value));

distinct()

List<String> stringList = new ArrayList<String>();

stringList.add("one");
stringList.add("two");
stringList.add("three");
stringList.add("one");

Stream<String> stream = stringList.stream();

List<String> distinctStrings = stream
        .distinct()
        .collect(Collectors.toList());

System.out.println(distinctStrings);

limit()

List<String> stringList = new ArrayList<String>();

stringList.add("one");
stringList.add("two");
stringList.add("three");
stringList.add("one");

Stream<String> stream = stringList.stream();
stream
    .limit(2)
    .forEach( element -> { System.out.println(element); });    

peek()

List<String> stringList = new ArrayList<String>();

stringList.add("abc");
stringList.add("def");

Stream<String> stream = stringList.stream();

Stream<String> streamPeeked = stream.peek((value) -> {
    System.out.println("value");
});

Steam 的結尾動作

collect()

List<String> stringList = new ArrayList<String>();

stringList.add("One flew over the cuckoo's nest");
stringList.add("To kill a muckingbird");
stringList.add("Gone with the wind");

Stream<String> stream = stringList.stream();

List<String> stringsAsUppercaseList = stream
.map(value -> value.toUpperCase())
.collect(Collectors.toList());

System.out.println(stringsAsUppercaseList);

foreach()

List<String> stringList = new ArrayList<String>();

stringList.add("one");
stringList.add("two");
stringList.add("three");
stringList.add("one");

Stream<String> stream = stringList.stream();

stream.forEach( element -> { System.out.println(element); });

anyMatch()

List<String> stringList = new ArrayList<String>();

stringList.add("One flew over the cuckoo's nest");
stringList.add("To kill a muckingbird");
stringList.add("Gone with the wind");

Stream<String> stream = stringList.stream();

boolean anyMatch = 
    stream.anyMatch((value) -> { 
    	return value.startsWith("One"); 
    });
System.out.println(anyMatch);

anyMatch()

List<String> stringList = new ArrayList<String>();

stringList.add("One flew over the cuckoo's nest");
stringList.add("To kill a muckingbird");
stringList.add("Gone with the wind");

Stream<String> stream = stringList.stream();

boolean allMatch = 
	stream.allMatch((value) -> { 
    	return value.startsWith("One"); 
    });
System.out.println(allMatch);

noneMatch()

List<String> stringList = new ArrayList<String>();

stringList.add("abc");
stringList.add("def");

Stream<String> stream = stringList.stream();

boolean noneMatch = stream.noneMatch((element) -> {
    return "xyz".equals(element);
});

System.out.println("noneMatch = " + noneMatch);

count()

List<String> stringList = new ArrayList<String>();

stringList.add("One flew over the cuckoo's nest");
stringList.add("To kill a muckingbird");
stringList.add("Gone with the wind");

Stream<String> stream = stringList.stream();

long count = stream.flatMap((value) -> {
    String[] split = value.split(" ");
    return (Stream<String>) Arrays.asList(split).stream();
})
.count();

System.out.println("count = " + count);

findAny()

List<String> stringList = new ArrayList<String>();

stringList.add("one");
stringList.add("two");
stringList.add("three");
stringList.add("one");

Stream<String> stream = stringList.stream();

Optional<String> anyElement = stream.findAny();

System.out.println(anyElement.get());

findFirst()

List<String> stringList = new ArrayList<String>();

stringList.add("one");
stringList.add("two");
stringList.add("three");
stringList.add("one");

Stream<String> stream = stringList.stream();

Optional<String> result = stream.findFirst();

System.out.println(result.get());

min()

List<String> stringList = new ArrayList<String>();

stringList.add("abc");
stringList.add("def");

Stream<String> stream = stringList.stream();

Optional<String> min = stream.min((val1, val2) -> {
    return val1.compareTo(val2);
});

String minString = min.get();

System.out.println(minString);

max()

List<String> stringList = new ArrayList<String>();

stringList.add("abc");
stringList.add("def");

Stream<String> stream = stringList.stream();

Optional<String> max = stream.max((val1, val2) -> {
    return val1.compareTo(val2);
});

String maxString = max.get();

System.out.println(maxString);

reduce()

List<String> stringList = new ArrayList<String>();

stringList.add("One flew over the cuckoo's nest");
stringList.add("To kill a muckingbird");
stringList.add("Gone with the wind");

Stream<String> stream = stringList.stream();

Optional<String> reduced = stream.reduce(
    (value, combinedValue) -> {
    return combinedValue + " + " + value;
});

System.out.println(reduced.get());

toArray()

List<String> stringList = new ArrayList<String>();

stringList.add("One flew over the cuckoo's nest");
stringList.add("To kill a muckingbird");
stringList.add("Gone with the wind");

Stream<String> stream = stringList.stream();

Object[] objects = stream.toArray();

Example

private Double getActualEffectiveEsdaya(String esdaysGrid, 
							Timestamp resignDate) throws Exception{
		
	List<EsdaysYear> esdaysYear = esdaysEBO.getEsdaysYearByEffectiveDate(esdaysGrid, resignDate);

	// Before Java 8 
	Double actualDays = 0.0;
	for(int i = 0 ; i < esdaysYear.size() ; i++ ){
		actualDays += esdaysYear.get(i).getDays();
		actualDays += esdaysYear.get(i).getPendingDays();
	}
 
 	// After Java 8 
	double actutal  = esdaysYear.stream()
			.mapToDouble(esdaysYearItem -> esdaysYearItem.getDays() + esdaysYearItem.getPendingDays())
			.sum();

	return actualDays;
}

Java 8 Stream

By Balicanta Yao

Java 8 Stream

  • 116