Java 8 API添加了一個新的抽象稱爲流Stream,可讓你以一種聲明的方式處理數據。java
這種風格將要處理的元素集合看做一種流, 流在管道中傳輸, 而且能夠在管道的節點上進行處理, 好比篩選, 排序,聚合等。ide
元素流在管道中通過中間操做的處理,最後由最終操做獲得前面處理的結果。this
簡單描述一下大概是這樣:3d
如今有一個字符串集合,咱們須要過濾掉集合裏頭長度小於2的字符串:調試
public static void main( String[] args ) { List<String> strings = Arrays.asList("ab", "", "bc", "cd", "abcd","", "jkl"); List<String> stringList = new ArrayList<>(); for (String str : strings){ //若是長度大於2 if (str.length() >= 2){ //將字符串添加至新集合 stringList.add(str); } } strings = stringList; }
若是使用stream實現如出一轍的效果:code
public static void main( String[] args ) { List<String> strings = Arrays.asList("ab", "", "bc", "cd", "abcd","", "jkl"); //經過stream操做集合 strings = strings.stream() //去掉長度小於2的字符串 .filter(s -> s.length() >= 2) //轉回集合 .collect(Collectors.toList()); }
可見,使用streamAPI能夠輕鬆寫出更高效,更簡潔,可讀性更強的代碼orm
簡單的說,分兩步:生成流,操做流對象
Stream 的建立須要指定一個數據源,好比 java.util.Collection的子類,List或者Set, 不支持Mapblog
1.1 Collection接口的stream()或parallelStream()方法排序
//將Set或List集合直接轉換爲stream對象 List<Person> personList = new ArrayList<>(); Set<Person> set = new HashSet<>(); Stream<Person> personStream1 = personList.stream();//生成串行流 Stream<Person> personStream2 = set.parallelStream();//生成並行流
1.2 Stream.of(),Arrays.stream,Stream.empty()方法
String[] strArr = {"a","a","a","a","a","a"}; //Stream.empty() Stream<Integer> integerStream = Stream.empty(); //Stream.of() (方法內部調用的仍是Arrays.stream) Stream<String> stringStream = Stream.of(strArr); //Arrays.stream Stream<String> stringStream2 = Arrays.stream(strArr);
1.3 Stream.concat()方法
//已有的對象 Stream<Integer> integerStream = Stream.empty(); Stream<String> stringStream = Stream.of(strArr); Stream<String> stringStream2 = Arrays.stream(strArr); //合併兩個流 Stream conStream1 = Stream.concat(stringStream,integerStream); Stream conStream2 = Stream.concat(stringStream,stringStream2);
1.4 靜態的Files.lines(path)
File file = new File("D://test.txt"); Stream<String> lines = Files.lines(file);
Stream 操做分爲中間操做或者最終操做兩種,最終操做返回一特定類型的計算結果,而中間操做返回Stream自己,能夠在後頭跟上其餘中間操做
//接下來的示例代碼基於此集合 List<String> strings = Arrays.asList("ab", "", "bc", "cd", "abcd","", "jkl");
2.1 filter(Predicate:將結果爲false的元素過濾掉
//去掉長度小於2的字符串 strings = strings.stream() .filter(s -> s.length() >= 2) //返回集合 .collect(Collectors.toList()); System.out.println(strings); //打印strings [ab, bc, cd, abcd, jkl]
2.2 map(fun):轉換元素的值,能夠用方法引元或者lambda表達式
strings = strings.stream() //爲每一個字符串加上「???」 .map(s -> s += "???") //返回集合 .collect(Collectors.toList()); System.out.println(strings); //打印strings [ab???, ???, bc???, cd???, abcd???, ???, jkl???]
2.3 limit(n):保留前n個元素
strings = strings.stream() //保留前3個 .limit(3) //返回集合 .collect(Collectors.toList()); System.out.println(strings); //打印strings [ab, , bc]
2.4 skip(n):跳過前n個元素
strings = strings.stream() //跳過前2個 .skip(2) //返回集合 .collect(Collectors.toList()); System.out.println(strings); //打印strings [bc, cd, abcd, , jkl]
2.5 distinct():剔除重複元素
strings = strings.stream() //過濾重複元素 .distinct() //返回集合 .collect(Collectors.toList()); System.out.println(strings); //打印strings(過濾掉了一個空字符串) [ab, , bc, cd, abcd, jkl]
2.6 sorted():將Comparable元素的流排序
strings = strings.stream() //按字符串長度排序 .sorted( //比較字符串長度 Comparator.comparing(s -> s.length()) ) //返回集合 .collect(Collectors.toList()); System.out.println(strings); //打印strings(過濾掉了一個空字符串) [, , ab, bc, cd, jkl, abcd]
2.7 peek(fun):流不變,但會把每一個元素傳入fun執行,能夠用做調試
strings = strings.stream() //爲字符串增長「???」 .peek(s -> s += "???") //返回集合 .collect(Collectors.toList()); System.out.println(strings); //打印strings,和map對比,實際並無改變集合 [ab, , bc, cd, abcd, , jkl]
2.8 flatMap(fun):若元素是流,將流攤平爲正常元素,再進行元素轉換
//將具備多重嵌套結構的集合扁平化 //獲取一個兩重集合 List<String> strings = Arrays.asList("ab", "", "bc", "cd", "abcd","", "jkl"); List<String> strings2 = Arrays.asList("asd", "", "bzxasdc", "cddsdsd", "adsdsg","", "jvcbl"); List<List<String>> lists = new ArrayList<>(); lists.add(strings); lists.add(strings2); //獲取將兩重集合壓成一層 List<String> stringList = lists.stream() //將兩重集合的子元素,即集合strings和strings2轉成流再平攤 .flatMap(Collection::stream) //返回集合 .collect(Collectors.toList()); System.out.println(stringList); //打印stringList [ab, , bc, cd, abcd, , jkl, asd, , bzxasdc, cddsdsd, adsdsg, , jvcbl]
2.9 anyMatch(fun),allMatch(fun):判斷流中的元素是否匹配 【最終操做】
//allMatch Boolean isAllMatch = strings.stream() //判斷元素中是否有匹配「ab」的字符串,返回true或fals //判斷元素中的字符串是否都與「ab」匹配,返回true或fals .allMatch(str -> str.equals("ab")); System.out.println(isMatch); //anyMatch Boolean isAnyMatch = strings.stream() //判斷元素中是否有匹配「ab」的字符串,返回true或fals .anyMatch(str -> str.equals("ab")); System.out.println("isAnyMatch:" + isAnyMatch); System.out.println("isAllMatch:" + isAllMatch); //打印結果 isAnyMatch:true isAllMatch:false
2.10 forEach(fun): 迭代流中的每一個數據 【最終操做】
strings.stream() //遍歷每個元素 .forEach(s -> System.out.print(s + "; "));
2.11 collect():返回結果集 【最終操做】
strings = strings.stream() //返回集合 .collect(Collectors.toList());
IntSummaryStatistics類,在 java8中配合Stream使用,是用於收集統計信息(例如計數,最小值,最大值,總和和*平均值)的狀態對象。
這個類長這樣:
public class IntSummaryStatistics implements IntConsumer { private long count; private long sum; private int min = Integer.MAX_VALUE; private int max = Integer.MIN_VALUE; public IntSummaryStatistics() { } @Override public void accept(int value) { ++count; sum += value; min = Math.min(min, value); max = Math.max(max, value); } public void combine(IntSummaryStatistics other) { count += other.count; sum += other.sum; min = Math.min(min, other.min); max = Math.max(max, other.max); } public final long getCount() { return count; } public final long getSum() { return sum; } public final int getMin() { return min; } public final int getMax() { return max; } public final double getAverage() { return getCount() > 0 ? (double) getSum() / getCount() : 0.0d; } @Override public String toString() { return String.format( "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}", this.getClass().getSimpleName(), getCount(), getSum(), getMin(), getAverage(), getMax()); } }
這個類的理解起來很簡單,內部有這幾個方法:
2.1 獲取總條數:getCount(),
2.2 獲取和:getSum(),
2.3 獲取最小值:getMin(),
2.4 獲取最大值:getMax(),
2.5 獲取平均值:getAverage()
示例以下:
public static void main( String[] args ) { List<Integer> integerList = Arrays.asList(3, 4, 22, 31, 75, 32, 54); IntSummaryStatistics sta = integerList .stream() //將元素映射爲對應的數據類型(int,double,long) .mapToInt(i -> i) //轉換爲summaryStatistics類 .summaryStatistics(); System.out.println("總共有 : "+ sta.getCount()); System.out.println("列表中最大的數 : " + sta.getMax()); System.out.println("列表中最小的數 : " + sta.getMin()); System.out.println("全部數之和 : " + sta.getSum()); System.out.println("平均數 : " + sta.getAverage()); } //打印結果 總共有 : 7 列表中最大的數 : 75 列表中最小的數 : 3 全部數之和 : 221 平均數 : 31.571428571428573