Jdk1.8 Lambda Stream | 快速掌握 Lambda 與 Stream

好久沒寫博客了,^_^。


目錄

1.基本概念。

2. Stream

         常用接口與操作

         常用函數式接口

         Stream 常用 api 操作

3.舉個慄

 3.1 首先準備一個數據源。

3.2 如何準備一個流呢?

3.3 對流進行操作

4. 結束

完整代碼


1.基本概念。

  jdk1.8 有着兩個重要的東西,那就是 lambda 與 stream,這兩樣對現在代碼編程還是有很大的影響。雖然 接口 增加了 default等一些新特性,但都沒有這兩樣重要的多。

 stream 是個什麼鬼呢》? 從字面意思便可以理解爲 流,不過這個流 和 以前的 io、buffer流還是不一樣的,這個流是針對於 集合(collection)來使用的。它的使用就很好理解了,流嘛,都有一個開始、中間、結束(終端)。如同雪川融化經過長江流入大海一樣一樣的。

lambda 又是個什麼鬼呢》?從字面意思理解爲匿名函數,它也確實沒有辜負這個名字,匿名簡寫。這個東東是爲了簡化代碼操作。比如聲明一個方法體,需要new Runnable()啊,它可以簡寫爲 ()->{},極大的簡化了語法。

2. Stream 常用接口與操作

常用函數式接口

  • Supplier<T>,主要方法:T get(),這是一個生產者,可以提供一個T對象。
  • Consumer<T>,主要方法:void accept(T),這是一個消費者,默認方法:andthen(),稍後執行。
  • Predicate<T>,主要方法:boolean test(T t),這是一個判斷者,默認方法:and():且,or():或,negate():非。
  • Function<T,R>,主要方法:R apply(T t),這是一個修改者,默認方法:compose():優先執行,andThen(),稍後執行,identity():直接傳自身。

Stream 常用 api 操作

操作

類型

返回類型

函數式接口

函數描述符

filter

中間

Stream<T>

Predicate<T>

T->Boolean

distinct

中間-有狀態

Stream<T>

 

 

Skip

中間-有狀態

Stream<T>

Long

 

Limit

中間-有狀態

Stream<T>

Long

 

Map

中間

Stream<T>

Function<T,R>

T->R

Flatmap

中間

Stream<T>

Function<T,Stream<R>>

T->Stream<R>

Sorted

中間-有狀態

Stream<T>

Compartor<T>

(T,T)->int

anyMatch

終端

Boolean

Predicate<T>

T->Boolean

noneMatch

終端

Boolean

Predicate<T>

T->Boolean

allMatch

終端

Boolean

Predicate<T>

T->Boolean

findAny

終端

Optional<T>

 

 

findFirst

終端

Optional<T>

 

 

forEach

終端

Void

Consumer<T>

T->void

Collect

終端

R

Collector<T,A,R>

 

Reduce

終端-有狀態

Optional<T>

BinaryOperator<T>

(T,T)->T

Count

終端

Long

 

 

想要知道更多騷操作?看看 java.util.stream 下面的 Stream 接口即可。

    Stream<T> filter(Predicate<? super T> var1);

    <R> Stream<R> map(Function<? super T, ? extends R> var1);

    IntStream mapToInt(ToIntFunction<? super T> var1);

    LongStream mapToLong(ToLongFunction<? super T> var1);

    DoubleStream mapToDouble(ToDoubleFunction<? super T> var1);

    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> var1);

    IntStream flatMapToInt(Function<? super T, ? extends IntStream> var1);

    LongStream flatMapToLong(Function<? super T, ? extends LongStream> var1);

    DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> var1);

    Stream<T> distinct();

    Stream<T> sorted();

    Stream<T> sorted(Comparator<? super T> var1);

    Stream<T> peek(Consumer<? super T> var1);

    Stream<T> limit(long var1);

    Stream<T> skip(long var1);
    
    long count();

    boolean anyMatch(Predicate<? super T> var1);

    boolean allMatch(Predicate<? super T> var1);

    boolean noneMatch(Predicate<? super T> var1);

    Optional<T> findFirst();

    Optional<T> findAny();

    static <T> Stream.Builder<T> builder() {
        return new StreamBuilderImpl();
    }

3.舉個慄

 3.1 首先準備一個數據源。

創建一個用戶類。

package com.example.demo.lambda;

/**
 * 用戶
 *
 * @author wbw
 * @date 2020/4/4 19:19
 */
public class User {
    /**
     * 姓名
     */
    private String name;
    /**
     * id
     */
    private Integer id;
    /**
     * 年齡
     */
    private Integer age;
    /**
     * 地址
     */
    private String address;
    /**
     * 手機號
     */
    private String phone;


    public User() {
    }

    public User(String name, Integer id, Integer age, String address, String phone) {
        this.name = name;
        this.id = id;
        this.age = age;
        this.address = address;
        this.phone = phone;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age='" + age + '\'' +
                ", address='" + address + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

 準備基礎數據

package com.example.demo.lambda;

import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * lambda
 *
 * @author wbw
 * @date 2020/4/4 19:21
 */
public class LambdaTest {

    public static void main(String[] args) {
        // 初始化數據
        List<User> userList = loadInfo();
        System.out.println(userList);
    }

    /**
     * 加載十條用戶信息
     *
     * @return userList
     */
    private static List<User> loadInfo() {
        List<User> userList = new LinkedList<>();
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            userList.add(new User(names.get(i), i, random.nextInt(),
                    getRandomAddress(random.nextInt(10)), String.valueOf(random.nextLong())));
        }
        return userList;
    }

    /**
     * 姓名
     */
    private static final List<String> names = Stream.of("張三", "李四", "王五", "張可汗", "李白", "扁鵲", "馬可波羅", "上官婉兒", "太乙真人", "東皇太一").collect(Collectors.toList());

    /**
     * 自動生成地址(中文)
     *
     * @param len 長度
     * @return name
     */
    public static String getRandomAddress(int len) {
        Random random = new Random();
        StringBuilder ret = new StringBuilder();
        for (int i = 0; i < len; i++) {
            String str = "";
            // 定義高低位
            int height = (176 + Math.abs(random.nextInt(39))); // 獲取高位值
            int lowPos = (161 + Math.abs(random.nextInt(93))); // 獲取低位值
            byte[] b = {Integer.valueOf(height).byteValue(), Integer.valueOf(lowPos).byteValue()};
            try {
                str = new String(b, "GBK"); // 轉成中文
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
            }
            ret.append(str);
        }
        return ret.toString();
    }
}

ok,開始正式騷操作。

3.2 如何準備一個流呢?

        // 初始化數據
        List<User> userList = loadInfo();
        // 得到一個流
        // 1. 直接調用集合自帶方法
        Stream<User> stream = userList.stream();
        // 2. 使用 stream 初始化
        Stream<Object> objectStream = Stream.of(userList.toArray());
        Stream.Builder<User> builder = Stream.builder();
        userList.forEach(e->builder.add(e));
        // 等價於  當明確調用一個帶匿名函數方法時可以簡寫
        userList.forEach(builder::add);

3.3 對流進行操作

        // 初始化數據
        List<User> userList = loadInfo();

        // 統計數量
        long count = userList.stream().count();

        // 轉換成 map ,key爲 id,(k1, k2) -> k1) 是指 key 的主鍵重複時,使用新的還是舊的主鍵,這裏使用舊的
        Map<Integer, User> userMap = userList.stream().collect(Collectors.toMap(user -> user.getId(), user -> user, (k1, k2) -> k1));
        // lambda 簡寫 User::getId 等於 user -> user.getId()
        userMap = userList.stream().collect(Collectors.toMap(User::getId, user -> user, (k1, k2) -> k1));

        // 再把 map 轉換成 list
        Collection<User> users = Optional.of(userMap).map(Map::values).get();

        // 獲取前8個用戶
        List<User> collect = userList.stream().limit(8).collect(Collectors.toList());
        // 去重
        List<User> collect1 = userList.stream().distinct().collect(Collectors.toList());
        // 獲取任意一個
        User user = userList.stream().findAny().get();
        // 獲取第一個
        User user1 = userList.stream().findFirst().get();
        // 匹配所有
        boolean b = userList.stream().allMatch(e -> e.getId() == 1);
        // 匹配任意一個
        boolean b1 = userList.stream().anyMatch(e -> e.getId() == 1);
        // 獲取 姓名 包含張的 用戶
        List<User> userList1 = userList.stream().filter(e -> e.getName().contains("張")).collect(Collectors.toList());

        // 對用戶名 進行拆分
        List<String[]> collect2 = userList.stream().map(e -> e.getName().split("")).collect(Collectors.toList());
        // 流扁平化 flatMap  拆分用戶名,去除重複字,得到一個list
        List<String> collect3 = userList.stream().map(e -> e.getName().split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());

        // 獲取用戶名長度爲 2 的用戶,直到長度不爲 2 時結束
        long count1 = userList.stream().takeWhile(u -> u.getName().length() == 2).count();

        // 和上面相反,刪除 用戶名長度爲 2 的用戶,直到 長度不爲 2 時 獲取。
        count1 = userList.stream().dropWhile(u -> u.getName().length() == 2).count();

        // 排序
        userList.stream().sorted(Comparator.comparingInt(User::getAge)).forEach(e -> System.out.println(e.getAge()));
        // 逆序
        userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).forEach(e -> System.out.println(e.getAge()));

        // peek 等於 foreach 返回一個流,繼續操作
        userList.stream().peek(us -> us.setId(1)).map(User::getId).forEach(System.out::println);

        // 獲取 用戶 年齡 最小的
        User user2 = userList.stream().min((o1, o2) -> o1.getAge() > o2.getAge() ? o2.getAge() : o1.getAge()).get();
        // 獲取用戶年齡最大的
        User user3 = userList.stream().max((o1, o2) -> o1.getAge() < o2.getAge() ? o2.getAge() : o1.getAge()).get();

        // reduce 比較 用戶年齡,除此之外 reduce 還可以對 數組集合進行操作計算
        User user4 = userList.stream().reduce((a, w) -> a.getAge() > w.getAge() ? a: w).get();

        // 跳過 前五個 元素
        long count2 = userList.stream().skip(5).count();

        // parallel 使用多線程處理
        userList.stream().parallel().forEach(System.out::println);
        // sequential 串行執行 主要和 上面多線程 結合使用
        userList.stream().sequential().forEach(System.out::println);
        System.out.println();

        // unordered 返回一個無序流
        userList.stream().sorted(Comparator.comparing(User::getName)).unordered().forEach(System.out::println);

4. 結束

到這裏,想必也清楚了 流的 基本操作與使用。

返回 void 與 具體的 (int、long、list、boolean、對象)都是終端操作,返回stream 都是中間操作。

 

完整代碼

package com.example.demo.lambda;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * lambda
 *
 * @author wbw
 * @date 2020/4/4 19:21
 */
public class LambdaTest {

    public static void main(String[] args) {
        // 初始化數據
        List<User> userList = loadInfo();

        // 統計數量
        long count = userList.stream().count();

        // 轉換成 map ,key爲 id,(k1, k2) -> k1) 是指 key 的主鍵重複時,使用新的還是舊的主鍵,這裏使用舊的
        Map<Integer, User> userMap = userList.stream().collect(Collectors.toMap(user -> user.getId(), user -> user, (k1, k2) -> k1));
        // lambda 簡寫 User::getId 等於 user -> user.getId()
        userMap = userList.stream().collect(Collectors.toMap(User::getId, user -> user, (k1, k2) -> k1));

        // 再把 map 轉換成 list
        Collection<User> users = Optional.of(userMap).map(Map::values).get();

        // 獲取前8個用戶
        List<User> collect = userList.stream().limit(8).collect(Collectors.toList());
        // 去重
        List<User> collect1 = userList.stream().distinct().collect(Collectors.toList());
        // 獲取任意一個
        User user = userList.stream().findAny().get();
        // 獲取第一個
        User user1 = userList.stream().findFirst().get();
        // 匹配所有
        boolean b = userList.stream().allMatch(e -> e.getId() == 1);
        // 匹配所有
        boolean b1 = userList.stream().anyMatch(e -> e.getId() == 1);
        // 獲取 姓名 包含張的 用戶
        List<User> userList1 = userList.stream().filter(e -> e.getName().contains("張")).collect(Collectors.toList());

        // 對用戶名 進行拆分
        List<String[]> collect2 = userList.stream().map(e -> e.getName().split("")).collect(Collectors.toList());
        // 流扁平化 flatMap  拆分用戶名,去除重複字,得到一個list
        List<String> collect3 = userList.stream().map(e -> e.getName().split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());

        // 獲取用戶名長度爲 2 的用戶,直到長度不爲 2 時結束
        long count1 = userList.stream().takeWhile(u -> u.getName().length() == 2).count();

        // 和上面相反,刪除 用戶名長度爲 2 的用戶,直到 長度不爲 2 時 獲取。
        count1 = userList.stream().dropWhile(u -> u.getName().length() == 2).count();

        // 排序
        userList.stream().sorted(Comparator.comparingInt(User::getAge)).forEach(e -> System.out.println(e.getAge()));
        // 逆序
        userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).forEach(e -> System.out.println(e.getAge()));

        // peek 等於 foreach 返回一個流,繼續操作
        userList.stream().peek(us -> us.setId(1)).map(User::getId).forEach(System.out::println);

        // 獲取 用戶 年齡 最小的
        User user2 = userList.stream().min((o1, o2) -> o1.getAge() > o2.getAge() ? o2.getAge() : o1.getAge()).get();
        // 獲取用戶年齡最大的
        User user3 = userList.stream().max((o1, o2) -> o1.getAge() < o2.getAge() ? o2.getAge() : o1.getAge()).get();
        // reduce 比較 用戶年齡,除此之外 reduce 還可以對 數組集合進行操作計算
        User user4 = userList.stream().reduce((a, w) -> a.getAge() > w.getAge() ? a: w).get();

        // 跳過 前五個 元素
        long count2 = userList.stream().skip(5).count();

        // parallel 使用多線程處理
        userList.stream().parallel().forEach(System.out::println);
        // sequential 串行執行 主要和 上面多線程 結合使用
        userList.stream().sequential().forEach(System.out::println);
        System.out.println();

        // unordered 返回一個無序流
        userList.stream().sorted(Comparator.comparing(User::getName)).unordered().forEach(System.out::println);


    }

    /**
     * 加載十條用戶信息
     *
     * @return userList
     */
    private static List<User> loadInfo() {
        List<User> userList = new LinkedList<>();
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            userList.add(new User(names.get(i), i, random.nextInt(),
                    getRandomAddress(random.nextInt(10)), String.valueOf(random.nextLong())));
        }
        return userList;
    }

    /**
     * 姓名
     */
    private static final List<String> names = Stream.of("張三", "李四", "王五", "張可汗", "李白", "扁鵲", "馬可波羅", "上官婉兒", "太乙真人", "東皇太一").collect(Collectors.toList());

    /**
     * 自動生成地址(中文)
     *
     * @param len 長度
     * @return name
     */
    public static String getRandomAddress(int len) {
        Random random = new Random();
        StringBuilder ret = new StringBuilder();
        for (int i = 0; i < len; i++) {
            String str = "";
            // 定義高低位
            int height = (176 + Math.abs(random.nextInt(39))); // 獲取高位值
            int lowPos = (161 + Math.abs(random.nextInt(93))); // 獲取低位值
            byte[] b = {Integer.valueOf(height).byteValue(), Integer.valueOf(lowPos).byteValue()};
            try {
                str = new String(b, "GBK"); // 轉成中文
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
            }
            ret.append(str);
        }
        return ret.toString();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章