亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Java 8 新特性之Stream API

cooxer / 2335人閱讀

摘要:簡而言之,提供了一種高效且易于使用的處理數(shù)據(jù)的方式。和以前的操作不同,操作還有兩個(gè)基礎(chǔ)的特征中間操作都會返回流對象本身。注意自己不會存儲元素不會改變源對象,相反,它們會返回一個(gè)持有結(jié)果的新操作時(shí)延遲執(zhí)行的。為集合創(chuàng)建并行流。

1. 概述 1.1 簡介

Java 8 中有兩大最為重要的改革,第一個(gè)是 Lambda 表達(dá)式,另外一個(gè)則是 Stream API(java.util.stream.*)。

Stream 是 Java 8 中處理集合的關(guān)鍵抽象概念,它可以指定你希望對集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作。使用 Stream API 對集合數(shù)據(jù)進(jìn)行,就類似于使用 SQL 執(zhí)行的數(shù)據(jù)庫查詢。也可以使用 Stream API 來并行執(zhí)行操作。簡而言之,Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。

1.2 流(Stream)到底是什么呢?

是數(shù)據(jù)渠道,用于操作數(shù)據(jù)源(集合、數(shù)組等)所生成的元素序列。“集合講的是數(shù)據(jù),流講的是計(jì)算”

Stream(流)是一個(gè)來自數(shù)據(jù)源的元素隊(duì)列并支持聚合操作

元素是特定類型的對象,形成一個(gè)隊(duì)列。 Java中的Stream并不會存儲元素,而是按需計(jì)算。

數(shù)據(jù)源 流的來源。 可以是集合,數(shù)組,I/O channel, 產(chǎn)生器generator 等。

聚合操作 類似SQL語句一樣的操作, 比如 filter, map, reduce, find, match, sorted 等。

和以前的 Collection 操作不同, Stream 操作還有兩個(gè)基礎(chǔ)的特征:

Pipelining: 中間操作都會返回流對象本身。 這樣多個(gè)操作可以串聯(lián)成一個(gè)管道, 如同流式風(fēng)格(fluent style)。 這樣做可以對操作進(jìn)行優(yōu)化, 比如延遲執(zhí)行(laziness)和短路( short-circuiting)。

內(nèi)部迭代: 以前對集合遍歷都是通過 Iterator 或者 For-Each 的方式, 顯式的在集合外部進(jìn)行迭代, 這叫做外部迭代。 Stream提供了內(nèi)部迭代的方式, 通過訪問者模式(Visitor)實(shí)現(xiàn)。

注意 :

Stream 自己不會存儲元素

Stream 不會改變源對象,相反,它們會返回一個(gè)持有結(jié)果的新 Stream

Stream 操作時(shí)延遲執(zhí)行的。這意味著它們會等到需要結(jié)果的時(shí)候才執(zhí)行

1.3 Stream 操作的三個(gè)步驟

創(chuàng)建 Stream

一個(gè)數(shù)據(jù)源(集合、數(shù)組等),獲取一個(gè)流

中間操作(聚合操作)

一個(gè)中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理

終止操作(終端操作)

一個(gè)終止操作,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果

2. 創(chuàng)建 Stream(流)

在 Java 8 中, 集合接口有兩個(gè)方法來生成流:

stream() ? 為集合創(chuàng)建串行流。

parallelStream() ? 為集合創(chuàng)建并行流。

創(chuàng)建 Stream 的 5 種方式

@Test
public void t1() {
    // 1. Collection 提供了兩個(gè)方法  stream() 與 parallelStream()
    List list = new ArrayList<>();
    Stream stream = list.stream(); //獲取一個(gè)順序流
    Stream parallelStream = list.parallelStream(); //獲取一個(gè)并行流

    // 2. 通過 Arrays 中的 stream() 獲取一個(gè)數(shù)組流
    Integer[] nums = new Integer[10];
    Stream stream1 = Arrays.stream(nums);

    // 3. 通過 Stream 類中靜態(tài)方法 of()
    Stream stream2 = Stream.of(1,2,3,4,5,6);

    // 4. 創(chuàng)建無限流 - 迭代
    Stream stream3 = Stream.iterate(0, (x) -> x + 2).limit(20);
    stream3.forEach(System.out::println);

    // 5. 創(chuàng)建無限流 - 生成
    Stream stream4 = Stream.generate(Math::random).limit(5);
    stream4.forEach(System.out::println);
}
3. Stream 的中間操作

多個(gè)中間操作可以連接起來形成一個(gè)流水線,除非流水線上觸發(fā)終止操作,否則中間操作不會執(zhí)行任何處理,而是在終止操作時(shí)一次性全部處理,稱為“惰性求值”

提供基礎(chǔ)的操作數(shù)據(jù)

List emps = Arrays.asList(
        new Employee(1, "a1", 28, 3888.99),
        new Employee(2, "a2", 49, 336.66),
        new Employee(3, "a3", 18, 3323.33),
        new Employee(4, "a4", 38, 6666.77),
        new Employee(5, "a5", 8, 80.88),
        new Employee(5, "a5", 8, 80.88),
        new Employee(5, "a5", 8, 80.88),
        new Employee(6, "a6", 56, 100.66)
);
3.1 篩選與切片

filter 接收Lambda,從流中排除某些元素。

limit 截?cái)嗔?,使元素不超過給定數(shù)量

skip(n) 跳過元素,返回一個(gè)扔掉了前 n 個(gè)元素的流,若流中元素不足 n 個(gè),則返回一個(gè)空流,與 limit 互補(bǔ)

distinct 篩選去重,通過流所生成元素的 hashCode()equals() 去除重復(fù)元素

1. filter 接收Lambda,從流中排除某些元素
@Test
public void t2() {
    // 中間操作:不會執(zhí)行任何操作
    Stream stream = emps.stream()
            .filter((e) -> {
                System.out.println("中間操作");
                return e.getAge() > 20;
            });

    // 終止操作:一次性執(zhí)行全部內(nèi)容,即"惰性求值"
    stream.forEach(System.out::println);

}
2. limit 截?cái)嗔?/b>
@Test
public void t3() {
    emps.stream()
            .filter((e) -> {
                // 當(dāng)達(dá)到 limit 為 2 時(shí)將不繼續(xù)遍歷,稱為短路,以提高效率
                System.out.println("短路");
                return e.getSalary() > 3000;
            })
            .limit(2)
            .forEach(System.out::println);
}
3. skip 跳過元素
@Test
public void t4() {
    emps.stream()
            .filter(e -> e.getSalary() > 100)
            .skip(2)
            .forEach(System.out::println);
}
4. distinct 篩選
@Test
public void t5() {
    emps.stream()
            .distinct()
            .forEach(System.out::println);
}

要使用 distinct 需要重寫 EmployeehashCode()equals() 方法

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + id;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    long temp;
    temp = Double.doubleToLongBits(salary);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Employee other = (Employee) obj;
    if (age != other.age)
        return false;
    if (id != other.id)
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
        return false;
    return true;
}
3.2 映射

map 接收 Lambda,將元素轉(zhuǎn)換成其它形式或提取信息。接收一個(gè)函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個(gè)元素上,并將其映射成一個(gè)新的元素

flatMap 接收一個(gè)函數(shù)作為參數(shù),將流中的每個(gè)值都換成另一個(gè)流,然后把所有流連接成一個(gè)流

1. map

將原有的元素進(jìn)過函數(shù)處理,讓后映射(覆蓋)成一個(gè)新的元素

@Test
public void t6() {
    List list = Arrays.asList("aa","bb","cc","dd");
    list.stream()
            .map((s) -> s.toUpperCase())
            .forEach(System.out::println);

    System.out.println("------------------------------------");
    
    emps.stream()
            .map(Employee::getName)
            .forEach(System.out::println);
}
2. flatMap

基礎(chǔ)方法

/**
 * 將字符串分解成字符 list,并返回 Stream
 * 
 * @param str 待分解字符串
 * @return Stream
 */
public static Stream filterCharacter(String str) {
    List list = new ArrayList<>();
    for (Character ch : str.toCharArray()) {
        list.add(ch);
    }
    return list.stream();
}

正常情況下,當(dāng) filterCharacter 返回的也是一個(gè) Stream 時(shí),相當(dāng)于流里面還有子流,接收的結(jié)果就是 Stream>,如果我們要進(jìn)行遍歷的話,就需要使用兩層 forEach 才能遍歷完成。

@Test
public void t7() {
    List list = Arrays.asList("aa","bb","cc","dd");
    Stream> stream = list.stream()
            .map(StreamTest1::filterCharacter);
    // 因?yàn)?Stream 還是 Stream 所以需要嵌套 forEach 才能進(jìn)行遍歷
    stream.forEach((sm) -> {
        sm.forEach(System.out::println);
    });
}

但如果使用 flatMap 就可以將每個(gè)子流都合并成一個(gè)流,這樣遍歷的時(shí)候只使用一層 forEach 就可以了

@Test
public void t8() {
    List list = Arrays.asList("aa","bb","cc","dd");
    Stream stream = list.stream()
            .flatMap(StreamTest1::filterCharacter);
    stream.forEach(System.out::println);
}
3.3 排序

sorted 自然排序(Comparable)

sorted(Comparator com) 定制排序(Comparator)

1. sorted 自然排序
@Test
public void t9() {
    List list = Arrays.asList("cc","aa","dd","bb");
    list.stream()
            .sorted()
            .forEach(System.out::println);
}
2. sorted(Comparator com) 定制排序
@Test
public void t10() {
    emps.stream()
            .sorted((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge()))
            .forEach(System.out::println);
}
4. Stream 終止操作 4.1 查找與匹配

allMatch 檢查是否匹配所有元素

anyMatch 檢查是否至少匹配一個(gè)元素

noneMatch 檢查是否沒有匹配的元素

findFirst 返回第一個(gè)元素

findAny 返回當(dāng)前流中的任意元素

count 返回流中元素的總個(gè)數(shù)

max 返回流中最大值

min 返回流中最小值

基礎(chǔ)數(shù)據(jù)

List emps = Arrays.asList(
        new Employee(1, "a1", 28, 3888.99, Employee.Status.BUSY),
        new Employee(2, "a2", 49, 336.66, Employee.Status.FREE),
        new Employee(3, "a3", 18, 3323.33, Employee.Status.VOCATION),
        new Employee(4, "a4", 38, 6666.77, Employee.Status.FREE),
        new Employee(5, "a5", 8, 80.88, Employee.Status.VOCATION),
        new Employee(6, "a6", 56, 100.66, Employee.Status.BUSY)
);
1. allMatch 檢查是否匹配所有元素
@Test
public void t1() {
    boolean bool = emps.stream()
            .allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));

    System.out.println(bool);
}
2. anyMatch 檢查是否至少匹配一個(gè)元素
@Test
public void t2() {
    boolean bool = emps.stream()
            .anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));

    System.out.println(bool);
}
3. noneMatch 檢查是否沒有匹配的元素
@Test
public void t3() {
    boolean bool = emps.stream()
            .noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));

    System.out.println(bool);
}
4. findFirst 返回第一個(gè)元素
@Test
public void t4() {
    Optional op = emps.stream()
            .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
            .findFirst();

    System.out.println(op.get());
}
5. findAny 返回當(dāng)前流中的任意元素
@Test
public void t5() {
    Optional op = emps.stream()
            .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
            .findAny();
    System.out.println(op.get());
}
6. count 返回流中元素的總個(gè)數(shù)
/**
 * 查詢空閑人數(shù)
 */
@Test
public void t6() {
    Long count = emps.stream()
            .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
            .count();
    System.out.println("count : " + count);
}
7. max 返回流中最大值
/**
 * 查詢工資最高的人
 */
@Test
public void t7() {
    Optional op = emps.stream()
            .max((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()));

    System.out.println(op.get());
}
8. min 返回流中最小值
/**
 * 獲取工資最少的人的工資
 */
@Test
public void t8() {
    Optional op = emps.stream()
            .map(Employee::getSalary)
            .min(Double::compare);

    System.out.println(op.get());
}
4.2 規(guī)約(reduce)

T reduce(T identity, BinaryOperator accumulator) 可以將流中的元素反復(fù)結(jié)合起來,得到一個(gè)值,返回 T

Optional reduce(BinaryOperator accumulator) 可以將流中的元素反復(fù)結(jié)合起來,得到一個(gè)值,返回 Optional

備注:map 和 reduce 的連接通常稱為 map-reduce 模式,因 Google 用它來進(jìn)行網(wǎng)絡(luò)搜索而出名
1. 實(shí)例
@Test
public void t9() {
    List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Integer sum = list.stream()
            .reduce(0, (x, y) -> x + y);
    System.out.println("sum : " + sum);
}
說明 : 
首先將起始值 0 給 x,然后在流中取出一個(gè)元素 1 給了 y,然后 x y 相加結(jié)果為 1,再賦給 x,然后再取出一個(gè)元素 2 賦給y,然后 x y 相加結(jié)果為 3,以此類推
2. 實(shí)例
/**
 * 計(jì)算所有人工資的總和
 */
@Test
public void t10() {
    Optional op = emps.stream()
            .map(Employee::getSalary)
            .reduce(Double::sum);
    System.out.println("Salary Sum : " + op.get());
}
4.3 收集(collect)

collect 將流轉(zhuǎn)換為其它形式,接收一個(gè) Collector(收集器) 接口的實(shí)現(xiàn),用于給 Stream 中元素做匯總的方法

Collector 接口中方法的實(shí)現(xiàn)決定了如何對流執(zhí)行收集操作(如收集到List、Set、Map)。但是 Collector 實(shí)現(xiàn)類提供了很多靜態(tài)方法,可以方便地創(chuàng)建常見收集器實(shí)例,具體方法與實(shí)例如下表:

1. 實(shí)例 - 將結(jié)果收集到 List、Set 等容器
@Test
public void t1() {
    List list = emps.stream()
            .map(Employee::getName)
            .collect(Collectors.toList());
    list.forEach(System.out::println);

    System.out.println("------------------------------------------");

    Set set = emps.stream()
            .map(Employee::getName)
            .collect(Collectors.toSet());
    set.forEach(System.out::println);

    System.out.println("------------------------------------------");

    HashSet hs = emps.stream()
            .map(Employee::getName)
            .collect(Collectors.toCollection(HashSet::new));
    hs.forEach(System.out::println);
}
2. 實(shí)例 - 計(jì)算
@Test
public void t2() {
    Long count = emps.stream()
            .collect(Collectors.counting());
    System.out.println("總數(shù) : " + count);

    System.out.println("------------------------------------------");

    Double avg = emps.stream()
            .collect(Collectors.averagingDouble(Employee::getSalary));
    System.out.println("工資平均值 : " + avg);

    System.out.println("------------------------------------------");

    Double sum = emps.stream()
            .collect(Collectors.summingDouble(Employee::getSalary));
    System.out.println("工資總和 : " + sum);

    System.out.println("------------------------------------------");

    Optional max = emps.stream()
            .collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())));
    System.out.println("工資最多的員工 : " + max.get());

    System.out.println("------------------------------------------");

    Optional min = emps.stream()
            .map(Employee::getSalary)
            .collect(Collectors.minBy(Double::compare));
    System.out.println("工資最少的員工 : " + min.get());

}
3. 實(shí)例 - 計(jì)算的另一種實(shí)現(xiàn)方式
@Test
public void t6() {
    DoubleSummaryStatistics dss = emps.stream()
            .collect(Collectors.summarizingDouble(Employee::getSalary));
    
    System.out.println("sum : " + dss.getSum());
    System.out.println("max : " + dss.getMax());
    System.out.println("avg : " + dss.getAverage());
    System.out.println("count : " + dss.getCount());
    System.out.println("min : " + dss.getMin());
}
4.4 分組

分組就相當(dāng)于 SQL 語句中的 group by,按一個(gè)類別或多個(gè)類別進(jìn)行分組

1. 實(shí)例
@Test
public void t3() {
    Map> map = emps.stream()
            .collect(Collectors.groupingBy(Employee::getStatus));
    // 格式化輸出,方便查看
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    System.out.println(gson.toJson(map));
}
2. 實(shí)例 多級分組
 @Test
public void t4() {
    Map>> map = emps.stream()
            .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                if (e.getAge() <= 35) {
                    return "青年";
                } else if (e.getAge() <= 50) {
                    return "中年";
                } else {
                    return "老年";
                }
            })));
    // 格式化輸出,方便查看
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    System.out.println(gson.toJson(map));
}
4.5 分區(qū)

分區(qū)是一種特殊的分組,結(jié)果 map 至少包含兩個(gè)不同的分組一個(gè)true,一個(gè)false

@Test
public void t5() {
    Map> map = emps.stream()
            .collect(Collectors.partitioningBy((e) -> e.getSalary() > 1000));
    // 格式化輸出,方便查看
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    System.out.println(gson.toJson(map));
}
4.6 連接

將結(jié)果進(jìn)行連接

@Test
public void t8() {
    String s1 = emps.stream()
            .map(Employee::getName)
            .collect(Collectors.joining());
    System.out.println("連接 : " + s1);

    String s2 = emps.stream()
            .map(Employee::getName)
            .collect(Collectors.joining(","));
    System.out.println("添加中間分隔符 : " + s2);

    String s3 = emps.stream()
            .map(Employee::getName)
            .collect(Collectors.joining(",", "==", "=="));
    System.out.println("添加左右分隔符 : " + s3);
}
本文首發(fā)于凌風(fēng)博客:Java 8 新特性之Stream API
作者:凌風(fēng)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/72755.html

相關(guān)文章

  • 樂字節(jié)-Java8特性Stream流(上)

    摘要:需要注意的是很多流操作本身就會返回一個(gè)流,所以多個(gè)操作可以直接連接起來,如下圖這樣,操作可以進(jìn)行鏈?zhǔn)秸{(diào)用,并且并行流還可以實(shí)現(xiàn)數(shù)據(jù)流并行處理操作。為集合創(chuàng)建并行流。 上一篇文章,小樂給大家介紹了《Java8新特性之方法引用》,下面接下來小樂將會給大家介紹Java8新特性之Stream,稱之為流,本篇文章為上半部分。 1、什么是流? Java Se中對于流的操作有輸入輸出IO流,而Jav...

    dingda 評論0 收藏0
  • Java 8 特性Lambda表達(dá)式

    摘要:概述簡介是一個(gè)匿名函數(shù),我們可以把表達(dá)式理解為是一段可以傳遞的代碼將代碼像數(shù)據(jù)一樣進(jìn)行傳遞。作為一種更緊湊的代碼風(fēng)格,使的語言表達(dá)能力得到了提升。任何滿足單一抽象方法法則的接口,都會被自動(dòng)視為函數(shù)接口。 1. 概述 1.1 簡介 Lambda 是一個(gè)匿名函數(shù),我們可以把 Lambda 表達(dá)式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進(jìn)行傳遞)??梢詫懗龈啙崱⒏`活的代碼。作為一種更...

    Ververica 評論0 收藏0
  • 在Android項(xiàng)目中使用Java8

    摘要:現(xiàn)在爸爸終于讓平臺支持了,這篇文章中便來和大家聊聊如何在項(xiàng)目中配置使用。要想在項(xiàng)目中使用的新特性,需要將你的升級到及以上版本,并采用新的編譯。 轉(zhuǎn)載請注明出處:https://zhuanlan.zhihu.com/p/23279894 前言 在過去的文章中我介紹過Java8的一些新特性,包括: Java8新特性第1章(Lambda表達(dá)式) Java8新特性第2章(接口默認(rèn)方法) J...

    junnplus 評論0 收藏0
  • Top stackoverflow 問答系列Java 8 Stream 篇 (一)

    摘要:從發(fā)布到現(xiàn)在,已有三年多了,也得到了廣泛的應(yīng)用,但似乎里面最重要的特性和對很多人來說還是很陌生。想通過介紹一些實(shí)際的問題和答案來講解在現(xiàn)實(shí)開發(fā)中我們可以通過和可以做些什么,以及什么是正確的姿勢。 從Java 8 2014 發(fā)布到現(xiàn)在,已有三年多了,JDK 8 也得到了廣泛的應(yīng)用,但似乎Java 8里面最重要的特性:Lambdas和Stream APIs對很多人來說還是很陌生。想通過介紹...

    z2xy 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<