欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中l(wèi)ist.foreach()和list.stream().foreach()用法詳解

 更新時(shí)間:2024年07月05日 11:23:33   作者:碼農(nóng)研究僧  
在Java中List是一種常用的集合類,用于存儲(chǔ)一組元素,List提供了多種遍歷元素的方式,包括使用forEach()方法和使用Stream流的forEach()方法,這篇文章主要給大家介紹了關(guān)于Java中l(wèi)ist.foreach()和list.stream().foreach()用法的相關(guān)資料,需要的朋友可以參考下

前言

典故來源于項(xiàng)目中使用了兩種方式的foreach,后面嘗試體驗(yàn)下有何區(qū)別!

先看代碼示例:

使用List的forEach

import java.util.Arrays;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<String> data = Arrays.asList("One", "Two", "Three", "Four", "Five");

        // 使用List的forEach
        data.forEach(element -> {
            System.out.println("Element: " + element);
        });
    }
}

使用Stream API的forEach

import java.util.Arrays;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<String> data = Arrays.asList("One", "Two", "Three", "Four", "Five");

        // 使用Stream API的forEach
        data.stream().forEach(element -> {
            System.out.println("Element: " + element);
        });
    }
}

兩者輸出結(jié)果都為如下:

既然兩個(gè)都輸出差不多的結(jié)果,但兩者還是稍微有些小區(qū)別,具體看下文!

1. 基本知識(shí)

  • forEach() 是List接口的一部分,用于對(duì)列表中的每個(gè)元素執(zhí)行給定的操作。與Stream API的 forEach 不同,list的 forEach 不支持并行處理,因此它在處理大量數(shù)據(jù)時(shí)可能不如Stream API高效。
    適用于簡單的迭代和操作,不需要復(fù)雜的流處理。

  • stream().forEach() 是Stream API的一部分,用于對(duì)流中的每個(gè)元素執(zhí)行給定的操作。使用Stream API的 forEach 允許進(jìn)行更多的操作,例如過濾、映射等,因?yàn)槟憧梢栽诹魃湘準(zhǔn)秸{(diào)用其他方法。
    Stream API提供了更多的靈活性和功能,適用于處理大量數(shù)據(jù)或進(jìn)行復(fù)雜的操作。

兩者更多的區(qū)別可看下表:

代碼塊概念作用差異之處適用場景
list.foreach()List接口中的方法,用于對(duì)列表中的每個(gè)元素執(zhí)行給定的操作1.通過 forEach(),可以對(duì)列表中的每個(gè)元素進(jìn)行遍歷,并在每個(gè)元素上執(zhí)行指定的操作。

2.主要用于簡單的迭代和操作,適用于不需要復(fù)雜流處理的場景。
1.并行處理: List的 forEach 不支持并行處理,因此在處理大量數(shù)據(jù)時(shí)可能不如Stream API高效。Stream API的并行處理機(jī)制可以更好地利用多核處理器的性能。

2.功能限制: List的 forEach 主要用于簡單的迭代操作,而沒有提供像Stream API那樣的豐富中間操作和終端操作,限制了其在復(fù)雜數(shù)據(jù)處理場景中的應(yīng)用。
適用于簡單的遍歷和操作,例如對(duì)列表中的元素進(jìn)行打印、計(jì)算簡單統(tǒng)計(jì)量等。

不適用于需要復(fù)雜處理邏輯的情況。
stream().foreach()Java 8引入的Stream API中的方法,用于對(duì)流中的每個(gè)元素執(zhí)行給定的操作。1.通過 forEach(),可以對(duì)流中的每個(gè)元素進(jìn)行遍歷,并在每個(gè)元素上執(zhí)行指定的操作。

2.Stream API提供了一種更為函數(shù)式的方式來處理數(shù)據(jù),允許鏈?zhǔn)秸{(diào)用其他方法,如過濾、映射、排序等。
1.鏈?zhǔn)秸{(diào)用: 使用Stream API的 forEach 允許在流上進(jìn)行鏈?zhǔn)秸{(diào)用其他方法,使得可以進(jìn)行更多的操作。這種鏈?zhǔn)秸{(diào)用是函數(shù)式編程的一種特征,使代碼更為靈活和表達(dá)性強(qiáng)。

2.功能豐富: Stream API提供了更多的中間操作和終端操作,例如 map、filter、reduce 等,這些操作可以組合使用,實(shí)現(xiàn)更復(fù)雜的數(shù)據(jù)處理邏輯。
適用于處理大量數(shù)據(jù)或進(jìn)行復(fù)雜的操作,例如對(duì)數(shù)據(jù)進(jìn)行變換、過濾、聚合等。

Stream API的并行處理機(jī)制也使得在多核處理器上能夠更高效地處理大規(guī)模數(shù)據(jù)。

總結(jié):

2. 差異之處

此處的差異之處主要講解stream().foreach() 比 list.foreach()多的點(diǎn)

2.1 執(zhí)行順序

stream流中如果結(jié)合parallelStream(),會(huì)有不一樣的特性!

import java.util.Arrays;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<String> data = Arrays.asList("One", "Two", "Three", "Four", "Five");

        // 使用Stream API中的parallelStream  forEach
        data.parallelStream().forEach(element -> {
            System.out.println("Element: " + element);
        });
    }
}

截圖如下:

在使用 parallelStream() 進(jìn)行并行處理時(shí),元素的處理順序可能不會(huì)按照原始列表中的順序輸出。
并行流會(huì)將數(shù)據(jù)分成多個(gè)塊,然后并行處理這些塊,最后將結(jié)果合并。

因此,并行處理的結(jié)果可能在不同的塊之間交錯(cuò),導(dǎo)致輸出的順序不再按照原始列表的順序。

想要保持順序,可以使用 forEachOrdered() 方法,它會(huì)保證按照流的遍歷順序輸出結(jié)果(并行流的情況下保持元素的遍歷順序,但可能會(huì)犧牲一些并行處理的性能優(yōu)勢)。示例如下:

import java.util.Arrays;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<String> data = Arrays.asList("One", "Two", "Three", "Four", "Five");

        // 使用Stream API的parallelStream().forEachOrdered
        data.parallelStream().forEachOrdered(element -> {
            System.out.println("Element: " + element);
        });
    }
}

截圖如下:

2.2 串行并行

對(duì)應(yīng)上章節(jié)繼續(xù)科普parallelStream(),一般來說并行的輸出速度比較快,用于對(duì)順序輸出不講究,但是大量的數(shù)據(jù)處理可以用這個(gè)!

對(duì)于少量的數(shù)據(jù)來說,效果不明顯,甚至?xí)哂?code>list.foreach(),所以根據(jù)情況而來,一般數(shù)據(jù)處理多,可以應(yīng)用parallelStream()

import java.util.ArrayList;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        for (int i = 1; i <= 1000000; i++) {
            numbers.add(i);
        }

        // 使用 Stream.forEach 進(jìn)行并行處理
        long startTime = System.currentTimeMillis();

        numbers.parallelStream().forEach(element -> {
            // 模擬一些耗時(shí)的操作
            Math.pow(element, 2);
        });

        long endTime = System.currentTimeMillis();
        System.out.println("Time taken with Stream.forEach (parallel): " + (endTime - startTime) + " ms");
    }
}

截圖如下所示:

原本以為使用list.foreach(),時(shí)間會(huì)更長,反而時(shí)間更短:

import java.util.ArrayList;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        for (int i = 1; i <= 1000000; i++) {
            numbers.add(i);
        }

        // 使用 List.forEach 進(jìn)行串行處理
        long startTime = System.currentTimeMillis();

        numbers.forEach(element -> {
            // 模擬一些耗時(shí)的操作
            Math.pow(element, 2);
        });

        long endTime = System.currentTimeMillis();
        System.out.println("Time taken with List.forEach (sequential): " + (endTime - startTime) + " ms");
    }
}

截圖如下:

可能是由于數(shù)據(jù)規(guī)模較小、并行處理帶來的額外開銷以及模擬的耗時(shí)操作較短,導(dǎo)致并行流的性能沒有得到有效提升。

并行處理的優(yōu)勢在于處理大規(guī)模數(shù)據(jù)時(shí)更為顯著。

2.3 復(fù)雜數(shù)據(jù)處理

Stream API提供了豐富的中間操作和終端操作,使得能夠進(jìn)行更復(fù)雜的數(shù)據(jù)處理。

下面舉例說明 filter()、map()、reduce() 這幾個(gè)常用的操作方法。

  • filter() 用于對(duì)流中的元素進(jìn)行過濾,只保留滿足某個(gè)條件的元素:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Demo {
    public static void main(String[] args) {
        List<String> data = Arrays.asList("One", "Two", "Three", "Four", "Five");

        // 過濾出長度大于3的元素
        List<String> filteredList = data.stream()
                .filter(element -> element.length() > 3)
                .collect(Collectors.toList());

        System.out.println("Filtered List: " + filteredList);
    }
}

截圖如下:

  • map() 用于對(duì)流中的每個(gè)元素進(jìn)行映射轉(zhuǎn)換,生成一個(gè)新的流:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Demo {
    public static void main(String[] args) {
        List<String> data = Arrays.asList("One", "Two", "Three", "Four", "Five");

        // 將每個(gè)元素轉(zhuǎn)換為大寫
        List<String> uppercasedList = data.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());

        System.out.println("Uppercased List: " + uppercasedList);
    }
}

截圖如下:

  • reduce() 用于將流中的元素逐個(gè)進(jìn)行操作,最終得到一個(gè)結(jié)果
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Demo {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 對(duì)所有元素求和
        Optional<Integer> sum = numbers.stream()
                .reduce((x, y) -> x + y);
        
        sum.ifPresent(result -> System.out.println("Sum: " + result));
    }
}

使用 Optional<Integer> 主要是為了處理可能沒有元素的情況,避免返回 null。

考慮到 numbers 可能為空,如果直接使用 reduce((x, y) -> x + y),當(dāng) numbers 為空時(shí),會(huì)得到 null,而這可能導(dǎo)致空指針異常。

截圖如下:

拓展1

對(duì)于上述代碼中,都有使用到Collectors.toList()

Collectors.toList() 是Collectors 工具類提供的一個(gè)靜態(tài)方法,它用于將流中的元素收集到一個(gè) List 集合中。
在Stream API中,對(duì)流進(jìn)行一系列的操作后,通常會(huì)希望將結(jié)果收集到一個(gè)集合中,以便后續(xù)的操作或輸出。

在實(shí)際應(yīng)用中,還可以使用其他的 Collectors 方法,如 toSet()、toMap() 等,以便根據(jù)需求將元素收集到不同的集合類型中。

拓展2

對(duì)于上述reduce中,使用到了Optional 

Optional 是Java 8引入的一個(gè)類,用于處理可能為null的值。
它的設(shè)計(jì)目的是避免使用null,減少空指針異常的發(fā)生,并提供更安全、清晰的代碼。

在上述代碼中,通過使用 Optional<Integer>,可以更安全地處理可能為空的情況。如果 numbers 為空,reduce 操作的結(jié)果將是 Optional.empty(),而不是 null。

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class ReduceWithOptionalExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 使用Optional處理可能為空的情況
        Optional<Integer> sum = numbers.stream()
                .reduce((x, y) -> x + y);

        // 判斷Optional是否包含值
        if (sum.isPresent()) {
            System.out.println("Sum: " + sum.get());
        } else {
            System.out.println("The list is empty.");
        }
    }
}

2.4 CRUD集合

當(dāng)使用 list.foreach() 或 stream().foreach() 進(jìn)行遍歷操作時(shí),如果在遍歷過程中對(duì)集合進(jìn)行了增、刪、改的操作,可能會(huì)導(dǎo)致 ConcurrentModificationException 異常。

一、list.foreach()的增刪:

增加數(shù)據(jù)的Demo代碼:

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        List<String> data = new ArrayList<>();
        data.add("One");
        data.add("Two");
        data.add("Three");

        // 使用 List.forEach 遍歷,并在遍歷過程中增加元素
        data.forEach(element -> {
            System.out.println("Element: " + element);
            if (element.equals("Two")) {
                data.add("Four"); // 在遍歷過程中增加元素
            }
        });
    }
}

以及刪除數(shù)據(jù)Demo:

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        List<String> data = new ArrayList<>();
        data.add("One");
        data.add("Two");
        data.add("Three");

        // 使用 List.forEach 遍歷,并在遍歷過程中刪除元素
        data.forEach(element -> {
            System.out.println("Element: " + element);
            if (element.equals("Two")) {
                data.remove(element); // 在遍歷過程中刪除元素,可能導(dǎo)致異常
            }
        });
    }
}

最終的結(jié)果截圖如下:

二、list.stream().foreach()的增刪:

增加數(shù)據(jù)的Demo代碼:

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        List<String> data = new ArrayList<>();
        data.add("One");
        data.add("Two");
        data.add("Three");

        // 使用 Stream.forEach 遍歷,并在遍歷過程中增加元素
        data.stream().forEach(element -> {
            System.out.println("Element: " + element);
            if (element.equals("Two")) {
                data.add("Four"); // 在遍歷過程中增加元素
            }
        });
    }
}

截圖如下:

以及刪除數(shù)據(jù)Demo:

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        List<String> data = new ArrayList<>();
        data.add("One");
        data.add("Two");
        data.add("Three");

        // 使用 Stream.forEach 遍歷,并在遍歷過程中刪除元素
        data.stream().forEach(element -> {
            System.out.println("Element: " + element);
            if (element.equals("Two")) {
                data.remove(element); // 在遍歷過程中刪除元素,可能導(dǎo)致異常
            }
        });
    }
}

截圖如下:

通過上述四個(gè)程序的執(zhí)行結(jié)果,可以得到什么體會(huì)呢???

stream().foreach()在操作集合的CRUD的時(shí)候,執(zhí)行錯(cuò)誤之后,還是會(huì)迭代整個(gè)列表,才看到異常

這也證明stream().foreach()為并行執(zhí)行處理數(shù)據(jù),而不是串行

那有辦法解決這種異常的情況么,又能對(duì)集合進(jìn)行CRUD!(答案是有的,可看如下正文)

2.5 迭代器

通過上述的閱讀,急需需要一個(gè)對(duì)集合的CRUD做一個(gè)安全性的迭代!
于是有了如下的解決方式:

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        List<String> data = new ArrayList<>();
        data.add("One");
        data.add("Two");
        data.add("Three");

        // 使用迭代器遍歷,并在條件滿足時(shí)刪除元素
        Iterator<String> iterator = data.iterator();
        while (iterator.hasNext()) {
            String element = iterator.next();
            System.out.println("Element: " + element);
            if (element.equals("Two")) {
                iterator.remove(); // 嘗試在不支持結(jié)構(gòu)性修改的列表上進(jìn)行刪除操作,拋出異常
            }
        }

        System.out.println("Modified List: " + data);
    }
}

截圖如下:

3. 總結(jié)

總結(jié)起來,對(duì)于上面的代碼學(xué)習(xí),主要涉及了兩種遍歷集合的方式:List.forEach() 和 List.stream().forEach()。下面對(duì)這兩種方式的區(qū)別進(jìn)行總結(jié):

List.forEach() 方法:

  • 遍歷是在當(dāng)前線程中按順序執(zhí)行的,對(duì)集合元素的操作是同步的。

  • 適用于簡單的、順序執(zhí)行的遍歷操作。

  • 不支持并行操作,不保證源數(shù)據(jù)的順序。

List.stream().forEach() 方法:

  • 可以利用并行流進(jìn)行多線程處理,提高遍歷效率,不保證源數(shù)據(jù)的順序。

  • 適用于更復(fù)雜的、并行處理的遍歷操作,可以配合 Stream 的其他操作進(jìn)行更靈活的數(shù)據(jù)處理。

4. 彩蛋

對(duì)于上述中的代碼,有一個(gè)需要注意的點(diǎn):
不管是list.foreach()還是list.stream().foreach(),集合的CRUD都會(huì)出現(xiàn)會(huì)爆:Exception in thread "main" java.lang.UnsupportedOperationException的錯(cuò)誤,舉一個(gè)例子。

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        List<String> data = Arrays.asList("One", "Two", "Three");

        // 使用 List.forEach 遍歷,并在遍歷過程中刪除元素
        data.forEach(element -> {
            System.out.println("Element: " + element);
            if (element.equals("Two")) {
                data.remove(element); // 在遍歷過程中刪除元素,可能導(dǎo)致異常
            }
        });
    }
}

截圖如下:

主要的原因在于:

Arrays.asList("One", "Two", "Three", "Four", "Five") 創(chuàng)建的列表是由數(shù)組支持的固定大小的列表。

這意味著該列表不支持結(jié)構(gòu)性修改操作(如添加、刪除),并且會(huì)在嘗試進(jìn)行這些操作時(shí)拋出UnsupportedOperationException 異常。

到此這篇關(guān)于Java中l(wèi)ist.foreach()和list.stream().foreach()用法詳解的文章就介紹到這了,更多相關(guān)Java中l(wèi)ist.foreach()和list.stream().foreach()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中IO流 RandomAccessFile類實(shí)例詳解

    Java中IO流 RandomAccessFile類實(shí)例詳解

    這篇文章主要介紹了Java中IO流 RandomAccessFile類實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • java去掉文本中多余的空格與空行實(shí)例代碼

    java去掉文本中多余的空格與空行實(shí)例代碼

    在最近的一個(gè)項(xiàng)目中發(fā)現(xiàn)用戶提交的數(shù)據(jù)中多了很多多余的空格與空行,為了不影響使用,只能想辦法去掉了,下面這篇文章主要給大家介紹了關(guān)于java去掉文本中多余的空格與空行的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-08-08
  • Java編程使用UDP建立群聊系統(tǒng)代碼實(shí)例

    Java編程使用UDP建立群聊系統(tǒng)代碼實(shí)例

    這篇文章主要介紹了Java編程使用UDP建立群聊系統(tǒng)代碼實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2018-01-01
  • 解析Java編程中對(duì)于包結(jié)構(gòu)的命名和訪問

    解析Java編程中對(duì)于包結(jié)構(gòu)的命名和訪問

    這篇文章主要介紹了Java編程中對(duì)于包結(jié)構(gòu)的命名和訪問,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-12-12
  • Spring?Cloud?Stream實(shí)現(xiàn)數(shù)據(jù)流處理

    Spring?Cloud?Stream實(shí)現(xiàn)數(shù)據(jù)流處理

    Spring?Cloud?Stream的核心是Stream,準(zhǔn)確來講Spring?Cloud?Stream提供了一整套數(shù)據(jù)流走向(流向)的API,?它的最終目的是使我們不關(guān)心數(shù)據(jù)的流入和寫出,而只關(guān)心對(duì)數(shù)據(jù)的業(yè)務(wù)處理,本文給大家介紹了Spring?Cloud?Stream實(shí)現(xiàn)數(shù)據(jù)流處理,需要的朋友可以參考下
    2024-11-11
  • 手把手教你如何在idea中搭建SpringBoot項(xiàng)目

    手把手教你如何在idea中搭建SpringBoot項(xiàng)目

    這篇文章主要介紹了如何搭建一個(gè)SpringBoot項(xiàng)目,包括環(huán)境準(zhǔn)備、創(chuàng)建新項(xiàng)目、探索項(xiàng)目結(jié)構(gòu)以及展望未來,通過詳細(xì)的步驟和實(shí)用的技巧,幫助開發(fā)者快速上手SpringBoot開發(fā),文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2025-02-02
  • 利用gson將map轉(zhuǎn)為json示例

    利用gson將map轉(zhuǎn)為json示例

    這篇文章主要介紹了利用gson將map轉(zhuǎn)為json示例,需要的朋友可以參考下
    2014-05-05
  • Java 生成PDF文檔的示例代碼

    Java 生成PDF文檔的示例代碼

    這篇文章主要介紹了Java 生成PDF文檔的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • SpringBoot啟動(dòng)遇到的異常問題及解決方案

    SpringBoot啟動(dòng)遇到的異常問題及解決方案

    這篇文章主要介紹了SpringBoot啟動(dòng)遇到的異常問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 一文詳解Java如何優(yōu)雅地判斷對(duì)象是否為空

    一文詳解Java如何優(yōu)雅地判斷對(duì)象是否為空

    這篇文章主要給大家介紹了關(guān)于Java如何優(yōu)雅地判斷對(duì)象是否為空的相關(guān)資料,在Java中可以使用以下方法優(yōu)雅地判斷一個(gè)對(duì)象是否為空,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-04-04

最新評(píng)論