Java中實現流的分割槽

banq發表於2024-04-11

Java Streams 是處理集合的強大抽象。通常,我們需要將流分成更小的塊以進行進一步的操作。本文探討了基於固定最大大小對 Java 8 Stream 進行分割槽的各種技術。

1. 用列表分割槽
處理 List 時,使用 Java 8 Streams 基於固定最大大小進行分割槽可以相對簡單。它的工作原理如下:

  • 計算分割槽數量:根據列表的大小和所需的分割槽大小確定所需的分割槽數量。
  • 建立分割槽:迭代分割槽索引範圍並提取原始列表的子列表。
  • 收集分割槽:將子列表收集到列表列表中。

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class ListPartitioning {

    public static <T> List<List<T>> partitionList(List<T> list, int partitionSize) {
        return IntStream.range(0, (list.size() + partitionSize - 1) / partitionSize)
                .mapToObj(i -> list.subList(i * partitionSize, Math.min(list.size(), (i + 1) * partitionSize)))
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<Integer> numbers = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());
        List<List<Integer>> partitions = partitionList(numbers, 5);
        partitions.forEach(System.out::println);
    }
}

要測試此方法:

  • 我們使用IntStream.range建立表示分割槽索引的整數流。
  • 對於每個索引,它使用 提取原始列表的子列表list.subList。
  • 然後使用該collect方法將子列表收集到列表列表中。

2.使用 Guava 分割資料流
使用 Guava 可以高效地在 Java 中對流進行分割槽。我們可以利用 Guava 的 Lists.partition 方法將流分割成固定大小的塊。首先,請確保已將 Guava 庫作為依賴項新增到專案中。

匯入 Guava
如果您使用的是 Maven,可以透過在 pom.xml 檔案中新增以下依賴關係來包含 Guava:

<dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>33.0.0-jre</version> <!-- Replace with the latest version -->
        </dependency>
    </dependencies>

Guava 的 Lists.partition 方法允許我們將列表分割成固定大小的子列表。該方法可直接應用於流,以實現流分割。
build.gradle:
implementation 'com.google.guava:guava:33.0.0-jre' // Replace with the latest version

import com.google.common.collect.Lists;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
 
public class GuavaPartitioning {
 
    public static void main(String[] args) {
        List<Integer> numbers = IntStream.rangeClosed(1, 10)
                                         .boxed()
                                         .collect(Collectors.toList());
 
        <font>//定義分割槽大小<i>
        int partitionSize = 3;
 
       
//使用 Guava 對資料流進行分割槽<i>
        List<List<Integer>> partitions = Lists.partition(numbers, partitionSize);
 
       
// Print each partition<i>
        partitions.forEach(System.out::println);
    }
     
}

這段程式碼的輸出顯示了分割後的子列表,每個子列表根據分割大小包含指定數量的元素。在這個例子中,我們將一個從 1 到 10 的整數列表進行了分割槽,分割槽大小為 3,輸出結果如下:

[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10]

3. 使用 Guava 的 Iterables.partition 對流進行分割槽
在 Java 中使用 Guava 的 Iterables.partition 方法對流進行分割槽,也是將流或序列分割槽/劃分為固定大小塊的一種高效、便捷的方法。下面是我們如何使用它:

import com.google.common.collect.Iterables;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
 
public class GuavaPartitionExample {
 
    public static void main(String[] args) {
        List<Integer> numbers = IntStream.rangeClosed(1, 10)
                                         .boxed()
                                         .collect(Collectors.toList());
 
        <font>// Define the partition size<i>
        int partitionSize = 3;
 
       
// 使用 Iterables.partition 對資料流進行分割槽<i>
        Iterable<List<Integer>> partitions = Iterables.partition(numbers, partitionSize);
 
       
// Print each partition<i>
        partitions.forEach(System.out::println);
    }
}

這種方法與上述使用 List.partition 方法的方法類似。唯一的區別在於它們如何處理輸入資料結構和由此產生的分割槽輸出。在本例中

  • 我們使用 Iterables.partition(numbers, partitionSize) 將數字列表分割成大小為 partitionSize 的子列表。
  • 結果是一個 Iterable<List<Integer>> 包含原始列表的分割槽。

使用 Guava 對流進行分割槽的要點

  • 簡單:Guava 的 Lists.partition 和 Iterables.partition 方法簡化了將流劃分為固定大小塊的任務。
  • 靈活性:這種方法用途廣泛,能很好地處理各種型別的資料和分割槽大小。
  • 可讀性:透過利用 Guava 實用程式,程式碼的可讀性和簡潔性均優於手動分割槽實現。
  • 效能:Guava 經過精心最佳化,即使在處理大資料流時也能高效處理分割槽。

Iterables.partition 與 List.partition 之間的區別
使用 Guava 的 Iterables.partition 和 List.partition 之間的區別在於它們如何處理輸入資料結構和分割槽輸出結果。

Iterables.partition

  • 輸入:Iterables.partition 可對任何 Iterable 型別進行操作,而不僅限於 List。這意味著它可以處理任何實現 Iterable 介面的集合,如 List、Set、Queue 等。
  • 輸出:Iterables.partition 的輸出是一個 Iterable<List<T>>,其中每個 List<T> 代表原始序列的一個分割槽。這適用於懶散地分割和處理大型或無限序列,而無需將整個資料載入到記憶體中。
  • 使用方法:Iterables.partition 用途更廣,可應用於更多資料結構,因此適用於需要處理不同型別集合或流的場景。

List.partition

  • 輸入List.partition 專用於 List 集合。它將 list 分割成固定大小的子 list。
  • 輸出List.partition 的輸出是 List<List<T>>,其中每個 List<T> 代表原始列表的一個分割槽。當你有一個 List 並想將它分割成較小的塊時,通常需要隨機訪問每個分割槽內的元素,這種方法就非常有用。
  • 使用方法:當你有一個 List,並希望根據固定的分割槽大小將其劃分為更小的列表時,List.partition 是理想的選擇。對於只處理 List 集合的用例,List.partition 非常簡單。

在兩者之間做出選擇

  • 當您需要對任何 Iterable 序列(不限於 List)進行懶散分割槽或處理各種型別的集合時,請使用 Iterables.partition。
  • 如果您特別擁有一個 List 並希望將其劃分為更小的子列表以便隨機訪問,或者您只喜歡處理 List 集合,請使用 List.partition。

相關文章