JavaRush /Java Blog /Random-TW /喝咖啡休息#108。Java 流的 12 種常見用途,如何評估 Java 中物件的記憶體分配

喝咖啡休息#108。Java 流的 12 種常見用途,如何評估 Java 中物件的記憶體分配

在 Random-TW 群組發布

使用 Java Streams 的 12 種常見方法

來源:Dev.to Java Streams API 首次出現在 Java 8 中。其目的是提供一種更緊湊的方式來對物件集合執行常見操作。此外,Java Streams API 可用於實作複雜的演算法。在本文中,我們將討論 Java Streams 的常見用例。 喝咖啡休息#108。 Java 流的 12 種常見用途,如何評估 Java 中物件的記憶體分配 - 1首先,讓我們澄清一些基礎知識:
  • Stream() - 從集合中建立一個流。

  • collect() - 將流收集到物件中。物件可以是集合、基元或自訂類別。

  • Collectors是一個提供(許多)靜態方法來收集流的類別。

現在讓我們來看看 Streams 的一些用例:

1. 過濾

  • 用於根據條件從集合中刪除值。

  • 若要根據條件過濾集合元素,請使用filter()方法。僅儲存符合的元素。

範例:從清單中刪除所有奇數。
List<Integer> evenNumbers = originalList.stream()
        .filter(n -> n % 2 == 0)
        .collect(Collectors.toList());

2. 預處理

  • 當集合中的每個值都需要就地更改時很有用。

  • map()方法用於將函數應用於集合的每個元素並傳回計算值的新集合。

例如,讓我們將每個值轉換為其平方。
List<Integer> squares = originalList.stream()
        .map(n -> n * n)
        .collect(Collectors.toList());

3. 轉換

  • 當我們想要將一個集合轉換為另一個集合時很有用。

  • 有多種方法可以實現這一目標。

如上所述,我們可以使用map()collect()方法將一個集合轉換為另一個集合。

範例 1:從清單建立地圖。

將字串列表轉換為字串和長度的映射。
Map<String, Integer> wordLengths = words.stream()
        .collect(Collectors.toMap(
                word -> word,
                word -> word.length()));

範例 2. 將清單轉換為集合。

這是刪除重複項的常見用例。此外,如果我們想要將元素放回清單中,我們可以使用兩次stream()collect()方法。例如,讓我們將字串清單轉換為唯一字串清單:
// if we want to collect to a set
Set<String> uniqueWords = words.stream()
        .collect(Collectors.toSet());

// OR

// if we want to start and end as a list
List<String> uniqueWords = words.stream()
        .collect(Collectors.toSet()).stream().collect(Collectors.toList());

範例 3. 將產品清單轉換為其名稱清單。(展平 - 對齊)

List<String> productNames = products.stream()
        .map(product -> product.getName())
        .collect(Collectors.toList());

4. 減少

  • 將 Collection 減少為單一值。

  • reduce()方法用於將函數應用於集合的每個元素並傳回單一值。

請注意,由於reduce()方法傳回單一值,因此它不能用於傳回Collection。例如,我們將清單中的所有值相加:
int sum = numbers.stream()
        .reduce(0, (a, b) -> a + b);

5. 分組

  • 根據給定條件對集合的元素進行分組。

  • 若要依條件將 Collection 元素分組,請使用Collectors.groupingBy()方法。

例如,讓我們按類別將所有產品分組到產品清單中。
Map<String, List<Product>> productsByCategory = products.stream()
        .collect(Collectors.groupingBy(product -> product.getCategory()));

6. 尋找

  • 搜尋與條件相符的第一個或任何 Collection 元素。

  • findFirst()findAny()方法用於搜尋。

這通常類似於線性搜尋。例如,我們正在尋找清單中的第一個單字,其長度超過5個字元。
Optional<String> firstLongWord = words.stream()
        .filter(word -> word.length() > 5)
        .findFirst();
// Note that findFirst() and findAny() methods return Optional<T> objects.

7. 排序

  • 將集合的元素進行排序。

  • Sorted()方法用於排序。

一般來說,Collections.sort()足以對集合進行排序。如果我們想要執行另一個操作,我們可以專門使用sorted() 。例如,讓我們按升序對數字清單進行排序,然後傳回前 k 個元素。
List<Integer> topK = numbers.stream()
        .sorted()
        .limit(k)
        .collect(Collectors.toList());

8. 分區

  • 根據給定條件分隔集合的元素。

  • Collectors.partitioningBy()方法用來分隔元素。

拆分與群組類似,不同之處在於它會傳回兩個集合 - 一個用於匹配條件的元素,另一個用於不匹配條件的元素。例如,讓我們將學生分為通過考試的學生和未通過考試的學生。
Map<Boolean, List<Student>> passingFailing = students
        .stream()
        .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));

9. 計數

  • 計算符合條件的元素數量。

  • count()方法用於計算符合條件的元素數量。

例如,我們來統計列表中長度超過 5 個字元的單字數。
long count = words.stream()
        .filter(word -> word.length() > 5)
        .count();

10. 範圍

  • 建立一系列值。

  • 若要建立值範圍,請使用range()方法。

有一些特殊的類別用於創建某些類型的流 - IntStreamLongStreamDoubleStreamStream。這些類別在處理原始數字類型時非常有用。若要將陣列轉換為流,請使用Arrays.stream()。例如,讓我們建立一個 0 到 10 之間的數字數組。
int[] numbers = IntStream.range(0, 10).toArray();

11. 匹配

  • 將集合的元素與謂詞(條件)配對。

  • 諸如anyMatch()allMatch()noneMatch()之類的方法用於將集合元素與謂詞進行匹配並傳回布林值。

例如,讓我們檢查價格高於 10 的產品。
// true when all elements match the predicate
boolean allMatch = products.stream()
        .allMatch(product -> product.getPrice() > 10);

// true when any element matches the predicate
boolean anyMatch = products.stream()
        .anyMatch(product -> product.getPrice() > 10);

// true when no elements match the predicate
boolean noneMatch = products.stream()
        .noneMatch(product -> product.getPrice() > 10);

12. 加入

  • 將集合的元素連接成字串。

  • 若要將集合元素連接到字串中,請使用Collectors.joining()方法。

例如,讓我們將清單中的所有單字連接成一個字串。
String joinedWords = words.stream()
        .collect(Collectors.joining(" "));
對於一般場景來說就是這樣。您也可以自行探索其他不太常見的場景:
  • 並行流;
  • 統計數據;
  • 客製化收藏家。

線程的好處

  • 更緊湊的程式碼 - 減少處理集合所需的程式碼量。

  • 更少的中間變數。介入變數可能會導致錯誤發生。越少,就越容易避免意外的錯誤。

  • 直觀的代碼。一些開發人員不同意線程比其他方法更直觀。然而,一旦我們習慣了它們,它們就會變得比其他方法直觀得多。

感謝您的閱讀。我希望您喜歡這篇文章。還有許多其他可以使用線程的情況,但本主題未涵蓋。請隨意添加我錯過的任何常見場景。

如何在 Java 中評估物件的記憶體分配

來源:DZone 本文展示了在 Java 中評估物件記憶體分配的三種最著名的方法。

使用 Profiler 進行記憶體評估

估計某些物件的記憶體最簡單的方法是使用分析器(例如Visual VM)直接查看 JVM 記憶體。 喝咖啡休息#108。 Java 流的 12 種常見用途,如何評估 Java 中物件的記憶體分配 - 2這種方法的問題是您需要連接到正在運行的 JVM,由於安全原因,這在生產環境中可能無法實現。

使用儀器進行記憶評估

估計給定物件分配的記憶體的另一種方法是使用 Instruments。簡單來說,我們需要建立一個類別並將其編譯成 JAR。建立 JAR 後,我們必須與該 JAR 一起執行 JVM。您可以在此處了解有關此方法的更多資訊。這裡的缺點是需要將特定的 jar 檔案添加到 JVM,由於安全或相關問題,這可能不適合生產。

使用 JOL 庫評估內存

作為另一種選擇,我們可以使用JOL Library。這是一個非常強大的函式庫,可以提供物件權重和物件實例分配的記憶體的詳細估計。要使用該庫,我們需要新增依賴項:
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.16</version>
</dependency>
之後我們可以像這樣使用它:
out.println(GraphLayout.parseInstance(myObject).totalSize() / 1024000d + " MB")

Twitter 檔案中的 ObjectSizeCalculator

Twitter 的公共GitHub儲存庫有一個名為 ObjectSizeCalculator 的工具類,可以估計給定物件實例分配的記憶體。使用時不需要太多記憶體或時間。即使對於大型物體,評估過程也需要幾秒鐘。使用這個類別非常簡單:
ObjectSizeCalculator.getObjectSize(address)
我推薦這種方法,但請記住,它僅由 Java Hotspot、OpenJDK 和 TwitterJDK 支援。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION