Java流中的方法

Java流中的方法

Java 8 引入了 Stream API,它是一个强大的工具,用于处理集合和数组等数据源。

  1. 过滤(Filter)filter(Predicate p) 方法根据给定的条件筛选元素,返回一个满足条件的新流。

     List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     List<Integer> evenNumbers = numbers.stream()
                                        .filter(num -> num % 2 == 0)
                                        .collect(Collectors.toList());
  2. 累加(Reduce)reduce(T identity, BinaryOperator op) 方法可以对流中的元素进行累加或合并操作,返回一个单一的值。

     List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
     int sum = numbers.stream()
                      .reduce(0, Integer::sum);
  3. 查找第一个(Find First)findFirst() 方法返回流中的第一个元素。

    findAny() : 返回流中的任意一个元素;如果流是空的,则返回空;

    【大多数情况下,数据量不大的情况下,findAny()也会返回第一个元素,此时效果与findFirst()一致】

     查找第一个元素
         
     List<Integer> numbers = Arrays.asList(1, 3, 5, 2, 4, 6);
             Optional<Integer> firstEven = numbers.stream()
                     .filter(num -> num % 2 == 0)
                     .findFirst();
     ​
             if (firstEven.isPresent()) {
                 // 如果Optional中存在值,输出该值
                 System.out.println("第一个偶数是: " + firstEven.get());
             } else {
                 // 如果Optional为空,即没有找到偶数
                 System.out.println("列表中没有偶数");
             }
         
             isPresent()方法用来检查Optional对象是否包含一个非空值
  4. 查找最后一个(Find Last):虽然流 API 没有直接的 findLast() 方法,但是可以通过排序或使用 reduce() 方法来实现。

     查找最后一个元素
     ​
     List<Integer> numbers = Arrays.asList(2, 4, 6, 1, 3, 5);
     Optional<Integer> lastOdd = numbers.stream()
                                        .filter(num -> num % 2 != 0)
                                        .reduce((first, second) -> second);
  5. 统计(Count)count() 方法返回流中元素的总数。

     统计被二整除的元素个数
     ​
     List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     long evenCount = numbers.stream()
                             .filter(num -> num % 2 == 0)
                             .count();

为什么使用流?

  1. 函数式编程:流 API 支持函数式编程,可以写出更简洁、声明式的代码。

  2. 聚合操作:流 API 提供了如 filtermapreduce 等聚合操作,简化了数据处理。

  3. 并行处理:流 API 可以很容易地进行并行处理,提高性能。

  4. 无副作用:流操作不修改原始数据源,保证了数据的不变性。

  5. 惰性求值:流操作是惰性求值的,只有当必要时才计算结果,这可以提高效率。

Map 和 Map Filter 的区别

在 Java 流中,map 是一个中间操作,用于将流中的每个元素转换成另一种形式。

  • Mapmap(Function f) 方法接收一个函数作为参数,将流中的每个元素应用该函数,返回一个新流。

    示例:

     将list里的名字转成他的字符长度
     ​
     List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
     List<Integer> lengths = names.stream()
                                  .map(String::length)
                                  .collect(Collectors.toList());

    1. 创建字符串列表

     List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

    这行代码创建了一个包含三个字符串("Alice"、"Bob"、"Charlie")的List集合。

    2. 创建流并应用map操作

     names.stream()
       .map(String::length)
    • names.stream(): 将List集合转换成了一个流(Stream)。流允许以声明式的方式处理数据集合。

    • .map(String::length): map是一个中间操作,它将一个函数应用于流中的每个元素,并产生一个新的流。这里的String::length是一个方法引用,它引用了String类的length()实例方法。length()方法返回字符串的字符数。因此,.map(String::length)将流中的每个字符串转换成了它们的长度。

    3. 收集结果到列表

     .collect(Collectors.toList());
    • .collect(): 是一个终止操作,它将流中的元素汇总或归纳成一个结果。在这个例子中,collect操作将流中的元素(字符串的长度)收集到一个新的列表中。

    • Collectors.toList(): 是一个收集器,它定义了如何将流中的元素收集到一个List集合中。

    4. 存储结果

     List<Integer> lengths = ...
    • lengths: 是一个List<Integer>类型的变量,它存储了collect操作的结果。在这个例子中,lengths将包含原始字符串列表中每个字符串的长度。

    5. 输出结果

    执行上述代码后,lengths列表将包含以下元素:

    • "Alice"的长度是5

    • "Bob"的长度是3

    • "Charlie"的长度是7

    因此,lengths列表的结果是:

     [5, 3, 7]
  • Map Filter:实际上流 API 中并没有 mapFilter 这样的方法,但 filter 方法结合 map 方法可以达到类似 mapFilter 的效果,即先过滤后映射。

    示例:

     List<Integer> evenLengths = names.stream()
                                      .filter(name -> name.length() % 2 == 0)
                                      .map(String::length)
                                      .collect(Collectors.toList());

创建一个新的列表evenLengths,其中只包含这些字符串长度为偶数的字符串的长度。

  1. 原始列表:

     List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

    假设names列表包含了上述几个字符串。

  2. 流的创建:

     names.stream()

    通过调用names列表的stream()方法,我们创建了一个字符串流,这是一个元素序列,可以对其执行一系列操作。

  3. 过滤操作:

     .filter(name -> name.length() % 2 == 0)

    filter()是一个中间操作,它接受一个Predicate函数作为参数。在这个例子中,我们传递了一个Lambda表达式name -> name.length() % 2 == 0,它检查每个字符串的长度是否为偶数(即长度除以2的余数是否为0)。这个操作会返回一个新流,其中只包含满足条件的字符串。

  4. 映射操作:

     .map(String::length)

    map()也是一个中间操作,它接受一个函数作为参数。这里我们使用了方法引用String::length,它将流中的每个字符串转换成它们的长度。这个操作同样返回一个新流,这次流中包含的是数字(字符串长度),等同于 Lambda 表达式 s -> s.length()

  5. 收集操作:

     .collect(Collectors.toList())

    collect()是一个终止操作,它将流中的元素汇总或归纳成一个结果。这里我们使用了Collectors.toList()收集器,它将流中的元素收集到一个新的List中。

  6. 最终结果:

     List<Integer> evenLengths = ...

    最终,我们得到了一个名为evenLengths的新列表,其中包含了原始列表中长度为偶数的字符串的长度。

示例执行过程

假设names列表包含以下字符串:

  • Alice(长度为5,奇数)

  • Bob(长度为3,奇数)

  • Charlie(长度为7,奇数)

  • David(长度为5,奇数)

执行过滤操作后,由于我们只保留长度为偶数的字符串,所以没有任何字符串被选中。

执行映射操作时,由于没有字符串被过滤出来,所以映射操作没有元素可以处理,最终得到的流是空的。

最后,通过收集操作,我们得到的evenLengths列表将是空的。

注意事项

  • 流操作是惰性求值的,这意味着实际的计算会在调用终止操作时才执行。

  • 流操作可以并行执行,以提高性能,但在这个例子中,我们使用的是顺序流。

  • collect()方法需要一个Collector接口的实现,Collectors.toList()是Collector接口的一个实现,用于将流元素收集到列表中。

通过这种方式,Stream API 提供了一种声明式的处理集合数据的方法,使代码更加简洁、易读,并能够利用现代多核处理器的计算能力。

示例

  • Map 示例

     List<String> words = Arrays.asList("one", "two", "three");
     List<Integer> wordLengths = words.stream()
                                      .map(String::length)
                                      .collect(Collectors.toList());
  • MapFilter 示例

     List<String> words = Arrays.asList("one", "two", "three", "four");
     List<String> evenLengthWords = words.stream()
                                         .filter(word -> word.length() % 2 == 0)
                                         .map(word -> word.toUpperCase())
                                         .collect(Collectors.toList());

在这个示例中,我们首先过滤出长度为偶数的单词,然后将它们转换为大写形式。

flatMap 通俗易懂的讲解

flatMap 是 Java 8 Stream API 中的一个方法,它用于将流中的每个元素转换成另一个流,然后将这些流“扁平化”(或“展平”)成一个新的流。简单来说,flatMap 可以看作是 mapflatten(扁平化)两个操作的结合。

flatMapmap 的区别

  • map: 这个操作将一个函数应用于流中的每个元素,返回一个新的流。每个元素被转换成另一个对象,但流的结构不变,即一个元素映射后仍然是一个元素。

  • flatMap: 这个操作也是将一个函数应用于流中的每个元素,但它允许你将每个元素转换成一个流,然后 flatMap 会将这些流连接起来,形成一个统一的流。

map 的应用场景

  • 当你需要对集合中的每个元素应用一个函数,并且想要保持元素的一一对应关系时,使用 map

  • 例如,你可能有一个字符串列表,想要将每个字符串转换成它的大写形式。

  • 当你需要将集合中的每个元素转换成另一种形式时,比如将字符串列表转换为它们的长度列表。

flatMap 的应用场景

  • 当你需要将一个元素转换成多个元素,并且想要在结果流中将它们“展平”时,使用 flatMap

  • 例如,如果你有一个嵌套列表(列表的列表),你可能想要将它们展平成一个单一的列表。

Map Filter的应用场景

当你需要先根据条件筛选出一部分元素,然后对这些元素进行转换时。比如,筛选出长度为偶数的字符串,然后获取它们的长度。

map 的优点

  • 代码简洁:map 提供了一种简洁的方式来转换流中的元素。

  • 易于理解:由于其直观的操作,map 很容易理解和使用。

flatMap 的优点

  • 强大的数据转换能力:flatMap 允许你将复杂数据结构(如嵌套列表)展平成更简单的结构。

  • 灵活性:flatMap 提供了更多的灵活性来处理更复杂的数据转换逻辑。

flatMap 示例

假设我们有一个嵌套的字符串列表,我们想要将其展平成一个单一的列表:

 List<List<String>> nestedList = Arrays.asList(
     Arrays.asList("Alice", "Bob"),
     Arrays.asList("Charlie", "David", "Eve")
 );
 ​
 List<String> flatList = nestedList.stream()
     .flatMap(innerList -> innerList.stream())
     .collect(Collectors.toList());

在这个例子中:

  1. nestedList.stream() 创建了一个包含嵌套列表的流。

  2. flatMap(innerList -> innerList.stream()) 将每个嵌套列表转换成一个流,然后展平成一个单一的流。这里使用了 Lambda 表达式 innerList -> innerList.stream(),它对每个嵌套列表调用 stream() 方法。

  3. collect(Collectors.toList()) 将展平后的流收集到一个新的列表中。

执行上述代码后,flatList 列表将包含所有嵌套列表中的元素:

 ["Alice", "Bob", "Charlie", "David", "Eve"]

这个例子展示了 flatMap 如何将一个嵌套列表结构展平成一个简单的列表,这是 map 无法做到的。使用 flatMap 可以处理更复杂的数据转换任务,特别是涉及到嵌套结构或需要将一个元素转换成多个元素的情况。

总结

流 API 是 Java 8 中处理集合的强大工具,它提供了一种声明式、函数式的方法来处理数据。map 用于转换元素,而 filter 用于筛选元素。结合使用这两个方法可以达到特定条件下的元素转换,适用于各种数据处理场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值