JavaRush /Java 博客 /Random-ZH /喝咖啡休息#108。Java 流的 12 种常见用途,如何评估 Java 中对象的内存分配

喝咖啡休息#108。Java 流的 12 种常见用途,如何评估 Java 中对象的内存分配

已在 Random-ZH 群组中发布

使用 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