簡體   English   中英

在 Java 8 中從 java.util.stream.Stream 檢索列表

[英]Retrieving a List from a java.util.stream.Stream in Java 8

我正在使用 Java 8 lambdas 來輕松過濾集合。 但是我沒有找到一種簡潔的方法來檢索結果作為同一語句中的新列表。 這是我迄今為止最簡潔的方法:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = new ArrayList<>();
sourceLongList.stream().filter(l -> l > 100).forEach(targetLongList::add);

網上的例子沒有回答我的問題,因為它們沒有生成新的結果列表就停止了。 必須有更簡潔的方法。 我原以為Stream類具有toList()toSet()等方法……

有沒有辦法讓變量targetLongList可以直接由第三行賦值?

您正在做的可能是最簡單的方法,前提是您的流保持順序 - 否則您必須在forEach之前調用 Sequential() 。

[稍后編輯:必須調用序列() 的原因是,如果流是並行的,那么代碼本身( forEach(targetLongList::add) ) 會很活躍。 即便如此,它也不會達到預期的效果,因為forEach是明確不確定的——即使在順序流中,元素處理的順序也無法保證。 您必須使用forEachOrdered來確保正確排序。 Stream API 設計者的意圖是您將在這種情況下使用收集器,如下所示。]

另一種選擇是

targetLongList = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(Collectors.toList());

更新:

另一種方法是使用Collectors.toList

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toList());

以前的解決方案:

另一種方法是使用Collectors.toCollection

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toCollection(ArrayList::new));

我喜歡使用 util 方法,當這是我想要的時候,它會為ArrayList返回一個收集器。

我認為使用Collectors.toCollection(ArrayList::new)的解決方案對於這種常見操作來說有點太吵了。

例子:

ArrayList<Long> result = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(toArrayList());

public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
    return Collectors.toCollection(ArrayList::new);
}

通過這個答案,我還想演示創建和使用自定義收集器是多么簡單,這通常非常有用。

collect(Collectors.toList());

這是您可以用來將任何流轉換為列表的調用。

更具體地說:

    List<String> myList = stream.collect(Collectors.toList()); 

從:

https://www.geeksforgeeks.org/collectors-tolist-method-in-java-with-examples/

如果您有一組原語,則可以使用Eclipse Collections 中提供的原語集合。

LongList sourceLongList = LongLists.mutable.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
LongList targetLongList = sourceLongList.select(l -> l > 100);

如果您無法從List更改 sourceLongList :

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = 
    ListAdapter.adapt(sourceLongList).select(l -> l > 100, new ArrayList<>());

如果你想使用LongStream

long[] sourceLongs = new long[]{1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L};
LongList targetList = 
    LongStream.of(sourceLongs)
    .filter(l -> l > 100)
    .collect(LongArrayList::new, LongArrayList::add, LongArrayList::addAll);

注意:我是 Eclipse Collections 的貢獻者。

一種更有效的方法(避免創建源列表和過濾器的自動拆箱):

List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
    .filter(l -> l > 100)
    .boxed()
    .collect(Collectors.toList());

Java 16 中有一個新方法Stream.toList()

List<Long> targetLongList = sourceLongList
         .stream()
         .filter(l -> l > 100)
         .toList();

如果您不介意使用 3rd 方庫,AOL 的cyclops-react lib(披露我是貢獻者)具有所有JDK 集合類型的擴展,包括List ListX 接口擴展了 java.util.List 並添加了大量有用的運算符,包括過濾器。

你可以簡單地寫——

ListX<Long> sourceLongList = ListX.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
ListX<Long> targetLongList = sourceLongList.filter(l -> l > 100);

ListX 也可以從現有列表創建(通過 ListX.fromIterable)

LongStream 類和 IntStream 和 DoubleStream 類也提供了另一種 collect 方法的變體。

<R> R collect(Supplier<R> supplier,
              ObjLongConsumer<R> accumulator,
              BiConsumer<R,R> combiner)

對此流的元素執行可變的歸約操作。 可變歸約是其中歸約值是可變結果容器,例如 ArrayList,並且通過更新結果的狀態而不是替換結果來合並元素。 這產生的結果相當於:

R result = supplier.get();
  for (long element : this stream)
       accumulator.accept(result, element);
  return result;

與reduce(long, LongBinaryOperator) 一樣,收集操作可以並行化而無需額外的同步。 這是一個終端操作。

使用此收集方法回答您的問題如下:

    LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
    .collect(ArrayList::new, (list, value) -> list.add(value)
    , (list1, list2) -> list1.addAll(list2));

下面是方法參考變體,它非常聰明,但有些難以理解:

     LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
    .collect(ArrayList::new, List::add , List::addAll);

下面將是 HashSet 變體:

     LongStream.of(1L, 2L, 3L, 3).filter(i -> i > 2)
     .collect(HashSet::new, HashSet::add, HashSet::addAll);

類似的 LinkedList 變體是這樣的:

     LongStream.of(1L, 2L, 3L, 3L)
     .filter(i -> i > 2)
     .collect(LinkedList::new, LinkedList::add, LinkedList::addAll);

如果有人(像我一樣)正在尋找處理對象而不是原始類型的方法,然后使用mapToObj()

String ss = "An alternative way is to insert the following VM option before "
        + "the -vmargs option in the Eclipse shortcut properties(edit the "
        + "field Target inside the Shortcut tab):";

List<Character> ll = ss
                        .chars()
                        .mapToObj(c -> new Character((char) c))
                        .collect(Collectors.toList());

System.out.println("List type: " + ll.getClass());
System.out.println("Elem type: " + ll.get(0).getClass());
ll.stream().limit(50).forEach(System.out::print);

印刷:

List type: class java.util.ArrayList
Elem type: class java.lang.Character
An alternative way is to insert the following VM o

這是AbacusUtil 的代碼

LongStream.of(1, 10, 50, 80, 100, 120, 133, 333).filter(e -> e > 100).toList();

披露:我是AbacusUtil的開發者。

String joined = 
                Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
                      .filter(s -> s != null && !s.isEmpty())
                      .collect(Collectors.joining(","));

您可以按如下方式重寫代碼:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = sourceLongList.stream().filter(l -> l > 100).collect(Collectors.toList());

在可變列表中收集:

targetList = sourceList.stream()
                       .filter(i -> i > 100) //apply filter
                       .collect(Collectors.toList());

在不可變列表中收集:

targetList = sourceList.stream()
                       .filter(i -> i > 100) //apply filter
                       .collect(Collectors.toUnmodifiableList());

JavaDoc collect說明:

使用收集器對此流的元素執行可變歸約操作。 Collector 封裝了用作 collect(Supplier, BiConsumer, BiConsumer) 參數的函數,允許重復使用收集策略和組合收集操作,例如多級分組或分區。 如果流是並行的,並且收集器是並發的,並且流是無序的或收集器是無序的,那么將執行並發歸約(有關並發歸約的詳細信息,請參閱收集器。)

這是一個終端操作。

當並行執行時,可以實例化、填充和合並多個中間結果,以保持可變數據結構的隔離。 因此,即使與非線程安全的數據結構(例如 ArrayList)並行執行時,也不需要額外的同步來進行並行縮減。

如果您不使用parallel()這將起作用

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);

List<Long> targetLongList =  new ArrayList<Long>();

sourceLongList.stream().peek(i->targetLongList.add(i)).collect(Collectors.toList());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM