Stream流
體驗Stream流【理解】
-
案例需求
按照下面的要求完成集合的建立和遍歷
- 建立一個集合,儲存多個字串元素
- 把集合中所有以"張"開頭的元素儲存到一個新的集合
- 把"張"開頭的集合中的長度為3的元素儲存到一個新的集合
- 遍歷上一步得到的集合
-
原始方式示例程式碼
public class StreamDemo { public static void main(String[] args) { //建立一個集合,儲存多個字串元素 ArrayList<String> list = new ArrayList<String>(); list.add("林青霞"); list.add("張曼玉"); list.add("王祖賢"); list.add("柳巖"); list.add("張敏"); list.add("張無忌"); //把集合中所有以"張"開頭的元素儲存到一個新的集合 ArrayList<String> zhangList = new ArrayList<String>(); for(String s : list) { if(s.startsWith("張")) { zhangList.add(s); } } // System.out.println(zhangList); //把"張"開頭的集合中的長度為3的元素儲存到一個新的集合 ArrayList<String> threeList = new ArrayList<String>(); for(String s : zhangList) { if(s.length() == 3) { threeList.add(s); } } // System.out.println(threeList); //遍歷上一步得到的集合 for(String s : threeList) { System.out.println(s); } System.out.println("--------"); //Stream流來改進 list.stream().filter(s -> s.startsWith("張")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s)); } }
-
Stream流的好處
- 直接閱讀程式碼的字面意思即可完美展示無關邏輯方式的語義:獲取流、過濾姓張、過濾長度為3、逐一列印
- Stream流把真正的函數語言程式設計風格引入到Java中
- 程式碼簡潔
Stream流的常見生成方式【應用】
- Stream流的思想
-
Stream流的三類方法
- 獲取Stream流
- 建立一條流水線,並把資料放到流水線上準備進行操作
- 中間方法
- 流水線上的操作
- 一次操作完畢之後,還可以繼續進行其他操作
- 終結方法
- 一個Stream流只能有一個終結方法
- 是流水線上的最後一個操作
- 獲取Stream流
-
生成Stream流的方式
-
Collection體系集合(單列集合)
使用預設方法stream()生成流, default Stream
stream() -
Map體系集合(雙列集合)
把Map轉成Set集合,間接的生成流
-
陣列
通過Arrays中的靜態方法stream生成流
-
同種資料型別的多個資料
通過Stream介面的靜態方法of(T... values)生成流
-
-
程式碼演示
public class StreamDemo { public static void main(String[] args) { //Collection體系的集合可以使用預設方法stream()生成流 List<String> list = new ArrayList<String>(); Stream<String> listStream = list.stream(); Set<String> set = new HashSet<String>(); Stream<String> setStream = set.stream(); //Map體系的集合間接的生成流 Map<String,Integer> map = new HashMap<String, Integer>(); Stream<String> keyStream = map.keySet().stream(); Stream<Integer> valueStream = map.values().stream(); Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream(); //陣列可以通過Arrays中的靜態方法stream生成流 String[] strArray = {"hello","world","java"}; Stream<String> strArrayStream = Arrays.stream(strArray); //同種資料型別的多個資料可以通過Stream介面的靜態方法of(T... values)生成流 Stream<String> strArrayStream2 = Stream.of("hello", "world", "java"); Stream<Integer> intStream = Stream.of(10, 20, 30); } }
Stream流中間操作方法【應用】
-
概念
中間操作的意思是,執行完此方法之後,Stream流依然可以繼續執行其他操作
-
常見方法
方法名 說明 Stream filter(Predicate predicate) 用於對流中的資料進行過濾 Stream limit(long maxSize) 返回此流中的元素組成的流,擷取前指定引數個數的資料 Stream skip(long n) 跳過指定引數個數的資料,返回由該流的剩餘元素組成的流 static Stream concat(Stream a, Stream b) 合併a和b兩個流為一個流 Stream distinct() 返回由該流的不同元素(根據Object.equals(Object) )組成的流(自定義資料型別重寫equals和hashCode) -
filter原理
ArrayList list = new ArrayList(List.of(1,2,3,4)); list.stream().filter(new Predicate() { @Override public boolean test(Object o) { return false; } }); //Predicate中有一個抽象方法test可以使用匿名內部類或者lambda表示式 //filter方法獲取流中的每一個資料 //而test中的s,依次表示流中的每一個資料 //我們只需要在流中對s進行判斷就行了 //如果判斷結果為true,則當前結果留下 //如果判斷結果為false,則當前結果不要
-
filter程式碼演示
public class StreamDemo01 { public static void main(String[] args) { //建立一個集合,儲存多個字串元素 ArrayList<String> list = new ArrayList<String>(); list.add("林青霞"); list.add("張曼玉"); list.add("王祖賢"); list.add("柳巖"); list.add("張敏"); list.add("張無忌"); //需求1:把list集合中以張開頭的元素在控制檯輸出 list.stream().filter(s -> s.startsWith("張")).forEach(System.out::println); System.out.println("--------"); //需求2:把list集合中長度為3的元素在控制檯輸出 list.stream().filter(s -> s.length() == 3).forEach(System.out::println); System.out.println("--------"); //需求3:把list集合中以張開頭的,長度為3的元素在控制檯輸出 list.stream().filter(s -> s.startsWith("張")).filter(s -> s.length() == 3).forEach(System.out::println); } }
-
limit&skip程式碼演示
public class StreamDemo02 { public static void main(String[] args) { //建立一個集合,儲存多個字串元素 ArrayList<String> list = new ArrayList<String>(); list.add("林青霞"); list.add("張曼玉"); list.add("王祖賢"); list.add("柳巖"); list.add("張敏"); list.add("張無忌"); //需求1:取前3個資料在控制檯輸出 list.stream().limit(3).forEach(System.out::println); System.out.println("--------"); //需求2:跳過3個元素,把剩下的元素在控制檯輸出 list.stream().skip(3).forEach(System.out::println); System.out.println("--------"); //需求3:跳過2個元素,把剩下的元素中前2個在控制檯輸出 list.stream().skip(2).limit(2).forEach(System.out::println); } }
-
concat&distinct程式碼演示
public class StreamDemo03 { public static void main(String[] args) { //建立一個集合,儲存多個字串元素 ArrayList<String> list = new ArrayList<String>(); list.add("林青霞"); list.add("張曼玉"); list.add("王祖賢"); list.add("柳巖"); list.add("張敏"); list.add("張無忌"); //需求1:取前4個資料組成一個流 Stream<String> s1 = list.stream().limit(4); //需求2:跳過2個資料組成一個流 Stream<String> s2 = list.stream().skip(2); //需求3:合併需求1和需求2得到的流,並把結果在控制檯輸出 // Stream.concat(s1,s2).forEach(System.out::println); //需求4:合併需求1和需求2得到的流,並把結果在控制檯輸出,要求字串元素不能重複 Stream.concat(s1,s2).distinct().forEach(System.out::println); } }
Stream流終結操作方法【應用】
-
概念
終結操作的意思是,執行完此方法之後,Stream流將不能再執行其他操作
-
常見方法
方法名 說明 void forEach(Consumer action) 獲取流的每個元素並對其執行操作 long count() 返回此流中的元素數 -
程式碼演示
public class StreamDemo { public static void main(String[] args) { //建立一個集合,儲存多個字串元素 ArrayList<String> list = new ArrayList<String>(); list.add("林青霞"); list.add("張曼玉"); list.add("王祖賢"); list.add("柳巖"); list.add("張敏"); list.add("張無忌"); //需求1:把集合中的元素在控制檯輸出 //list.stream().forEach(System.out::println); //list.stream().forEach(new Consumer() { // @Override // public void accept(Object o) { // // } // }); //在forEach方法底層會迴圈呼叫流中每一個資料 //並迴圈呼叫accept方法,把每一個資料傳遞給accept方法 //s就依次代表流中的每一個資料 //所以只需要在accept方法中編寫相應的業務邏輯即可 //需求2:統計集合中有幾個以張開頭的元素,並把統計結果在控制檯輸出 long count = list.stream().filter(s -> s.startsWith("張")).count(); System.out.println(count); } }
Stream流的收集操作【應用】
-
概念
對資料使用Stream流的方式操作完畢後,可以把流中的資料收集到集合中
-
常用方法
方法名 說明 R collect(Collector collector) 把結果收集到集合中 -
工具類Collectors提供了具體的收集方式
方法名 說明 public static Collector toList() 把元素收集到List集合中 public static Collector toSet() 把元素收集到Set集合中 public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中 -
程式碼演示
- 單列集合
ArrayList<Integer> list = new ArrayList<Integer>(List.of(1, 2, 3, 4,4,4)); //filter負責過濾資料 //collect負責收集資料 //獲取流中剩餘的資料,但是他不負責建立容器,也不負責把資料新增到容器中 //Collectors.toList()會在底層建立一個List集合,並把所以的資料新增到List集合中。 List<Integer> list1 = list.stream().filter(number -> number % 2 == 0).collect(Collectors.toList()); System.out.println(list1); Set<Integer> set = list.stream().filter(number -> number % 2 == 0).collect(Collectors.toSet()); System.out.println(set); //[2, 4, 4, 4] //[2, 4]
- 雙列集合
public static void main(String[] args) { /** * Steam流的收集方法 * * 建立一個ArrayList集合,並新增以下的字串,字串中前面是姓名,後面是年齡 * "zhangsan,23" * "lisi,24" * "wangwu,25" * 保留年齡大於等於24歲的人,並將結果收集到Map集合中,姓名為鍵,年齡為值 */ ArrayList<String> list = new ArrayList<>(List.of("zhangsan,23","lisi,24","wangwu,25")); Map<String,Integer> map = list.stream().filter((String s)->{ String[] split = s.split(","); int i = Integer.parseInt(split[1]); return i>=24; }).collect(Collectors.toMap( (String s)-> { return s.split(",")[0]; }, (String s)->{ return Integer.valueOf(s.split(",")[1]); } )); map.forEach((String s,Integer i)->{ System.out.println(s+"---"+i); }); }
Stream流綜合練習【應用】
- 案例需求
-
程式碼實現
演員類
public class Actor { private String name; public Actor(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
測試類
package com.cnblogs.gonghr; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class test13 { public static void main(String[] args) { String actor_man_one = "周潤發"; String actor_man_two = "成龍"; String actor_man_three = "劉德華"; String actor_man_four = "吳京"; String actor_man_five = "周星馳"; String actor_man_six = "李連杰"; ArrayList<String> actors_man = new ArrayList<>(List.of(actor_man_one, actor_man_two, actor_man_three, actor_man_four, actor_man_five, actor_man_six)); String actor_woman_one = "林心如"; String actor_woman_two = "張曼玉"; String actor_woman_three = "楊超越"; String actor_woman_four = "林志玲"; String actor_woman_five = "周冬雨"; String actor_woman_six = "楊穎"; ArrayList<String> actors_woman = new ArrayList<>(List.of(actor_woman_one, actor_woman_two, actor_woman_three, actor_woman_four, actor_woman_five, actor_woman_six)); Stream<String> actorStream_man= actors_man.stream().filter(actor -> actor.length() == 3).limit(2); Stream<String> actorStream_woman = actors_woman.stream().filter(actor -> actor.startsWith("楊")).skip(1); Stream.concat(actorStream_man, actorStream_woman).forEach(s->{ Actor actor = new Actor(s); System.out.println(actor); }); } } //Actor{name='周潤發'} //Actor{name='劉德華'} //Actor{name='楊穎'}