您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

带你了解 Stream 的使用,提升集合开发效率

时间:2023-08-21 12:34:27  来源:  作者:IT技术控

当涉及 JAVA 编程时,Java Stream 是一个功能强大且高效的工具,用于处理集合数据。它提供了一种声明式的方式来操作数据,可以显著简化代码并提高可读性。在本文中,我们将深入探讨 Java Stream,介绍其基本概念、常用操作和用例。

什么是 Java Stream

Java Stream 是 Java 8 引入的一种新的抽象层,用于处理集合数据(如列表、数组等)。它允许你以一种更简洁、更声明式的方式对数据进行操作,而无需编写冗长的循环和条件语句。

其核心类库主要改进了对集合类的 API 和新增 Stream 操作。Stream类中每一个方法都对应集合上的一种操作。将真正的函数式编程引入到Java中,能让代码更加简洁,极大地简化了集合的处理操作,提高了开发的效率和生产力。

同时 Stream 不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel 等。在 Stream 中的操作每一次都会产生新的流,内部不会像普通集合操作一样立刻获取值,而是惰性取值,只有等到用户真正需要结果的时候才会执行。

通过使用 Stream,你可以对数据执行各种操作,如筛选、映射、排序、聚合等。

集合操作与 Stream 操作对比

集合操作

处理方式

集合操作是通过迭代和循环来处理集合中的元素。你需要编写显式的循环代码,手动访问和操作每个元素。

适用场景

集合操作适用于简单的数据处理需求,或者在需要直接操作集合内部的情况下。它在处理小型数据集时可能较为方便。

优点

  • 直观:集合操作可以更直观地展示数据的处理过程。
  • 熟悉:如果你对循环和迭代操作非常熟悉,可能更容易上手。

缺点

  • 冗余:集合操作通常需要编写较多的循环和条件语句,导致代码冗余。
  • 低效:在大数据集上,集合操作可能会导致性能问题,因为它需要显式迭代每个元素。

Stream 操作

处理方式

Stream 操作使用声明式的方式来操作集合数据。你可以链式调用多个操作,以流水线的方式对数据进行处理。

适用场景

Stream 操作适用于需要对数据进行筛选、转换、排序、聚合等复杂操作的情况。它在处理大型数据集和需要并行处理的情况下更为有效。

优点

  • 简洁:Stream 操作可以以更简洁的方式表达数据处理逻辑,减少了循环和条件的使用。
  • 高效:Stream 操作可以在内部进行优化,如并行处理,从而在大数据集上提供更高的性能。

缺点

  • 学习曲线:如果你对 Stream 操作不熟悉,可能需要一些时间来学习其概念和语法。
  • 不适合直接操作集合:Stream 操作通常不直接修改原始集合,而是生成新的 Stream 或最终结果。

案例

本示例以操作订单金额集合为例,查询金额小于 100 的订单,并且根据创建时间进行排序,得到订单标题,生成新集合

java复制代码public class List {

  public static void mAIn(String[] args) {

    java.util.List<Order> orders = new ArrayList<>();
    orders.add( new Order(1, "水果", 18, "2023-08-13"));
    orders.add( new Order(2, "衣服", 59, "2023-08-12"));
    orders.add( new Order(3, "日用品", 28, "2023-08-11"));
    orders.add( new Order(4, "电子产品", 8999, "2023-08-10"));
    orders.add( new Order(5, "图书", 128, "2023-08-09"));
    java.util.List<Order> result = new ArrayList<>();

    // 过滤出价格大于100的订单
    for (Order order : orders) {
      if (order.getPrice() > 100){
        result.add(order);
      }
    }

    // 按照日期进行排序
    Collections.sort(result,new Comparator<Order>(){
      @Override
      public int compare(Order o1, Order o2) {
        return Integer.compare(o1.getDate(),o2.getDate());
      }
    });

    // 取出订单名称
    ArrayList<Order> names = new ArrayList<>();

    for (Order order : result) {
      names.add(order.getName());
    }
    // 打印
    System.out.println(names.toString());

  }

} 

上述示例代码代码中产生了两个多余的声明,result 和 names,这两个的声明在整个过程中的作用是作为一个中间数据存储容器,而且还需要将整体的操作多次遍历。

那么通过 Stream 流是如何处理上述数据的,请看下面示例

java复制代码public class Stream {
  public static void main(String[] args) {

    java.util.List<Order> orders = new ArrayList<>();
    orders.add( new Order(1, "水果", 18, "2023-08-13"));
    orders.add( new Order(2, "衣服", 59, "2023-08-12"));
    orders.add( new Order(3, "日用品", 28, "2023-08-11"));
    orders.add( new Order(4, "电子产品", 8999, "2023-08-10"));
    orders.add( new Order(5, "图书", 128, "2023-08-09"));

    // 直接遍历输出
    orders.stream()
        .filter(order -> order.getPrice() > 100) // 过滤出价格大于100的订单
        .sorted(Comparator.comparing(Order::getDate)) // 按照日期进行排序
        .map(Order::getName)// 取出订单名称
        .forEach(System.out::println); // 遍历输出

    // 得到新的集合进行输出
    List<String> result = orders.stream()
        .filter(order -> order.getPrice() > 100).sorted(Comparator.comparing(Order::getDate))
        .map(Order::getName).collect(Collectors.toList());
    System.out.println(result);
  }
}

通过上述代码的执行,可以发现无需再去定义过多的冗余变量。我们可以将多个操作组成一个调用链,形成数据处理流水线。在减少代码量的同时也更加的清晰易懂。

并且对于现在调用的方法,本身都是一种高层次构件,与线程模型无关。因此在并行使用中,开发者们无需再去操心线程和锁了。Stream内部都已经做好了。

更好的理解 Sream 流操作

把 Stream 流操作理解成数据库的查询操作

集合=数据表 元素=表中的每条数据 属性=数据列 流 API = SQL 查询

Stream 流主要思想

Stream 流思想就是将集合的操作由传统的 for 循环式(外部迭代)转变为 Stream 流式操作(内部迭代)

外部迭代

所有的集合迭代所及都是在我们自己编写的代码中,所以这种显式的方式称之为外部迭代。其主要关注于数据本身。并且一般都是串行的。

1)for 循环是串行的,而且必须按照集合中元素的顺序进行依次处理,要想改造成并行的话,需要修改每个for循环 2)使用是及早求值,返回的是另一个值或空。使用性能上存在一点点的瑕疵 3)易读性不好,如果for中嵌套大量循环与功能代码,阅读起来简直是灾难

内部迭代

而内部迭代来说,它所操作的就是不是一个集合了,而是一个流。它会将所有的操作融合在流中,由其在内部进行处
理,这种隐式的方式称之为内部迭代。并且内部迭代支持并行处理,更利于集合操作的性能优化。其关注与对数据的计算。

Stream 操作详解

Stream 流接口中定义了许多对于集合的操作方法,总的来说分为以下两大类

  • 中间操作:会返回一个流,通过这种方式可以将多个中间操作连接起来,形成一个调用链,从而转换为另外一个流。除非调用链最后存在一个终端操作,否则中间操作对流不会进行任何结果处理。
  • 终端操作:会返回一个具体的结果,比如 boolean、list、integer 等类型结果。

 

筛选操作

对于集合的操作,经常性的会涉及到对于集中符合条件的数据筛选,Stream 中对于数据筛选两个常见的API:filter(过滤)、distinct(去重)

filter

filter 是 Stream 中的一个中间操作,它接受一个 Predicate 参数,用于筛选出符合条件的元素。Predicate 是一个函数式接口,用于表示一个条件判断操作。

使用 filter 操作筛选元素

java复制代码import java.util.List;
import java.util.stream.Collectors;

public class StreamFilterExample {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<Integer> evenNumbers = numbers.stream()
                .filter(num -> num % 2 == 0)
                .collect(Collectors.toList());
        System.out.println("Even numbers: " + evenNumbers);
    }
}

在上面的示例中,我们创建了一个整数列表 numbers,然后使用 stream 方法将其转换为一个流。接着,我们使用 filter 操作筛选出偶数,最后通过 collect 方法将结果收集到一个新的列表中。

自定义筛选条件

你可以根据自己的需求定义不同的筛选条件。例如,筛选出字符串长度大于 5 的元素:

java复制代码import java.util.List;
import java.util.stream.Collectors;

public class StreamFilterExample {

    public static void main(String[] args) {
        List<String> words = List.of("Apple", "banana", "cherry", "date", "elderberry");
        List<String> longWords = words.stream()
                .filter(word -> word.length() > 5)
                .collect(Collectors.toList());
        System.out.println("Long words: " + longWords);
    }
}

源码解析

java复制代码    @Override
    public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
        //  判断 predicate 是否为 null,如果为 null,则抛出 NullPointerException
        Objects.requireNonNull(predicate);
        /**
        * 构建 Stream ,重写 onWrapSink 方法
        */
        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SIZED) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
                    /**
                    * 流已经构建完成,但是因为 begin 方法会优先执行,此时无法明确流中后续会存在多少元素,所有传递 -1,代表无法确定
                    */
                    @Override
                    public void begin(long size) {
                        downstream.begin(-1);
                    }

                   
                    //调用 predicate 中的 test 方法,进行条件判断,最终将符合条件数据放入流中
                    @Override
                    public void accept(P_OUT u) {
                        if (predicate.test(u))
                            downstream.accept(u);
                    }
                };
            }
        };
    }

distinct

distinct 是一个中间操作,它可以应用于 Stream 上,用于消除流中的重复元素。

使用 distinct 操作去除重复元素

java复制代码import java.util.List;
import java.util.stream.Collectors;

public class StreamDistinctExample {

    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 2, 3, 4, 4, 5, 5, 5);

        List<Integer> distinctNumbers = numbers.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println("Distinct numbers: " + distinctNumbers);
    }
}

在上面的示例中,我们创建了一个整数列表 numbers,其中包含重复的元素。使用 stream 方法将列表转换为流,然后应用 distinct 操作消除重复元素。最终,通过 collect 方法将结果收集到一个新的列表中。

自定义去重逻辑

distinct 操作默认使用对象的 equals 方法来判断是否为重复元素。

如果你希望根据自定义的逻辑来判断元素是否重复,可以结合 equals 和 hashCode 方法的重写,或者使用 Comparator 来自定义比较。

java复制代码import java.util.List;
import java.util.stream.Collectors;
// 定义 Person 对象
class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
      @Override
  public boolean equals(Object obj) {
    if (obj instanceof Person) {
      return this.name.equals(((Person) obj).name);
    }
    return false;
  }

  @Override
  public int hashCode() {
    return this.name.hashCode();
  }
}

public class StreamDistinctExample {

    public static void main(String[] args) {
        // 创建 Person 对象集合
        List<Person> people = List.of(
                new Person("Alice"),
                new Person("Bob"),
                new Person("Alice")
        );
        
        List<Person> distinctPeople = people.stream()
                .distinct()
                .collect(Collectors.toList());

        System.out.println("Distinct people: " + distinctPeople.stream().map(Person::getName).collect(Collectors.toList()));
    }
}

切片操作

切片操作是 Java 8 中 Stream API 提供的一组操作,用于对流中的元素进行截取或分割,以获取所需的部分元素。这组操作包括 limit、skip 和 substream(Java 9 及以上版本)。

limit

limit 操作是 Stream API 中的一个中间操作,它允许我们从流中获取指定数量的元素,然后返回一个新的流。这个操作在许多场景中都很有用,比如只需要查看前几条记录、分页显示数据等情况。

使用 limit 操作获取前 N 个元素

java复制代码public class LimitDemo {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    numbers.stream()
        .limit(3)
        .forEach(System.out::println);
  }
}

在这个例子中,我们创建了一个包含整数的列表。我们首先将其转换为流,然后使用 limit 方法只获取前三个元素。最后,我们使用 forEach 方法打印输出结果。 过 limit 方法,我们限制了输出结果的大小,只获取了前三个元素。除了以上的基本用法之外,limit 方法还可以和其他 Stream 方法一起使用,进行更复杂的操作。

源码分析

java复制代码  @Override
    public final Stream<P_OUT> limit(long maxSize) {
        if (maxSize < 0)
            throw new IllegalArgumentException(Long.toString(maxSize));
        return SliceOps.makeRef(this, 0, maxSize);
    }
    
    
        public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
                                        long skip, long limit) {
        if (skip < 0)
            throw new IllegalArgumentException("Skip must be non-negative: " + skip);

        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
                                                      flags(limit)) {
            Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
                                                         long skip, long limit, long sizeIfKnown) {
                if (skip <= sizeIfKnown) {
                    // Use just the limit if the number of elements
                    // to skip is <= the known pipeline size
                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
                    skip = 0;
                }
                return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
            }
            
      }
    
  • 对于limit方法的实现,它会接收截取的长度,如果该值小于0,则抛出异常,否则会继续向下调用SliceOps.makeRef()。
  • 该方法中this代表当前流,skip代表需要跳过元素,比方说本来应该有4个元素,当跳过元素值为2,会跳过前面两个元素,获取后面两个。maxSize代表要截取的长度.
  • 在makeRef方法中的unorderedSkipLimitSpliterator()中接收了四个参数Spliterator,skip(跳过个数)、limit(截取个数)、sizeIfKnown(已知流大小)。如果跳过个数小于已知流大小,则判断跳过个数是否大于0,如果大于则取截取个数或已知流大小-跳过个数的两者最小值,否则取已知流大小-跳过个数的结果,作为跳过个数。 最后对集合基于跳过个数和截取个数进行切割。

skip

skip 操作是 Stream API 中的一个中间操作,它允许我们跳过流中的指定数量元素,然后返回一个新的流。这个操作在许多场景中都很有用,比如分页显示数据、去除前几条记录等情况。

使用 skip 操作获取前 N 个元素

java复制代码public class SkipDemo {

  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    numbers.stream()
        .skip(2)
        .forEach(System.out::println);
  }
}

使用 forEach 方法打印输出结果。 过 limit 方法,我们限制了输出结果的大小,只获取了前三个元素。除了以上的基本用法之外,limit 方法还可以和其他 Stream 方法一起使用,进行更复杂的操作。

映射操作

在Stream API中,映射操作是指将一个流中的每个元素都应用于一个函数,并将结果存储在一个新的流中。这个函数可以是一个Lambda表达式,也可以是一个方法引用。映射操作可以用于将一个流中的元素转化为另一种类型,或者提取出某个属性或字段。映射操作就是将一个集合的每个元素应用某个函数,并将返回值形成一个新的集合。

map

Stream接口中的map()方法是用于映射操作的主要方法之一。它接受一个Function函数作为参数,该函数将被应用于流中的每个元素,并返回一个新的流。

使用 Map 操作

java复制代码
public class MapDemo {

  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    List<Integer> squares = numbers.stream()
        .map(n -> n * n)
        .collect(Collectors.toList());
    }
}

上述代码中,map() 方法将集合中的每个元素进行平方计算,并将计算结果组成一个新的集合。

源码分析

 

java复制代码    public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
        Objects.requireNonNull(mapper);
        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
                return new Sink.ChainedReference<P_OUT, R>(sink) {
                    @Override
                    public void accept(P_OUT u) {
                        downstream.accept(mapper.apply(u));
                    }
                };
            }
        };
    }

将当前流给定函数中的元素,包含到一个新的流中进行返回其会接收一个Function函数式接口,内部接收一个 内部对Function函数式接口中的apply方法进行实现,接收一个对象,返回另外一个对象,并把这个内容存入当前流中,最后返回。

flatMap

除了map()方法之外,Stream API还提供了flatMap()方法用于进行扁平化映射操作。它接受一个Function函数作为参数,该函数将被应用于流中的每个元素,并返回一个新的流。不同之处在于,flatMap 操作在处理嵌套集合、展开多维数据结构等场景中非常有用。

使用 flatMap 操作

java复制代码public class FlatMapDemo {

  public static void main(String[] args) {
    List<List<Integer>> nestedList = Arrays.asList(
        Arrays.asList(1, 2, 3),
        Arrays.asList(4, 5, 6),
        Arrays.asList(7, 8, 9)
    );

    List<Integer> flattenedList = nestedList.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());

    System.out.println(flattenedList); // 输出 [1, 2, 3, 4, 5, 6, 7, 8, 9]
  }
}

在上面的示例中,我们使用flatMap()方法将每个子列表转换为流,然后合并这些流为一个扁平的流。

java复制代码  public static void main(String[] args) {
    List<String> words = Arrays.asList("Hello", "Stream", "API");

    List<Character> characters = words.stream()
        .flatMap(str -> str.chars().mapToObj(c -> (char) c))
        .collect(Collectors.toList());

    System.out.println(characters); // 输出 [H, e, l, l, o, S, t, r, e, a, m, A, P, I]

  }

在上述示例中,flatMap 操作将每个单词转换为字符流,然后将所有字符流合并为一个字符流。

匹配操作

在日常开发中,有时还需要判断集合中某些元素是否匹配对应条件,如果有的话,在进行后续的操作。在Stream API中也提供了相关方法供我们进行使用,如anyMatch、allMatch等。他们对应的就是 && 和 || 运算符。

anyMatch

anyMatch 操作是 Stream API 中的一个终端操作,用于检查流中是否至少有一个元素满足给定的条件。当流中有任何一个元素满足条件时,anyMatch 操作会返回 true,否则返回 false。并且对于它的操作,一般叫做短路求值

短路求值就是对于集合的一些操作,在正常情况下,无需处理整个集合就能得到结果,比方说通过 && 或者 || 连接一个判断条件,对于流来说,某些操作不用操作整个流就能得到结果

使用 anyMatch 操作

java复制代码public class AnyMatchDemo {

  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(3, 8, 4, 9, 2, 7);

    boolean hasNumberGreaterThanFive = numbers.stream()
        .anyMatch(number -> number > 5);
    System.out.println(hasNumberGreaterThanFive); // 输出 true
  }
}

在上述示例中,anyMatch 操作用于检查是否有元素大于 5,由于列表中存在 8、9 和 7,所以返回结果为 true。

allMatch

allMatch 操作是 Stream API 中的一个终端操作,用于检查流中的所有元素是否都满足给定的条件。当流中的所有元素都满足条件时,allMatch 操作会返回 true,否则返回 false。

使用 allMatch 操作

java复制代码 public static void main(String[] args) {
    List<String> words = Arrays.asList("apple", "banana", "orange", "grape");

    boolean allWordsHaveLengthThreeOrMore = words.stream()
        .allMatch(word -> word.length() >= 3);

    System.out.println(allWordsHaveLengthThreeOrMore); // 输出 true

  }

在上述示例中,allMatch 操作用于检查是否所有字符串的长度都大于等于 3,由于列表中的所有字符串都满足条件,所以返回结果为 true。

查找操作

在日常开发中,有时候还需要从集合中查找符合条件的元素,Stream 也提供了相关的 API,如 findAny 和 findFirst 等方法。同时上述方法也可以跟其他流操作组合使用

findAny

findAny 操作是 Stream API 中的一个终端操作,它用于在流中查找任意一个满足给定条件的元素。由于流可能是并行处理的,所以返回的是一个可能满足条件的元素,而不是第一个元素

java复制代码
  public static void main(String[] args) {
    List<String> words = Arrays.asList("apple", "banana", "orange", "grape");
    Optional<String> anyWordStartingWithA = words.stream()
        .filter(word -> word.startsWith("a"))
        .findAny();

    if (anyWordStartingWithA.isPresent()) {
      System.out.println("Found: " + anyWordStartingWithA.get()); // 输出 Found: apple 或其他以 "a" 开头的单词
    } else {
      System.out.println("Not found");
    }
  }

在上述示例中,filter 操作用于过滤以字母 "a" 开头的单词,然后使用 findAny 操作来查找任意一个满足条件的单词。

findFirst

findFirst 操作是 Stream API 中的一个终端操作,它用于在流中查找第一个满足给定条件的元素。由于流可能是并行处理的,所以返回的是第一个满足条件的元素。

使用 findFirst 操作

java复制代码  public static void main(String[] args) {
    List<String> words = Arrays.asList("apple", "banana", "orange", "grape");

    Optional<String> firstWordStartingWithA = words.stream()
        .filter(word -> word.startsWith("a"))
        .findFirst();

    if (firstWordStartingWithA.isPresent()) {
      System.out.println("Found: " + firstWordStartingWithA.get()); // 输出 Found: apple
    } else {
      System.out.println("Not found");
    }
  }

在上述示例中,filter 操作用于过滤以字母 "a" 开头的单词,然后使用 findFirst 操作来查找第一个满足条件的单词。

归约操作

归约操作是将一个流中的元素按照给定的操作进行合并,得到一个最终的结果。归约操作的基本思想是将流中的元素逐个进行合并,最终得到一个合并后的结果。

在 Stream API 中,reduce 方法用于实现归约操作。它有两种重载形式:

  1. Optional<T> reduce(BinaryOperator<T> accumulator)
  2. T reduce(T identity, BinaryOperator<T> accumulator)

其中,accumulator 是一个二元操作,用于定义合并规则。identity 是一个初始值,用于在归约开始前初始化结果。

使用归约操作

示例 1:对整数列表求和

假设我们有一个整数列表,现在我们想要计算列表中所有元素的和。

ini复制代码javaCopy code
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

int sum = numbers.stream()
                 .reduce(0, (a, b) -> a + b);

System.out.println("Sum: " + sum); // 输出 Sum: 15

在上述示例中,reduce 操作用于计算整数列表中所有元素的和。

示例 2:连接字符串列表

假设我们有一个字符串列表,现在我们想要将列表中的所有字符串连接成一个大字符串。

ini复制代码javaCopy code
List<String> words = Arrays.asList("Hello", "Stream", "API");

String concatenated = words.stream()
                           .reduce("", (a, b) -> a + " " + b);

System.out.println("Concatenated: " + concatenated); // 输出 Concatenated:  Hello Stream API

在上述示例中,reduce 操作用于将字符串列表中的所有字符串连接成一个大字符串。

示例 3:求最大值

假设我们有一个整数列表,现在我们想要找到列表中的最大值。

ini复制代码javaCopy code
List<Integer> numbers = Arrays.asList(5, 9, 3, 7, 1);

Optional<Integer> max = numbers.stream()
                               .reduce(Integer::max);

max.ifPresent(value -> System.out.println("Max: " + value)); // 输出 Max: 9

在上述示例中,reduce 操作用于找到整数列表中的最大值。

总结

Stream 是 Java 8 中引入的一个强大的功能,它提供了一种更简洁、更具有表现力的方式来处理集合数据。通过使用 Stream,我们可以轻松地进行过滤、映射、排序、归约等操作,从而实现更加优雅和函数式的代码编写。



Tags:Stream   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Java Stream 的使用技巧
Java Stream API 就像 Java 开发人员最常用的武器,它用途广泛、结构紧凑,可以轻松处理各种任务。它为开发人员提供了一种功能性和声明性的方式来表达复杂的数据转换和操作,使代...【详细内容】
2023-10-25  Search: Stream  点击:(116)  评论:(0)  加入收藏
四个步骤,掌握Spring Cloud Stream
随着微服务和云原生应用程序的不断发展,事件驱动架构成为了一种实现微服务之间高效通信的主流方法。在Java Spring生态系统中,Spring Cloud Stream是一个专门为事件驱动、云原...【详细内容】
2023-10-13  Search: Stream  点击:(213)  评论:(0)  加入收藏
通过线程池方式改造Stream.parallel()并行流
大家好,我是哪吒。上一篇简单聊一聊公平锁和非公平锁,parallel并行流,提到了一个IntStream.rangeClosed并行流问题,很多小伙伴,对这个比较陌生,想用线程池的方式改造一下。一、Int...【详细内容】
2023-10-12  Search: Stream  点击:(359)  评论:(0)  加入收藏
一文详解 JDK1.8 的 Lambda、Stream、LocalDateTime
今天跟小伙伴们聊聊 Java中JDK1.8的一些新语法特性使用,主要是Lambda、Stream和LocalDate日期的一些使用讲解。LambdaLambda介绍Lambda 表达式(lambda expression)是一个匿名...【详细内容】
2023-10-10  Search: Stream  点击:(331)  评论:(0)  加入收藏
StreamingLLM 框架问世,号称“可让大模型处理无限长度文本”
IT之家 10 月 6 日消息,麻省理工学院联合 Meta AI 的研究人员日前开发了一款名为 StreamingLLM 的框架,为大语言模型可能遇到的 RAM 与泛化问题提出了一系列解决方案,号称能够...【详细内容】
2023-10-06  Search: Stream  点击:(238)  评论:(0)  加入收藏
Redis Stream 数据结构实现原理真的很强
你好,我是码哥,一个拥抱硬核技术和对象,面向人民币编程的男人,设置星标不迷路。我在【Redis 使用 List 实现消息队列的利与弊】说过使用 List 实现消息队列有很多局限性。 没有...【详细内容】
2023-09-13  Search: Stream  点击:(361)  评论:(0)  加入收藏
再聊Java Stream的一些实战技能与注意点
在此前我的文章中,曾分2篇详细探讨了下JAVA中Stream流的相关操作,2篇文章在掘金社区收获了累计 10w+阅读、2k+点赞以及 5k+收藏的记录。能够得到众多小伙伴的认可,是技术分享过...【详细内容】
2023-09-13  Search: Stream  点击:(408)  评论:(0)  加入收藏
解锁多核处理器的力量:探索数据并行化在 Java 8 Stream 中的应用
在 Java 8 中引入的 Stream 为集合数据的处理带来了现代化的方式,而数据并行化则进一步提升了处理速度,充分发挥了多核处理器的优势。本篇博客将详细介绍数据并行化在 Java 8...【详细内容】
2023-08-22  Search: Stream  点击:(268)  评论:(0)  加入收藏
带你了解 Stream 的使用,提升集合开发效率
当涉及 Java 编程时,Java Stream 是一个功能强大且高效的工具,用于处理集合数据。它提供了一种声明式的方式来操作数据,可以显著简化代码并提高可读性。在本文中,我们将深入探讨...【详细内容】
2023-08-21  Search: Stream  点击:(341)  评论:(0)  加入收藏
Spring Cloud Stream 入门、主要概念与自定义消息发送与接收前言
快速入门五分钟左右为你展示如何创建一个Spring Cloud Stream的应用程序,它是如何从消息中间件中接收并输出接收的信息到console,这里的消息中间件有两种选择:RabbitMQ和Kafka,...【详细内容】
2023-08-12  Search: Stream  点击:(263)  评论:(0)  加入收藏
▌简易百科推荐
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  vivo互联网技术    Tags:Java 8   点击:(14)  评论:(0)  加入收藏
如何编写高性能的Java代码
作者 | 波哥审校 | 重楼在当今软件开发领域,编写高性能的Java代码是至关重要的。Java作为一种流行的编程语言,拥有强大的生态系统和丰富的工具链,但是要写出性能优异的Java代码...【详细内容】
2024-03-20    51CTO  Tags:Java代码   点击:(21)  评论:(0)  加入收藏
在Java应用程序中释放峰值性能:配置文件引导优化(PGO)概述
译者 | 李睿审校 | 重楼在Java开发领域,优化应用程序的性能是开发人员的持续追求。配置文件引导优化(Profile-Guided Optimization,PGO)是一种功能强大的技术,能够显著地提高Ja...【详细内容】
2024-03-18    51CTO  Tags:Java   点击:(24)  评论:(0)  加入收藏
Java生产环境下性能监控与调优详解
堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。堆被划分为新生代和老年代,新生代又被进一步划分为 Eden 和 Survivor 区,...【详细内容】
2024-02-04  大雷家吃饭    Tags:Java   点击:(56)  评论:(0)  加入收藏
在项目中如何避免和解决Java内存泄漏问题
在Java中,内存泄漏通常指的是程序中存在一些不再使用的对象或数据结构仍然保持对内存的引用,从而导致这些对象无法被垃圾回收器回收,最终导致内存占用不断增加,进而影响程序的性...【详细内容】
2024-02-01  编程技术汇  今日头条  Tags:Java   点击:(68)  评论:(0)  加入收藏
Java中的缓存技术及其使用场景
Java中的缓存技术是一种优化手段,用于提高应用程序的性能和响应速度。缓存技术通过将计算结果或者经常访问的数据存储在快速访问的存储介质中,以便下次需要时可以更快地获取。...【详细内容】
2024-01-30  编程技术汇    Tags:Java   点击:(72)  评论:(0)  加入收藏
JDK17 与 JDK11 特性差异浅谈
从 JDK11 到 JDK17 ,Java 的发展经历了一系列重要的里程碑。其中最重要的是 JDK17 的发布,这是一个长期支持(LTS)版本,它将获得长期的更新和支持,有助于保持程序的稳定性和可靠性...【详细内容】
2024-01-26  政采云技术  51CTO  Tags:JDK17   点击:(88)  评论:(0)  加入收藏
Java并发编程高阶技术
随着计算机硬件的发展,多核处理器的普及和内存容量的增加,利用多线程实现异步并发成为提升程序性能的重要途径。在Java中,多线程的使用能够更好地发挥硬件资源,提高程序的响应...【详细内容】
2024-01-19  大雷家吃饭    Tags:Java   点击:(105)  评论:(0)  加入收藏
这篇文章彻底让你了解Java与RPA
前段时间更新系统的时候,发现多了一个名为Power Automate的应用,打开了解后发现是一个自动化应用,根据其描述,可以自动执行所有日常任务,说的还是比较夸张,简单用了下,对于office、...【详细内容】
2024-01-17  Java技术指北  微信公众号  Tags:Java   点击:(95)  评论:(0)  加入收藏
Java 在 2023 年仍然流行的 25 个原因
译者 | 刘汪洋审校 | 重楼学习 Java 的过程中,我意识到在 90 年代末 OOP 正值鼎盛时期,Java 作为能够真正实现这些概念的语言显得尤为突出(尽管我此前学过 C++,但相比 Java 影响...【详细内容】
2024-01-10  刘汪洋  51CTO  Tags:Java   点击:(74)  评论:(0)  加入收藏
站内最新
站内热门
站内头条