Java 8 新特性-Stream更優雅的處理集合入門


Java 8 新特性之——Stream

一. 簡單介紹

Stream是Java 8提出了的一種新的對集合對象功能的增強。它集合Lambda表達式,對集合提供了一些非常便利,高效的操作,使得代碼具有非常高的可讀性,優雅性!!舉個例子來說,它就像一個流水線操作,對輸入流水線的東西(水果)進行一系列加工處理,最后獲取到我們需要的某種特殊的水果(沒有洗過的蘋果)。

  1. Stream提供了對集合的便捷化處理方式
  2. 聲明式編程的思想
  3. 代碼更加優雅,簡潔,不信往下看→_→

來個例子來看看Stream風格

上海從今年7月1號開始,進行了史無前例的垃圾分類,先看個圖圖,下圖是上海最近流行的挎包(捂臉笑哭),怕不怕,哈哈。

上海流行挎包(捂臉笑)

閑話不多說,進入正題,現在需要將一堆垃圾List<Garbage> garbages分類處理。

  • 使用了Stream的代碼風格
//有一堆沒分類的垃圾
List<Garbage> garbage = new ArrayList<>();
//通過 Java 8 提供的流優雅的處理下,瞧好嘍
List<Garbage> 干垃圾 = garbage.stream()         //1. 垃圾倒出來,放到流水線
                .filter(x -> "挑出有害垃圾")     //2. 挑出有害垃圾 
                .filter(x -> "挑出可回收垃圾")   //3. 挑出可回收垃圾
                .filter(x -> "挑出有害垃圾")     //4. 挑出有害垃圾
                .collect(Collectors.toList());  //5. 把剩下的干垃圾裝到干垃圾桶
/** 上面是不是非常優雅呢 **/

二. Stream 的操作流程

Stream的所有操作分為三個階段,【創建】>> 【中間操作】>> 【終端操作】

1. Stream 的【創建】

  • 方式一

    list.stream()

    //通過List集合創建
    List<String> list = Arrays.asList("1", "2", "3");
    //list.stream()
    Stream<String> stream = list.stream();
    
  • 方式二

    Stream.of()

    //直接通過指定的元素創建
    Stream<String> stream = Stream.of("1", "2", "3");
    //通過數組Array
    String[] arrays = {"a", "b", "c"};
    Stream<String> stream = Stream.of(arrays);
    //和上面區別不大
    Stream<String> stream1 = Arrays.stream(arrays);
    
  • 其他

  • 數值流的操作
    對於基本數值型,目前有三種對應的包裝類型 Stream:

IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
IntStream.range(1, 3).forEach(System.out::println);
IntStream.rangeClosed(1, 3).forEach(System.out::println);

2. Stream的流水線操作【中間操作】

下面式常用的中間操作

Stream Operation Goal Input
filter filter 方法用於通過設置的條件過濾出元素。 條件(返回布爾值)Predicate
map map 方法用於映射每個元素到對應的結果 可以是一個功能 Function
limit limit 方法用於獲取指定數量的流 int值
sorted sorted 方法用於對流進行排序 Comparator
distinct 去除重復 --
parallel parallelStream 是流並行處理程序的代替方法 --
  • filter統計空字符串的個數
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數量
int count = strings.stream().filter(string -> string.isEmpty()).count()
  • map 使用 map 輸出了元素對應的平方數
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 獲取對應的平方數
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
  • limit使用 limit 方法打印出 10 條數據
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
  • sorted使用 sorted 方法對輸出的 10 個隨機數進行排序
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
  • distinct使用 distinct 對元素進行去重
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().distinct().forEach(System.out::println);
  • parallel 使用 parallelStream 來輸出空字符串的數量
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數量
int count = strings.parallelStream().filter(string -> string.isEmpty()).count();

3. 【終端操作】

Stream Operation Goal Input Or Output
forEach 遍歷元素 其他操作
count 統計元素個數 --
collect 聚合操作 --
  • forEach遍歷打印
Stream.of("a", "b", "c").forEach(System.out::println);
  • count統計'a'的數量
long count = Stream.of("a", "b", "c", "a").filter(x -> "a".equals(x)).count();//2
  • collect聚合
// 1. 聚合轉成List
List<String> list1 = stream.collect(Collectors.toList());
List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
// 2. 聚合轉成Set
Set set1 = stream.collect(Collectors.toSet());
Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
// 3. 聚合轉成String
String str = stream.collect(Collectors.joining()).toString();
// 4. ···其他

1. 循環list中的所有元素然后刪除重復

    /**
     * 循環list中的所有元素然后刪除重復
     *
     * @param list 待去重的list
     * @return 去重后的list
     */
     public static List<StaffResponse> removeDuplicate(List<StaffResponse> list) {
        for (int i = 0; i < list.size() - 1; i++) {
            for (int j = list.size() - 1; j > i; j--) {
                if (list.get(j).getStaffNo().equals(list.get(i).getStaffNo())) {
                    list.remove(j);
                }
            }
        }
        return list;
    }

2. 利用java8新特性去重參考原文鏈接

//list集合中根據userName去重
List<User> lists = lists.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(User::getUsrName))), ArrayList::new));

3. 排序 參考原文鏈接

List<PromotionForHomeDto> list = promotionBasicDao.
list(new WherePrams().orderBy("create_time desc"));
list = list.stream().sorted(Comparator.comparing(PromotionForHomeDto::getCreateTime))
                .collect(Collectors.toList());

三. 簡單說下聲明式編程

小故事:早上剛上班,經理找到大胖說:“大胖啊,咱們下去去聚餐,軟件園旁邊有好幾家不錯的餐館,如巫山烤魚、海底撈、大鴨梨,你到大眾點評調查一下,也問問去過的同事,看看哪家的口碑好。我們有14個人,預定一張大桌子,然后用滴滴約4輛車,每輛車坐3~4人,我們會在11點半出發”。
如果經理是程序員,大胖是計算機,這就是典型的命令式編程
實際上,現實中一般是經理對大胖說:“大胖啊,我給你交代一件事,咱們下午要聚餐,你在軟件園旁邊找一家合適的餐館,我們有14個人,11點半出發”。這種就是聲明式編程

1. 聲明式編程最知名的就是我們都熟悉的SQL

SELECT stu.id, stu.name, ss.score
  FROM student stu, student_score ss
 WHERE stu.id = ss.id
   AND ss.score > 80

2. 用Java也來舉個例子

有一個學生列表,計算出年齡小於18歲的學生數量

傳統命令式編程

//聲明一個計數器,遍歷學生集合,如果學生年齡小於18歲,計數器+1
int count = 0;
Iterator<Student> iter = students.iterator();

while(iter.hasNext()) {
    Student s = iter.next();
    if (s.getAge < 18) {
        count++;
    }
}

聲明式編程

//過濾學生構成的流(Stream),只把年齡小於18歲的留下,然后做個統計。
int count = students.stream()
        .filter(s -> s.getAge() < 18)
        .count();

聲明式編程也是一種高度的抽象,我只告訴你我要干什么,至於怎么干,我Don't care

參考資料書-劉欣·碼農翻身

參考資料1

參考資料2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM