JDK1.8新特性(一):stream

一.什麼是stream?

1.概述

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?

簡單的說,分兩步:生成流,操做流對象

1. 生成流

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);

2. 操做流

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類處理數據

1. IntSummaryStatistics類

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.使用

這個類的理解起來很簡單,內部有這幾個方法:

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
相關文章
相關標籤/搜索