中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java Stream流式編程常見的坑有哪些

發布時間:2021-10-26 09:26:13 來源:億速云 閱讀:230 作者:iii 欄目:web開發

本篇內容介紹了“Java Stream流式編程常見的坑有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

1. Stream是什么?

Stream是Java8新增的一個接口,允許以聲明性方式處理數據集合。Stream不是一個集合類型不保存數據,可以把它看作是遍歷數據集合的高級迭代器(Iterator)。

Stream操作可以像Builder一樣逐步疊加,形成一條流水線。流水線一般由數據源+零或者多個中間操作+一個終端操作所構成。中間操作可以將流轉換成另外一個流,比如使用filter過濾元素,使用map映射提取值。

Stream與lambda表達式密不可分,本文默認你已經掌握了lambda基礎知識。

2. Stream的特點

  • 只能遍歷(消費)一次。Stream實例只能遍歷一次,終端操作后一次遍歷就結束,再次遍歷需要重新生成實例,這一點類似于Iterator迭代器。

  • 保護數據源。對Stream中任何元素的修改都不會導致數據源被修改,比如過濾刪除流中的一個元素,再次遍歷該數據源依然可以獲取該元素。

  • 懶。filter, map 操作串聯起來形成一系列中間運算,如果沒有一個終端操作(如collect)這些中間運算永遠也不會被執行。

3. 創建Stream實例的方法

(1)使用指定值創建Stream實例

// of為Stream的靜態方法 Stream<String> strStream = Stream.of("hello", "java8", "stream"); // 或者使用基本類型流 IntStream intStream = IntStream.of(1, 2, 3); 復制代碼

(2)使用集合創建Stream實例(常用方式)

// 使用guava庫,初始化一個不可變的list對象 ImmutableList<Integer> integers = ImmutableList.of(1, 2, 3); // List接口繼承Collection接口,java8在Collection接口中添加了stream方法 Stream<Integer> stream = integers.stream(); 復制代碼

(3)使用數組創建Stream實例

// 初始化一個數組 Integer[] array = {1, 2, 3}; // 使用Arrays的靜態方法stream Stream<Integer> stream = Arrays.stream(array); 復制代碼

(4)使用生成器創建Stream實例

// 隨機生成100個整數 Random random = new Random(); // 加上limit否則就是無限流了 Stream<Integer> stream = Stream.generate(random::nextInt).limit(100); 復制代碼

(5)使用迭代器創建Stream實例

// 生成100個奇數,加上limit否則就是無限流了 Stream<Integer> stream = Stream.iterate(1, n -> n + 2).limit(100); stream.forEach(System.out::println); 復制代碼

(6)使用IO接口創建Stream實例

// 獲取指定路徑下文件信息,list方法返回Stream類型 Stream<Path> pathStream = Files.list(Paths.get("/")); 復制代碼

4. Stream常用操作

Stream接口中定義了很多操作,大致可以分為兩大類,一類是中間操作,另一類是終端操作;

Java Stream流式編程常見的坑有哪些

(1)中間操作

中間操作會返回另外一個流,多個中間操作可以連接起來形成一個查詢。

中間操作有惰性,如果流上沒有一個終端操作,那么中間操作是不會做任何處理的。

下面介紹常用的中間操作:

map操作

map是將輸入流中每一個元素映射為另一個元素形成輸出流。

// 初始化一個不可變字符串 List<String> words = ImmutableList.of("hello", "java8", "stream"); // 計算列表中每個單詞的長度 List<Integer> list = words.stream()         .map(String::length)         .collect(Collectors.toList()); // output: 5 5 6 list.forEach(System.out::println); 復制代碼

flatMap操作

List<String[]> list1 = words.stream()         .map(word -> word.split("-"))         .collect(Collectors.toList());          // output: [Ljava.lang.String;@59f95c5d,  //             [Ljava.lang.String;@5ccd43c2 list1.forEach(System.out::println); 復制代碼

哪里?你預期是List, 返回卻是List<String[]>, 這是因為split方法返回的是String[]

這個時候你可以想到要將數組轉成stream, 于是有了第二個版本

Stream<Stream<String>> arrStream = words.stream()         .map(word -> word.split("-"))         .map(Arrays::stream);          // output: java.util.stream.ReferencePipeline$Head@2c13da15,  // java.util.stream.ReferencePipeline$Head@77556fd arrStream.forEach(System.out::println); 復制代碼

還是不對,這個問題使用flatMap扁平流可以解決,flatMap將流中每個元素取出來轉成另外一個輸出流

Stream<String> strStream = words.stream()         .map(word -> word.split("-"))         .flatMap(Arrays::stream)         .distinct(); // output: hello java8 stream strStream.forEach(System.out::println); 復制代碼

filter操作

filter接收Predicate對象,按條件過濾,符合條件的元素生成另外一個流。

// 過濾出單詞長度大于5的單詞,并打印出來 List<String> words = ImmutableList.of("hello", "java8", "hello", "stream"); words.stream()         .filter(word -> word.length() > 5)         .collect(Collectors.toList())         .forEach(System.out::println); // output: stream 復制代碼

(2)終端操作

終端操作將stream流轉成具體的返回值,比如List,Integer等。常見的終端操作有:foreach, min, max, count等。

foreach很常見了,下面舉一個max的例子。

// 找出最大的值 List<Integer> integers = Arrays.asList(6, 20, 19); integers.stream()         .max(Integer::compareTo)         .ifPresent(System.out::println); // output: 20 復制代碼

5. 實戰:使用Stream重構老代碼

假如有一個需求:過濾出年齡大于20歲并且分數大于95的學生。

使用for循環寫法:

private List<Student> getStudents() {     Student s1 = new Student("xiaoli", 18, 95);     Student s2 = new Student("xiaoming", 21, 100);     Student s3 = new Student("xiaohua", 19, 98);     List<Student> studentList = Lists.newArrayList();     studentList.add(s1);     studentList.add(s2);     studentList.add(s3);     return studentList; } public void refactorBefore() {     List<Student> studentList = getStudents();     // 使用臨時list     List<Student> resultList = Lists.newArrayList();     for (Student s : studentList) {         if (s.getAge() > 20 && s.getScore() > 95) {             resultList.add(s);         }     }     // output: Student{name=xiaoming, age=21, score=100}     resultList.forEach(System.out::println); } 復制代碼

使用for循環會初始化一個臨時list用來存放最終的結果,整體看起來不夠優雅和簡潔。

使用lambda和stream重構后:

public void refactorAfter() {     List<Student> studentLists = getStudents();     // output: Student{name=xiaoming, age=21, score=100}    studentLists.stream().filter(this::filterStudents).forEach(System.out::println); } private boolean filterStudents(Student student) {     // 過濾出年齡大于20歲并且分數大于95的學生     return student.getAge() > 20 && student.getScore() > 95; } 復制代碼

使用filter和方法引用使代碼清晰明了,也不用聲明一個臨時list,非常方便。

6. 使用Stream常見的誤區

(1)誤區一:重復消費stream對象

stream對象一旦被消費,不能再次重復消費。

List<String> strings = Arrays.asList("hello", "java8", "stream"); Stream<String> stream = strings.stream(); stream.forEach(System.out::println); // ok stream.forEach(System.out::println); // IllegalStateException 復制代碼

上述代碼執行后報錯:

java.lang.IllegalStateException: stream has already been operated upon or closed

(2)誤區二:修改數據源

在流操作的過程中嘗試添加新的string對象,結果報錯:

List<String> strings = Arrays.asList("hello", "java8", "stream"); // expect: HELLO JAVA8 STREAM WORLD, but throw UnsupportedOperationException strings.stream()         .map(s -> {             strings.add("world");             return s.toUpperCase();         }).forEach(System.out::println); 復制代碼

注意:一定不要在操作流的過程中修改數據源。

“Java Stream流式編程常見的坑有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

开封县| 南阳市| 集安市| 广南县| 满洲里市| 隆回县| 浮梁县| 五台县| 白河县| 乐清市| 中超| 巢湖市| 曲松县| 长汀县| 达孜县| 晋中市| 宁津县| 大邑县| 新竹市| 和顺县| 铁岭市| 敖汉旗| 元江| 永年县| 崇信县| 黄龙县| 绥宁县| 南丰县| 罗城| 康马县| 六安市| 吴旗县| 驻马店市| 淅川县| 武威市| 始兴县| 大港区| 上犹县| 蛟河市| 安化县| 台北市|