最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?Stream流常用方法歸納整理及案例解析

 更新時(shí)間:2026年02月14日 13:41:36   作者:J_liaty  
文章介紹了Java?Stream?API的基本概念、優(yōu)勢(shì)、應(yīng)用場(chǎng)景、創(chuàng)建方法、中間操作和終端操作,并通過(guò)實(shí)際應(yīng)用案例展示了其使用方法,同時(shí),文章還強(qiáng)調(diào)了使用Stream時(shí)需要注意的事項(xiàng)和最佳實(shí)踐,感興趣的朋友跟隨小編一起看看吧

一、引言

1.1 什么是Java Stream

Java Stream API 是 Java 8 引入的一個(gè)重要特性,它提供了一種聲明式的方式來(lái)處理集合數(shù)據(jù)。Stream(流)是對(duì)集合(Collection)對(duì)象功能的增強(qiáng),專(zhuān)注于對(duì)集合對(duì)象進(jìn)行各種非常便利、高效的聚合操作(aggregate operation),或者大批量數(shù)據(jù)操作(bulk data operation)。

核心特點(diǎn):

  • 聲明式編程:使用類(lèi)似 SQL 查詢(xún)的語(yǔ)法風(fēng)格表達(dá)數(shù)據(jù)處理邏輯
  • 可組合性:可以將多個(gè)操作串聯(lián)起來(lái)形成流水線(xiàn)
  • 可并行化:支持并行處理,充分利用多核 CPU 的優(yōu)勢(shì)
  • 惰性求值:中間操作是惰性的,只有在終端操作時(shí)才會(huì)執(zhí)行
  • 內(nèi)部迭代:由 Stream API 內(nèi)部處理迭代邏輯,代碼更簡(jiǎn)潔

1.2 Stream的優(yōu)勢(shì)

特性傳統(tǒng)方式Stream方式
代碼簡(jiǎn)潔度需要大量循環(huán)和條件判斷鏈?zhǔn)秸{(diào)用,代碼更簡(jiǎn)潔
可讀性需要深入代碼邏輯才能理解聲明式描述,語(yǔ)義清晰
并行處理需要手動(dòng)編寫(xiě)線(xiàn)程代碼簡(jiǎn)單調(diào)用 parallel() 即可
性能優(yōu)化需要手動(dòng)優(yōu)化底層自動(dòng)優(yōu)化

1.3 應(yīng)用場(chǎng)景

  • 數(shù)據(jù)過(guò)濾與轉(zhuǎn)換:從集合中篩選、轉(zhuǎn)換數(shù)據(jù)
  • 統(tǒng)計(jì)聚合:計(jì)算總和、平均值、最大值、最小值等
  • 分組與分區(qū):將數(shù)據(jù)按條件分組或分區(qū)
  • 數(shù)據(jù)轉(zhuǎn)換:將一種數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為另一種
  • 復(fù)雜查詢(xún):類(lèi)似數(shù)據(jù)庫(kù)查詢(xún)的數(shù)據(jù)處理

二、Stream創(chuàng)建方法

2.1 從Collection創(chuàng)建

// 從List創(chuàng)建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> streamFromList = list.stream();
// 從Set創(chuàng)建
Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
Stream<Integer> streamFromSet = set.stream();
// 并行流
Stream<String> parallelStream = list.parallelStream();

方法簽名:

default Stream<E> stream()
default Stream<E> parallelStream()

2.2 從數(shù)組創(chuàng)建

// 從數(shù)組創(chuàng)建
String[] array = {"Java", "Python", "Go"};
Stream<String> streamFromArray = Arrays.stream(array);
// 指定范圍創(chuàng)建流
Stream<String> partialStream = Arrays.stream(array, 0, 2);
// 使用Stream.of()
Stream<String> streamOf = Stream.of("Hello", "World", "Stream");
// 創(chuàng)建空流
Stream<String> emptyStream = Stream.empty();

方法簽名:

public static <T> Stream<T> stream(T[] array)
public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive)
public static<T> Stream<T> of(T... values)
public static<T> Stream<T> empty()

2.3 從值創(chuàng)建

// 使用of()方法
Stream<String> valueStream = Stream.of("Java", "Stream", "API");
// 使用generate()生成無(wú)限流
Stream<Double> randomStream = Stream.generate(Math::random);
// 使用iterate()生成無(wú)限流
Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2);

方法簽名:

public static<T> Stream<T> generate(Supplier<T> s)
public static<T> Stream<T> iterate(T seed, UnaryOperator<T> f)

2.4 其他創(chuàng)建方式

// 從文件創(chuàng)建
try (Stream<String> lines = Files.lines(Paths.get("data.txt"))) {
    lines.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}
// 使用Pattern分割字符串創(chuàng)建流
String text = "hello,world,java";
Stream<String> patternStream = Pattern.compile(",").splitAsStream(text);
// 使用IntStream、LongStream、DoubleStream等基本類(lèi)型流
IntStream intStream = IntStream.range(1, 10);
LongStream longStream = LongStream.rangeClosed(1, 10);
DoubleStream doubleStream = DoubleStream.of(1.1, 2.2, 3.3);

三、中間操作方法

中間操作返回一個(gè)新的Stream,可以串聯(lián)多個(gè)中間操作形成流水線(xiàn)。

3.1 篩選與切片

filter() - 過(guò)濾元素

方法簽名:

Stream<T> filter(Predicate<? super T> predicate)

功能說(shuō)明: 根據(jù)給定的條件過(guò)濾流中的元素,保留滿(mǎn)足條件的元素。

參數(shù)解釋?zhuān)?/strong>

  • predicate:斷言函數(shù),用于測(cè)試每個(gè)元素是否滿(mǎn)足條件

返回值: 返回一個(gè)新的Stream,只包含滿(mǎn)足條件的元素

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 過(guò)濾偶數(shù)
List<Integer> evenNumbers = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.toList());
System.out.println("偶數(shù): " + evenNumbers);
// 過(guò)濾長(zhǎng)度大于3的字符串
List<String> words = Arrays.asList("Java", "Python", "Go", "JavaScript");
List<String> longWords = words.stream()
    .filter(word -> word.length() > 3)
    .collect(Collectors.toList());
System.out.println("長(zhǎng)單詞: " + longWords);

運(yùn)行結(jié)果:

偶數(shù): [2, 4, 6, 8, 10]
長(zhǎng)單詞: [Java, Python, JavaScript]

distinct() - 去重

方法簽名:

Stream<T> distinct()

功能說(shuō)明: 去除流中重復(fù)的元素(基于對(duì)象的equals()方法)

參數(shù)解釋?zhuān)?/strong> 無(wú)參數(shù)

返回值: 返回一個(gè)新的Stream,不包含重復(fù)元素

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 5, 5);
List<Integer> distinctNumbers = numbers.stream()
    .distinct()
    .collect(Collectors.toList());
System.out.println("去重后: " + distinctNumbers);
// 對(duì)對(duì)象去重(需要重寫(xiě)equals和hashCode)
class Person {
    String name;
    int age;
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return name + "(" + age + ")";
    }
}
List<Person> people = Arrays.asList(
    new Person("張三", 25),
    new Person("李四", 30),
    new Person("張三", 25),
    new Person("王五", 28)
);
List<Person> distinctPeople = people.stream()
    .distinct()
    .collect(Collectors.toList());
System.out.println("去重后的人員: " + distinctPeople);

運(yùn)行結(jié)果:

去重后: [1, 2, 3, 4, 5]
去重后的人員: [張三(25), 李四(30), 王五(28)]

limit() - 限制元素?cái)?shù)量

方法簽名:

Stream<T> limit(long maxSize)

功能說(shuō)明: 截取流的前N個(gè)元素

參數(shù)解釋?zhuān)?/strong>

  • maxSize:要返回的元素?cái)?shù)量

返回值: 返回一個(gè)新的Stream,最多包含maxSize個(gè)元素

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 獲取前5個(gè)元素
List<Integer> firstFive = numbers.stream()
    .limit(5)
    .collect(Collectors.toList());
System.out.println("前5個(gè)元素: " + firstFive);
// 先過(guò)濾再限制
List<Integer> firstThreeEven = numbers.stream()
    .filter(n -> n % 2 == 0)
    .limit(3)
    .collect(Collectors.toList());
System.out.println("前3個(gè)偶數(shù): " + firstThreeEven);

運(yùn)行結(jié)果:

前5個(gè)元素: [1, 2, 3, 4, 5]
前3個(gè)偶數(shù): [2, 4, 6]

skip() - 跳過(guò)元素

方法簽名:

Stream<T> skip(long n)

功能說(shuō)明: 跳過(guò)流的前N個(gè)元素

參數(shù)解釋?zhuān)?/strong>

  • n:要跳過(guò)的元素?cái)?shù)量

返回值: 返回一個(gè)新的Stream,丟棄前n個(gè)元素后的剩余元素

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 跳過(guò)前5個(gè)元素
List<Integer> afterFive = numbers.stream()
    .skip(5)
    .collect(Collectors.toList());
System.out.println("跳過(guò)前5個(gè)后: " + afterFive);
// 獲取第4到第7個(gè)元素
List<Integer> middleElements = numbers.stream()
    .skip(3)
    .limit(4)
    .collect(Collectors.toList());
System.out.println("第4到第7個(gè)元素: " + middleElements);

運(yùn)行結(jié)果:

跳過(guò)前5個(gè)后: [6, 7, 8, 9, 10]
第4到第7個(gè)元素: [4, 5, 6, 7]

3.2 映射

map() - 元素轉(zhuǎn)換

方法簽名:

<R> Stream<R> map(Function<? super T, ? extends R> mapper)

功能說(shuō)明: 將流中的每個(gè)元素轉(zhuǎn)換為另一種形式

參數(shù)解釋?zhuān)?/strong>

  • mapper:轉(zhuǎn)換函數(shù),接收一個(gè)元素,返回轉(zhuǎn)換后的元素

返回值: 返回一個(gè)新的Stream,包含轉(zhuǎn)換后的元素

代碼示例:

// 將字符串轉(zhuǎn)換為大寫(xiě)
List<String> words = Arrays.asList("java", "python", "go");
List<String> upperWords = words.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());
System.out.println("大寫(xiě)字母: " + upperWords);
// 將對(duì)象提取屬性
class Employee {
    String name;
    int salary;
    Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }
    public String getName() { return name; }
    public int getSalary() { return salary; }
}
List<Employee> employees = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("王五", 6000)
);
List<String> names = employees.stream()
    .map(Employee::getName)
    .collect(Collectors.toList());
System.out.println("員工姓名: " + names);
// 計(jì)算平方
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squares = numbers.stream()
    .map(n -> n * n)
    .collect(Collectors.toList());
System.out.println("平方數(shù): " + squares);

運(yùn)行結(jié)果:

大寫(xiě)字母: [JAVA, PYTHON, GO]
員工姓名: [張三, 李四, 王五]
平方數(shù): [1, 4, 9, 16, 25]

flatMap() - 扁平化映射

方法簽名:

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

功能說(shuō)明: 將流中的每個(gè)元素轉(zhuǎn)換為一個(gè)流,然后將所有流連接成一個(gè)流

參數(shù)解釋?zhuān)?/strong>

  • mapper:轉(zhuǎn)換函數(shù),接收一個(gè)元素,返回一個(gè)Stream

返回值: 返回一個(gè)新的Stream,包含所有子流的元素

代碼示例:

// 將嵌套集合展平
List<List<String>> nestedList = Arrays.asList(
    Arrays.asList("a", "b"),
    Arrays.asList("c", "d", "e"),
    Arrays.asList("f")
);
List<String> flattened = nestedList.stream()
    .flatMap(List::stream)
    .collect(Collectors.toList());
System.out.println("展平后: " + flattened);
// 將字符串的字符拆分成流
List<String> words = Arrays.asList("Hello", "World");
List<String> characters = words.stream()
    .flatMap(word -> word.chars().mapToObj(c -> String.valueOf((char) c)))
    .collect(Collectors.toList());
System.out.println("字符列表: " + characters);
// 獲取所有員工的所有技能
class Employee {
    String name;
    List<String> skills;
    Employee(String name, List<String> skills) {
        this.name = name;
        this.skills = skills;
    }
    public List<String> getSkills() { return skills; }
}
List<Employee> employees = Arrays.asList(
    new Employee("張三", Arrays.asList("Java", "Python")),
    new Employee("李四", Arrays.asList("Go", "Rust", "C++")),
    new Employee("王五", Arrays.asList("JavaScript"))
);
List<String> allSkills = employees.stream()
    .flatMap(emp -> emp.getSkills().stream())
    .distinct()
    .collect(Collectors.toList());
System.out.println("所有技能: " + allSkills);

運(yùn)行結(jié)果:

展平后: [a, b, c, d, e, f]
字符列表: [H, e, l, l, o, W, o, r, l, d]
所有技能: [Java, Python, Go, Rust, C++, JavaScript]

3.3 排序

sorted() - 自然排序

方法簽名:

Stream<T> sorted()

功能說(shuō)明: 按自然順序?qū)α髦械脑剡M(jìn)行排序

參數(shù)解釋?zhuān)?/strong> 無(wú)參數(shù)

返回值: 返回一個(gè)新的Stream,元素已按自然順序排序

代碼示例:

List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3);
List<Integer> sortedNumbers = numbers.stream()
    .sorted()
    .collect(Collectors.toList());
System.out.println("升序排序: " + sortedNumbers);
List<String> words = Arrays.asList("Java", "Python", "Go", "C");
List<String> sortedWords = words.stream()
    .sorted()
    .collect(Collectors.toList());
System.out.println("字母排序: " + sortedWords);

運(yùn)行結(jié)果:

升序排序: [1, 2, 3, 5, 8, 9]
字母排序: [C, Go, Java, Python]

sorted(Comparator) - 自定義排序

方法簽名:

Stream<T> sorted(Comparator<? super T> comparator)

功能說(shuō)明: 根據(jù)給定的比較器對(duì)流中的元素進(jìn)行排序

參數(shù)解釋?zhuān)?/strong>

  • comparator:比較器,用于定義排序規(guī)則

返回值: 返回一個(gè)新的Stream,元素已按指定規(guī)則排序

代碼示例:

class Employee {
    String name;
    int salary;
    Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }
    public String getName() { return name; }
    public int getSalary() { return salary; }
    @Override
    public String toString() {
        return name + "(" + salary + ")";
    }
}
List<Employee> employees = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("王五", 6000)
);
// 按薪資升序排序
List<Employee> bySalaryAsc = employees.stream()
    .sorted(Comparator.comparingInt(Employee::getSalary))
    .collect(Collectors.toList());
System.out.println("按薪資升序: " + bySalaryAsc);
// 按薪資降序排序
List<Employee> bySalaryDesc = employees.stream()
    .sorted(Comparator.comparingInt(Employee::getSalary).reversed())
    .collect(Collectors.toList());
System.out.println("按薪資降序: " + bySalaryDesc);
// 多條件排序:先按薪資,再按姓名
List<Employee> multiSort = employees.stream()
    .sorted(Comparator.comparingInt(Employee::getSalary)
        .thenComparing(Employee::getName))
    .collect(Collectors.toList());
System.out.println("多條件排序: " + multiSort);

運(yùn)行結(jié)果:

按薪資升序: [張三(5000), 王五(6000), 李四(8000)]
按薪資降序: [李四(8000), 王五(6000), 張三(5000)]
多條件排序: [張三(5000), 王五(6000), 李四(8000)]

3.4 其他中間操作

peek() - 查看元素

方法簽名:

Stream<T> peek(Consumer<? super T> action)

功能說(shuō)明: 對(duì)流中的每個(gè)元素執(zhí)行指定操作,主要用于調(diào)試

參數(shù)解釋?zhuān)?/strong>

  • action:要對(duì)每個(gè)元素執(zhí)行的操作

返回值: 返回一個(gè)新的Stream,元素不變,但每個(gè)元素都會(huì)執(zhí)行action

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 使用peek進(jìn)行調(diào)試
List<Integer> result = numbers.stream()
    .peek(n -> System.out.println("處理前: " + n))
    .map(n -> n * n)
    .peek(n -> System.out.println("處理后: " + n))
    .collect(Collectors.toList());
System.out.println("最終結(jié)果: " + result);

運(yùn)行結(jié)果:

處理前: 1
處理后: 1
處理前: 2
處理后: 4
處理前: 3
處理后: 9
處理前: 4
處理后: 16
處理前: 5
處理后: 25
最終結(jié)果: [1, 4, 9, 16, 25]

四、終端操作方法

終端操作會(huì)觸發(fā)流的執(zhí)行,并返回結(jié)果或產(chǎn)生副作用。

4.1 查找與匹配

allMatch() - 全部匹配

方法簽名:

boolean allMatch(Predicate<? super T> predicate)

功能說(shuō)明: 檢查流中的所有元素是否都滿(mǎn)足指定條件

參數(shù)解釋?zhuān)?/strong>

  • predicate:斷言函數(shù),用于測(cè)試每個(gè)元素

返回值: 如果所有元素都滿(mǎn)足條件,返回true;否則返回false

代碼示例:

List<Integer> numbers = Arrays.asList(2, 4, 6, 8, 10);
boolean allEven = numbers.stream()
    .allMatch(n -> n % 2 == 0);
System.out.println("全部是偶數(shù): " + allEven);
List<Integer> numbers2 = Arrays.asList(2, 4, 6, 8, 9);
boolean allEven2 = numbers2.stream()
    .allMatch(n -> n % 2 == 0);
System.out.println("全部是偶數(shù): " + allEven2);

運(yùn)行結(jié)果:

全部是偶數(shù): true
全部是偶數(shù): false

anyMatch() - 任意匹配

方法簽名:

boolean anyMatch(Predicate<? super T> predicate)

功能說(shuō)明: 檢查流中是否有任意元素滿(mǎn)足指定條件

參數(shù)解釋?zhuān)?/strong>

  • predicate:斷言函數(shù),用于測(cè)試每個(gè)元素

返回值: 如果至少有一個(gè)元素滿(mǎn)足條件,返回true;否則返回false

代碼示例:

List<Integer> numbers = Arrays.asList(1, 3, 5, 7, 8);
boolean hasEven = numbers.stream()
    .anyMatch(n -> n % 2 == 0);
System.out.println("存在偶數(shù): " + hasEven);
List<String> words = Arrays.asList("Java", "Python", "Go");
boolean hasJava = words.stream()
    .anyMatch(word -> word.equals("Java"));
System.out.println("包含Java: " + hasJava);

運(yùn)行結(jié)果:

存在偶數(shù): true
包含Java: true

noneMatch() - 無(wú)匹配

方法簽名:

boolean noneMatch(Predicate<? super T> predicate)

功能說(shuō)明: 檢查流中是否沒(méi)有元素滿(mǎn)足指定條件

參數(shù)解釋?zhuān)?/strong>

  • predicate:斷言函數(shù),用于測(cè)試每個(gè)元素

返回值: 如果沒(méi)有元素滿(mǎn)足條件,返回true;否則返回false

代碼示例:

List<Integer> numbers = Arrays.asList(1, 3, 5, 7, 9);
boolean noEven = numbers.stream()
    .noneMatch(n -> n % 2 == 0);
System.out.println("沒(méi)有偶數(shù): " + noEven);
List<String> words = Arrays.asList("Java", "Python", "Go");
boolean noC = words.stream()
    .noneMatch(word -> word.startsWith("C"));
System.out.println("沒(méi)有C開(kāi)頭的單詞: " + noC);

運(yùn)行結(jié)果:

沒(méi)有偶數(shù): true
沒(méi)有C開(kāi)頭的單詞: true

findFirst() - 查找第一個(gè)

方法簽名:

Optional<T> findFirst()

功能說(shuō)明: 返回流中的第一個(gè)元素

參數(shù)解釋?zhuān)?/strong> 無(wú)參數(shù)

返回值: 返回一個(gè)Optional,包含第一個(gè)元素;如果流為空,返回空的Optional

代碼示例:

List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9);
Optional<Integer> first = numbers.stream()
    .findFirst();
System.out.println("第一個(gè)元素: " + first.orElse(-1));
List<String> words = Arrays.asList("Java", "Python", "Go");
Optional<String> firstLong = words.stream()
    .filter(word -> word.length() > 3)
    .findFirst();
System.out.println("第一個(gè)長(zhǎng)單詞: " + firstLong.orElse("無(wú)"));

運(yùn)行結(jié)果:

第一個(gè)元素: 3
第一個(gè)長(zhǎng)單詞: Java

findAny() - 查找任意一個(gè)

方法簽名:

Optional<T> findAny()

功能說(shuō)明: 返回流中的任意一個(gè)元素

參數(shù)解釋?zhuān)?/strong> 無(wú)參數(shù)

返回值: 返回一個(gè)Optional,包含任意一個(gè)元素;如果流為空,返回空的Optional

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> any = numbers.stream()
    .findAny();
System.out.println("任意元素: " + any.orElse(-1));
// 在并行流中,findAny可能返回不同的元素
List<Integer> parallelResult = numbers.parallelStream()
    .filter(n -> n > 2)
    .findAny();
System.out.println("并行流中大于2的任意元素: " + parallelResult.orElse(-1));

運(yùn)行結(jié)果:

任意元素: 1
并行流中大于2的任意元素: 3(或4、5)

4.2 歸約

reduce() - 歸約操作

方法簽名:

Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)

功能說(shuō)明: 將流中的元素組合成一個(gè)結(jié)果

參數(shù)解釋?zhuān)?/strong>

  • identity:初始值
  • accumulator:累加器函數(shù),定義如何組合元素
  • combiner:合并器函數(shù),用于并行流時(shí)合并部分結(jié)果

返回值: 返回歸約后的結(jié)果

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 無(wú)初始值,返回Optional
Optional<Integer> sum1 = numbers.stream()
    .reduce((a, b) -> a + b);
System.out.println("求和(無(wú)初始值): " + sum1.orElse(0));
// 有初始值
int sum2 = numbers.stream()
    .reduce(0, (a, b) -> a + b);
System.out.println("求和(有初始值): " + sum2);
// 使用方法引用
int sum3 = numbers.stream()
    .reduce(0, Integer::sum);
System.out.println("求和(方法引用): " + sum3);
// 求最大值
Optional<Integer> max = numbers.stream()
    .reduce(Integer::max);
System.out.println("最大值: " + max.orElse(0));
// 求最小值
Optional<Integer> min = numbers.stream()
    .reduce(Integer::min);
System.out.println("最小值: " + min.orElse(0));
// 求乘積
int product = numbers.stream()
    .reduce(1, (a, b) -> a * b);
System.out.println("乘積: " + product);
// 字符串連接
List<String> words = Arrays.asList("Java", "Stream", "API");
String joined = words.stream()
    .reduce("", (a, b) -> a + b);
System.out.println("字符串連接: " + joined);
String joinedWithComma = words.stream()
    .reduce((a, b) -> a + "," + b)
    .orElse("");
System.out.println("用逗號(hào)連接: " + joinedWithComma);

運(yùn)行結(jié)果:

求和(無(wú)初始值): 15
求和(有初始值): 15
求和(方法引用): 15
最大值: 5
最小值: 1
乘積: 120
字符串連接: JavaStreamAPI
用逗號(hào)連接: Java,Stream,API

4.3 收集

collect() - 收集結(jié)果

方法簽名:

<R> R collect(Collector<? super T, A, R> collector)
<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)

功能說(shuō)明: 將流中的元素收集到容器中

參數(shù)解釋?zhuān)?/strong>

  • collector:收集器,定義如何收集元素
  • supplier:提供結(jié)果容器
  • accumulator:累加器,將元素添加到容器
  • combiner:合并器,用于并行流時(shí)合并部分結(jié)果

返回值: 返回收集后的結(jié)果

Collectors常用方法

toList() - 收集到List
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.toList());
System.out.println("偶數(shù)列表: " + evenNumbers);

運(yùn)行結(jié)果:

偶數(shù)列表: [2, 4]

toSet() - 收集到Set
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4);
Set<Integer> uniqueNumbers = numbers.stream()
    .collect(Collectors.toSet());
System.out.println("唯一數(shù)字: " + uniqueNumbers);

運(yùn)行結(jié)果:

唯一數(shù)字: [1, 2, 3, 4]

toCollection() - 收集到指定集合
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);
LinkedList<Integer> linkedList = numbers.stream()
    .sorted()
    .collect(Collectors.toCollection(LinkedList::new));
System.out.println("有序鏈表: " + linkedList);

運(yùn)行結(jié)果:

有序鏈表: [1, 2, 5, 8, 9]

toMap() - 收集到Map
class Employee {
    String name;
    int salary;
    Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }
    public String getName() { return name; }
    public int getSalary() { return salary; }
    @Override
    public String toString() {
        return name + "(" + salary + ")";
    }
}
List<Employee> employees = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("王五", 6000)
);
// 轉(zhuǎn)換為Map:姓名->員工對(duì)象
Map<String, Employee> nameToEmployee = employees.stream()
    .collect(Collectors.toMap(Employee::getName, e -> e));
System.out.println("姓名到員工: " + nameToEmployee);
// 轉(zhuǎn)換為Map:姓名->薪資
Map<String, Integer> nameToSalary = employees.stream()
    .collect(Collectors.toMap(Employee::getName, Employee::getSalary));
System.out.println("姓名到薪資: " + nameToSalary);
// 處理鍵沖突(使用新值)
List<Employee> employeesWithConflict = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("張三", 7000)  // 同名員工
);
Map<String, Integer> handleConflict = employeesWithConflict.stream()
    .collect(Collectors.toMap(
        Employee::getName, 
        Employee::getSalary,
        (oldValue, newValue) -> newValue
    ));
System.out.println("處理鍵沖突: " + handleConflict);

運(yùn)行結(jié)果:

姓名到員工: {張三=張三(5000), 李四=李四(8000), 王五=王五(6000)}
姓名到薪資: {張三=5000, 李四=8000, 王五=6000}
處理鍵沖突: {張三=7000, 李四=8000}

joining() - 字符串連接
List<String> words = Arrays.asList("Java", "Stream", "API");
// 直接連接
String joined1 = words.stream()
    .collect(Collectors.joining());
System.out.println("直接連接: " + joined1);
// 用逗號(hào)分隔
String joined2 = words.stream()
    .collect(Collectors.joining(", "));
System.out.println("逗號(hào)分隔: " + joined2);
// 用分隔符、前綴、后綴
String joined3 = words.stream()
    .collect(Collectors.joining(", ", "[", "]"));
System.out.println("帶前后綴: " + joined3);

運(yùn)行結(jié)果:

直接連接: JavaStreamAPI
逗號(hào)分隔: Java, Stream, API
帶前后綴: [Java, Stream, API]

groupingBy() - 分組
class Employee {
    String name;
    String department;
    int salary;
    Employee(String name, String department, int salary) {
        this.name = name;
        this.department = department;
        this.salary = salary;
    }
    public String getName() { return name; }
    public String getDepartment() { return department; }
    public int getSalary() { return salary; }
    @Override
    public String toString() {
        return name + "(" + salary + ")";
    }
}
List<Employee> employees = Arrays.asList(
    new Employee("張三", "技術(shù)部", 5000),
    new Employee("李四", "技術(shù)部", 8000),
    new Employee("王五", "市場(chǎng)部", 6000),
    new Employee("趙六", "市場(chǎng)部", 7000),
    new Employee("孫七", "財(cái)務(wù)部", 5500)
);
// 按部門(mén)分組
Map<String, List<Employee>> byDept = employees.stream()
    .collect(Collectors.groupingBy(Employee::getDepartment));
System.out.println("按部門(mén)分組: " + byDept);
// 分組后計(jì)數(shù)
Map<String, Long> countByDept = employees.stream()
    .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.counting()));
System.out.println("各部門(mén)人數(shù): " + countByDept);
// 分組后求平均值
Map<String, Double> avgSalaryByDept = employees.stream()
    .collect(Collectors.groupingBy(
        Employee::getDepartment,
        Collectors.averagingInt(Employee::getSalary)
    ));
System.out.println("各部門(mén)平均薪資: " + avgSalaryByDept);
// 多級(jí)分組:先按部門(mén),再按薪資范圍
Map<String, Map<String, List<Employee>>> multiGroup = employees.stream()
    .collect(Collectors.groupingBy(
        Employee::getDepartment,
        Collectors.groupingBy(e -> e.getSalary() > 6000 ? "高薪" : "普通")
    ));
System.out.println("多級(jí)分組: " + multiGroup);

運(yùn)行結(jié)果:

按部門(mén)分組: {技術(shù)部=[張三(5000), 李四(8000)], 市場(chǎng)部=[王五(6000), 趙六(7000)], 財(cái)務(wù)部=[孫七(5500)]}
各部門(mén)人數(shù): {技術(shù)部=2, 市場(chǎng)部=2, 財(cái)務(wù)部=1}
各部門(mén)平均薪資: {技術(shù)部=6500.0, 市場(chǎng)部=6500.0, 財(cái)務(wù)部=5500.0}
多級(jí)分組: {技術(shù)部={普通=[張三(5000)], 高薪=[李四(8000)]}, 市場(chǎng)部={普通=[王五(6000)], 高薪=[趙六(7000)]}, 財(cái)務(wù)部={普通=[孫七(5500)]}}

partitioningBy() - 分區(qū)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 按是否為偶數(shù)分區(qū)
Map<Boolean, List<Integer>> partitionByEven = numbers.stream()
    .collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println("按奇偶分區(qū): " + partitionByEven);
// 分區(qū)后計(jì)數(shù)
Map<Boolean, Long> countPartition = numbers.stream()
    .collect(Collectors.partitioningBy(n -> n % 2 == 0, Collectors.counting()));
System.out.println("奇偶數(shù)量: " + countPartition);
// 按薪資是否大于6000分區(qū)
class Employee {
    String name;
    int salary;
    Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }
    public String getName() { return name; }
    public int getSalary() { return salary; }
    @Override
    public String toString() {
        return name + "(" + salary + ")";
    }
}
List<Employee> employees = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("王五", 6000),
    new Employee("趙六", 7000)
);
Map<Boolean, List<Employee>> partitionBySalary = employees.stream()
    .collect(Collectors.partitioningBy(e -> e.getSalary() > 6000));
System.out.println("按薪資分區(qū): " + partitionBySalary);

運(yùn)行結(jié)果:

按奇偶分區(qū): {false=[1, 3, 5, 7, 9], true=[2, 4, 6, 8, 10]}
奇偶數(shù)量: {false=5, true=5}
按薪資分區(qū): {false=[張三(5000), 王五(6000)], true=[李四(8000), 趙六(7000)]}

mapping() - 映射后收集
List<String> words = Arrays.asList("java", "stream", "api", "lambda");
// 轉(zhuǎn)換為大寫(xiě)后收集
List<String> upperWords = words.stream()
    .collect(Collectors.mapping(String::toUpperCase, Collectors.toList()));
System.out.println("大寫(xiě)單詞: " + upperWords);
// 分組后映射
Map<Integer, List<String>> byLength = words.stream()
    .collect(Collectors.groupingBy(
        String::length,
        Collectors.mapping(String::toUpperCase, Collectors.toList())
    ));
System.out.println("按長(zhǎng)度分組并轉(zhuǎn)大寫(xiě): " + byLength);

運(yùn)行結(jié)果:

大寫(xiě)單詞: [JAVA, STREAM, API, LAMBDA]
按長(zhǎng)度分組并轉(zhuǎn)大寫(xiě): {4=[JAVA, API], 6=[STREAM, LAMBDA]}

4.4 統(tǒng)計(jì)

count() - 計(jì)數(shù)

方法簽名:

long count()

功能說(shuō)明: 返回流中元素的數(shù)量

參數(shù)解釋?zhuān)?/strong> 無(wú)參數(shù)

返回值: 返回元素個(gè)數(shù)

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 總數(shù)
long total = numbers.stream().count();
System.out.println("總數(shù): " + total);
// 偶數(shù)個(gè)數(shù)
long evenCount = numbers.stream()
    .filter(n -> n % 2 == 0)
    .count();
System.out.println("偶數(shù)個(gè)數(shù): " + evenCount);
List<String> words = Arrays.asList("Java", "Python", "Go", "JavaScript");
long longWordCount = words.stream()
    .filter(word -> word.length() > 3)
    .count();
System.out.println("長(zhǎng)單詞個(gè)數(shù): " + longWordCount);

運(yùn)行結(jié)果:

總數(shù): 10
偶數(shù)個(gè)數(shù): 5
長(zhǎng)單詞個(gè)數(shù): 3

max() - 最大值

方法簽名:

Optional<T> max(Comparator<? super T> comparator)

功能說(shuō)明: 根據(jù)比較器返回流中的最大元素

參數(shù)解釋?zhuān)?/strong>

  • comparator:比較器,用于比較元素大小

返回值: 返回Optional,包含最大元素;如果流為空,返回空的Optional

代碼示例:

List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3);
Optional<Integer> maxNumber = numbers.stream()
    .max(Comparator.naturalOrder());
System.out.println("最大數(shù)字: " + maxNumber.orElse(-1));
class Employee {
    String name;
    int salary;
    Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }
    public String getName() { return name; }
    public int getSalary() { return salary; }
    @Override
    public String toString() {
        return name + "(" + salary + ")";
    }
}
List<Employee> employees = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("王五", 6000)
);
Optional<Employee> highestPaid = employees.stream()
    .max(Comparator.comparingInt(Employee::getSalary));
System.out.println("最高薪資員工: " + highestPaid);

運(yùn)行結(jié)果:

最大數(shù)字: 9
最高薪資員工: 李四(8000)

min() - 最小值

方法簽名:

Optional<T> min(Comparator<? super T> comparator)

功能說(shuō)明: 根據(jù)比較器返回流中的最小元素

參數(shù)解釋?zhuān)?/strong>

  • comparator:比較器,用于比較元素大小

返回值: 返回Optional,包含最小元素;如果流為空,返回空的Optional

代碼示例:

List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3);
Optional<Integer> minNumber = numbers.stream()
    .min(Comparator.naturalOrder());
System.out.println("最小數(shù)字: " + minNumber.orElse(-1));
List<String> words = Arrays.asList("Java", "Python", "Go", "C");
Optional<String> shortest = words.stream()
    .min(Comparator.comparingInt(String::length));
System.out.println("最短單詞: " + shortest.orElse("無(wú)"));

運(yùn)行結(jié)果:

最小數(shù)字: 1
最短單詞: C

average() - 平均值(IntStream/LongStream/DoubleStream)

方法簽名:

OptionalDouble average()

功能說(shuō)明: 計(jì)算流中元素的平均值

參數(shù)解釋?zhuān)?/strong> 無(wú)參數(shù)

返回值: 返回OptionalDouble,包含平均值;如果流為空,返回空的OptionalDouble

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 計(jì)算平均值
OptionalDouble average = numbers.stream()
    .mapToInt(Integer::intValue)
    .average();
System.out.println("平均值: " + average.orElse(0));
List<Employee> employees = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("王五", 6000)
);
OptionalDouble avgSalary = employees.stream()
    .mapToInt(Employee::getSalary)
    .average();
System.out.println("平均薪資: " + avgSalary.orElse(0));
// 使用Collectors.averagingInt
Double avgSalary2 = employees.stream()
    .collect(Collectors.averagingInt(Employee::getSalary));
System.out.println("平均薪資(方式2): " + avgSalary2);

運(yùn)行結(jié)果:

平均值: 3.0
平均薪資: 6333.333333333333
平均薪資(方式2): 6333.333333333333

sum() - 求和(IntStream/LongStream/DoubleStream)

方法簽名:

int sum()  // IntStream
long sum() // LongStream
double sum() // DoubleStream

功能說(shuō)明: 計(jì)算流中元素的總和

參數(shù)解釋?zhuān)?/strong> 無(wú)參數(shù)

返回值: 返回元素的和

代碼示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 求和
int sum = numbers.stream()
    .mapToInt(Integer::intValue)
    .sum();
System.out.println("求和: " + sum);
// 使用reduce求和
int sum2 = numbers.stream()
    .reduce(0, Integer::sum);
System.out.println("求和(reduce): " + sum2);
List<Employee> employees = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("王五", 6000)
);
int totalSalary = employees.stream()
    .mapToInt(Employee::getSalary)
    .sum();
System.out.println("總薪資: " + totalSalary);

運(yùn)行結(jié)果:

求和: 15
求和(reduce): 15
總薪資: 19000

summarizingInt/Long/Double - 綜合統(tǒng)計(jì)

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
IntSummaryStatistics stats = numbers.stream()
    .collect(Collectors.summarizingInt(Integer::intValue));
System.out.println("綜合統(tǒng)計(jì):");
System.out.println("  個(gè)數(shù): " + stats.getCount());
System.out.println("  總和: " + stats.getSum());
System.out.println("  平均值: " + stats.getAverage());
System.out.println("  最小值: " + stats.getMin());
System.out.println("  最大值: " + stats.getMax());
List<Employee> employees = Arrays.asList(
    new Employee("張三", 5000),
    new Employee("李四", 8000),
    new Employee("王五", 6000)
);
IntSummaryStatistics salaryStats = employees.stream()
    .collect(Collectors.summarizingInt(Employee::getSalary));
System.out.println("\n薪資統(tǒng)計(jì):");
System.out.println("  人數(shù): " + salaryStats.getCount());
System.out.println("  總薪資: " + salaryStats.getSum());
System.out.println("  平均薪資: " + salaryStats.getAverage());
System.out.println("  最低薪資: " + salaryStats.getMin());
System.out.println("  最高薪資: " + salaryStats.getMax());

運(yùn)行結(jié)果:

綜合統(tǒng)計(jì):
  個(gè)數(shù): 10
  總和: 55
  平均值: 5.5
  最小值: 1
  最大值: 10

薪資統(tǒng)計(jì):
  人數(shù): 3
  總薪資: 19000
  平均薪資: 6333.333333333333
  最低薪資: 5000
  最高薪資: 8000

五、實(shí)際應(yīng)用案例

案例一:電商訂單數(shù)據(jù)處理

場(chǎng)景描述: 處理訂單數(shù)據(jù),統(tǒng)計(jì)各商品類(lèi)別的銷(xiāo)售情況。

import java.util.*;
import java.util.stream.Collectors;
class OrderItem {
    String productId;
    String productName;
    String category;
    double price;
    int quantity;
    OrderItem(String productId, String productName, String category, double price, int quantity) {
        this.productId = productId;
        this.productName = productName;
        this.category = category;
        this.price = price;
        this.quantity = quantity;
    }
    public String getCategory() { return category; }
    public double getPrice() { return price; }
    public int getQuantity() { return quantity; }
    public double getTotal() { return price * quantity; }
    @Override
    public String toString() {
        return productName + "(" + category + ") - 數(shù)量:" + quantity + " 單價(jià):" + price;
    }
}
class Order {
    String orderId;
    List<OrderItem> items;
    Date orderDate;
    Order(String orderId, List<OrderItem> items, Date orderDate) {
        this.orderId = orderId;
        this.items = items;
        this.orderDate = orderDate;
    }
    public List<OrderItem> getItems() { return items; }
    public Date getOrderDate() { return orderDate; }
}
public class EcommerceAnalysis {
    public static void main(String[] args) {
        // 創(chuàng)建訂單數(shù)據(jù)
        List<Order> orders = Arrays.asList(
            new Order("ORD001", Arrays.asList(
                new OrderItem("P001", "手機(jī)", "電子產(chǎn)品", 3999.0, 1),
                new OrderItem("P002", "耳機(jī)", "電子產(chǎn)品", 299.0, 2)
            ), new Date()),
            new Order("ORD002", Arrays.asList(
                new OrderItem("P003", "T恤", "服裝", 199.0, 3),
                new OrderItem("P004", "牛仔褲", "服裝", 299.0, 2)
            ), new Date()),
            new Order("ORD003", Arrays.asList(
                new OrderItem("P001", "手機(jī)", "電子產(chǎn)品", 3999.0, 2),
                new OrderItem("P005", "運(yùn)動(dòng)鞋", "鞋類(lèi)", 599.0, 1)
            ), new Date())
        );
        // 1. 統(tǒng)計(jì)各類(lèi)別的銷(xiāo)售額
        Map<String, Double> salesByCategory = orders.stream()
            .flatMap(order -> order.getItems().stream())
            .collect(Collectors.groupingBy(
                OrderItem::getCategory,
                Collectors.summingDouble(OrderItem::getTotal)
            ));
        System.out.println("各類(lèi)別銷(xiāo)售額: " + salesByCategory);
        // 2. 找出銷(xiāo)量最高的商品
        Optional<OrderItem> bestSellingItem = orders.stream()
            .flatMap(order -> order.getItems().stream())
            .max(Comparator.comparingInt(OrderItem::getQuantity));
        System.out.println("\n銷(xiāo)量最高商品: " + bestSellingItem);
        // 3. 計(jì)算訂單總金額
        double totalRevenue = orders.stream()
            .flatMap(order -> order.getItems().stream())
            .mapToDouble(OrderItem::getTotal)
            .sum();
        System.out.println("\n總銷(xiāo)售額: " + totalRevenue);
        // 4. 按類(lèi)別分組,統(tǒng)計(jì)每個(gè)類(lèi)別的商品數(shù)量和平均價(jià)格
        Map<String, Map<String, Object>> categoryStats = orders.stream()
            .flatMap(order -> order.getItems().stream())
            .collect(Collectors.groupingBy(
                OrderItem::getCategory,
                Collectors.collectingAndThen(
                    Collectors.toList(),
                    items -> {
                        Map<String, Object> stats = new HashMap<>();
                        stats.put("商品數(shù)量", items.size());
                        stats.put("平均單價(jià)", items.stream().collect(Collectors.averagingDouble(OrderItem::getPrice)));
                        stats.put("總銷(xiāo)量", items.stream().mapToInt(OrderItem::getQuantity).sum());
                        return stats;
                    }
                )
            ));
        System.out.println("\n類(lèi)別統(tǒng)計(jì): " + categoryStats);
        // 5. 篩選出電子產(chǎn)品訂單,并按價(jià)格排序
        List<OrderItem> electronicsSorted = orders.stream()
            .flatMap(order -> order.getItems().stream())
            .filter(item -> item.getCategory().equals("電子產(chǎn)品"))
            .sorted(Comparator.comparingDouble(OrderItem::getPrice).reversed())
            .collect(Collectors.toList());
        System.out.println("\n電子產(chǎn)品(按價(jià)格降序): " + electronicsSorted);
    }
}

運(yùn)行結(jié)果:

各類(lèi)別銷(xiāo)售額: {電子產(chǎn)品=9296.0, 服裝=1194.0, 鞋類(lèi)=599.0}

銷(xiāo)量最高商品: 手機(jī)(電子產(chǎn)品) - 數(shù)量:2 單價(jià):3999.0

總銷(xiāo)售額: 11089.0

類(lèi)別統(tǒng)計(jì): {
    電子產(chǎn)品={商品數(shù)量=3, 平均單價(jià)=2765.6666666666665, 總銷(xiāo)量=5}, 
    服裝={商品數(shù)量=2, 平均單價(jià)=249.0, 總銷(xiāo)量=5}, 
    鞋類(lèi)={商品數(shù)量=1, 平均單價(jià)=599.0, 總銷(xiāo)量=1}
}

電子產(chǎn)品(按價(jià)格降序): [手機(jī)(電子產(chǎn)品) - 數(shù)量:1 單價(jià):3999.0, 手機(jī)(電子產(chǎn)品) - 數(shù)量:2 單價(jià):3999.0, 耳機(jī)(電子產(chǎn)品) - 數(shù)量:2 單價(jià):299.0]

案例二:學(xué)生成績(jī)管理系統(tǒng)

場(chǎng)景描述: 處理學(xué)生成績(jī)數(shù)據(jù),進(jìn)行成績(jī)統(tǒng)計(jì)和分析。

import java.util.*;
import java.util.stream.Collectors;
class Student {
    String id;
    String name;
    String className;
    Map<String, Integer> scores; // 科目 -> 分?jǐn)?shù)
    Student(String id, String name, String className, Map<String, Integer> scores) {
        this.id = id;
        this.name = name;
        this.className = className;
        this.scores = scores;
    }
    public String getId() { return id; }
    public String getName() { return name; }
    public String getClassName() { return className; }
    public Map<String, Integer> getScores() { return scores; }
    public double getAverageScore() {
        return scores.values().stream()
            .mapToInt(Integer::intValue)
            .average()
            .orElse(0);
    }
    public int getTotalScore() {
        return scores.values().stream()
            .mapToInt(Integer::intValue)
            .sum();
    }
    @Override
    public String toString() {
        return name + "(" + className + ") - 平均分:" + String.format("%.1f", getAverageScore());
    }
}
public class StudentGradeAnalysis {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("S001", "張三", "一班", 
                Map.of("語(yǔ)文", 85, "數(shù)學(xué)", 90, "英語(yǔ)", 88, "物理", 92)),
            new Student("S002", "李四", "一班", 
                Map.of("語(yǔ)文", 78, "數(shù)學(xué)", 85, "英語(yǔ)", 80, "物理", 75)),
            new Student("S003", "王五", "二班", 
                Map.of("語(yǔ)文", 92, "數(shù)學(xué)", 88, "英語(yǔ)", 95, "物理", 90)),
            new Student("S004", "趙六", "二班", 
                Map.of("語(yǔ)文", 65, "數(shù)學(xué)", 70, "英語(yǔ)", 68, "物理", 72)),
            new Student("S005", "孫七", "一班", 
                Map.of("語(yǔ)文", 88, "數(shù)學(xué)", 95, "英語(yǔ)", 90, "物理", 93))
        );
        // 1. 計(jì)算全班各科平均分
        Map<String, Double> subjectAvg = students.stream()
            .flatMap(student -> student.getScores().entrySet().stream())
            .collect(Collectors.groupingBy(
                Map.Entry::getKey,
                Collectors.averagingInt(Map.Entry::getValue)
            ));
        System.out.println("各科平均分: " + subjectAvg);
        // 2. 找出總分最高的學(xué)生
        Optional<Student> topStudent = students.stream()
            .max(Comparator.comparingInt(Student::getTotalScore));
        System.out.println("\n總分最高學(xué)生: " + topStudent);
        // 3. 按班級(jí)分組,計(jì)算每個(gè)班級(jí)的平均分
        Map<String, Double> classAvg = students.stream()
            .collect(Collectors.groupingBy(
                Student::getClassName,
                Collectors.averagingDouble(Student::getAverageScore)
            ));
        System.out.println("\n各班級(jí)平均分: " + classAvg);
        // 4. 找出各科分?jǐn)?shù)最高的學(xué)生
        Map<String, Student> topBySubject = students.stream()
            .flatMap(student -> student.getScores().entrySet().stream()
                .map(entry -> Map.entry(entry.getKey(), 
                    Map.entry(student, entry.getValue()))))
            .collect(Collectors.groupingBy(
                Map.Entry::getKey,
                Collectors.collectingAndThen(
                    Collectors.maxBy(
                        Comparator.comparingInt(e -> e.getValue().getValue())
                    ),
                    opt -> opt.map(Map.Entry::getValue).map(Map.Entry::getKey).orElse(null)
                )
            ));
        System.out.println("\n各科最高分學(xué)生:");
        topBySubject.forEach((subject, student) -> 
            System.out.println("  " + subject + ": " + student.getName() + 
                "(" + student.getScores().get(subject) + "分)"));
        // 5. 統(tǒng)計(jì)分?jǐn)?shù)段分布(以數(shù)學(xué)為例)
        String targetSubject = "數(shù)學(xué)";
        Map<String, Long> gradeDistribution = students.stream()
            .filter(s -> s.getScores().containsKey(targetSubject))
            .collect(Collectors.groupingBy(
                student -> {
                    int score = student.getScores().get(targetSubject);
                    if (score >= 90) return "優(yōu)秀";
                    else if (score >= 80) return "良好";
                    else if (score >= 70) return "中等";
                    else if (score >= 60) return "及格";
                    else return "不及格";
                },
                Collectors.counting()
            ));
        System.out.println("\n" + targetSubject + "分?jǐn)?shù)段分布: " + gradeDistribution);
        // 6. 找出所有科目都及格的學(xué)生
        List<Student> allPass = students.stream()
            .filter(student -> student.getScores().values().stream()
                .allMatch(score -> score >= 60))
            .collect(Collectors.toList());
        System.out.println("\n所有科目及格的學(xué)生: " + allPass);
        // 7. 按總分排名
        List<Student> ranked = students.stream()
            .sorted(Comparator.comparingInt(Student::getTotalScore).reversed())
            .collect(Collectors.toList());
        System.out.println("\n學(xué)生總分排名:");
        for (int i = 0; i < ranked.size(); i++) {
            System.out.printf("第%d名: %s - 總分: %d\n", 
                i + 1, ranked.get(i).getName(), ranked.get(i).getTotalScore());
        }
    }
}

運(yùn)行結(jié)果:

各科平均分: {語(yǔ)文=81.6, 數(shù)學(xué)=85.6, 英語(yǔ)=84.2, 物理=86.4}

總分最高學(xué)生: 孫七(一班) - 平均分:91.5

各班級(jí)平均分: {一班=87.16666666666667, 二班=78.5}

各科最高分學(xué)生:
  語(yǔ)文: 王五(92分)
  數(shù)學(xué): 孫七(95分)
  英語(yǔ): 王五(95分)
  物理: 孫七(93分)

數(shù)學(xué)分?jǐn)?shù)段分布: {良好=3, 優(yōu)秀=2}

所有科目及格的學(xué)生: [張三(一班) - 平均分:88.8, 李四(一班) - 平均分:79.5, 王五(二班) - 平均分:91.2, 孫七(一班) - 平均分:91.5]

學(xué)生總分排名:
第1名: 孫七 - 總分:366
第2名: 王五 - 總分:365
第3名: 張三 - 總分:355
第4名: 李四 - 總分:318
第5名: 趙六 - 總分:275

案例三:文本分析與詞頻統(tǒng)計(jì)

場(chǎng)景描述: 分析文本內(nèi)容,統(tǒng)計(jì)詞頻、查找最長(zhǎng)單詞等。

import java.util.*;
import java.util.stream.Collectors;
import java.util.regex.Pattern;
public class TextAnalysis {
    public static void main(String[] args) {
        String text = "Java Stream API is a powerful tool for data processing. " +
                     "It provides a declarative approach to process collections. " +
                     "Stream operations can be chained together to form pipelines. " +
                     "The API supports both sequential and parallel processing.";
        // 1. 分詞并統(tǒng)計(jì)詞頻
        Map<String, Long> wordCount = Pattern.compile("\\s+")
            .splitAsStream(text.toLowerCase()
                .replaceAll("[^a-zA-Z\\s]", ""))
            .filter(word -> word.length() > 2)  // 過(guò)濾掉長(zhǎng)度<=2的詞
            .collect(Collectors.groupingBy(
                word -> word,
                Collectors.counting()
            ));
        System.out.println("詞頻統(tǒng)計(jì):");
        wordCount.entrySet().stream()
            .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
            .limit(10)
            .forEach(entry -> System.out.printf("  %s: %d\n", entry.getKey(), entry.getValue()));
        // 2. 找出最長(zhǎng)的單詞
        String longestWord = Pattern.compile("\\s+")
            .splitAsStream(text.replaceAll("[^a-zA-Z\\s]", ""))
            .max(Comparator.comparingInt(String::length))
            .orElse("");
        System.out.println("\n最長(zhǎng)的單詞: " + longestWord + " (長(zhǎng)度: " + longestWord.length() + ")");
        // 3. 統(tǒng)計(jì)不同長(zhǎng)度單詞的數(shù)量
        Map<Integer, Long> lengthDistribution = Pattern.compile("\\s+")
            .splitAsStream(text.replaceAll("[^a-zA-Z\\s]", ""))
            .collect(Collectors.groupingBy(
                String::length,
                Collectors.counting()
            ));
        System.out.println("\n單詞長(zhǎng)度分布:");
        lengthDistribution.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry -> System.out.printf("  長(zhǎng)度%d: %d個(gè)\n", entry.getKey(), entry.getValue()));
        // 4. 找出所有以特定字母開(kāi)頭的單詞
        char startLetter = 'p';
        List<String> wordsStartingWith = Pattern.compile("\\s+")
            .splitAsStream(text.toLowerCase()
                .replaceAll("[^a-zA-Z\\s]", ""))
            .filter(word -> word.startsWith(String.valueOf(startLetter)))
            .distinct()
            .collect(Collectors.toList());
        System.out.println("\n以'" + startLetter + "'開(kāi)頭的單詞: " + wordsStartingWith);
        // 5. 檢查文本是否包含特定詞匯
        List<String> targetWords = Arrays.asList("stream", "api", "data", "parallel");
        Map<String, Boolean> wordPresence = targetWords.stream()
            .collect(Collectors.toMap(
                word -> word,
                word -> text.toLowerCase().contains(word.toLowerCase())
            ));
        System.out.println("\n關(guān)鍵詞檢查:");
        wordPresence.forEach((word, present) -> 
            System.out.println("  " + word + ": " + (present ? "存在" : "不存在")));
        // 6. 提取所有單詞并按字母順序排序
        List<String> allWordsSorted = Pattern.compile("\\s+")
            .splitAsStream(text.toLowerCase()
                .replaceAll("[^a-zA-Z\\s]", ""))
            .distinct()
            .sorted()
            .collect(Collectors.toList());
        System.out.println("\n所有單詞(排序后):");
        System.out.println("  " + String.join(", ", allWordsSorted));
        // 7. 計(jì)算文本的基本統(tǒng)計(jì)信息
        String[] words = text.replaceAll("[^a-zA-Z\\s]", "").split("\\s+");
        String[] sentences = text.split("[.!?]");
        String[] characters = text.split("");
        System.out.println("\n文本統(tǒng)計(jì):");
        System.out.println("  單詞數(shù): " + words.length);
        System.out.println("  句子數(shù): " + sentences.length);
        System.out.println("  字符數(shù): " + characters.length);
        System.out.println("  平均單詞長(zhǎng)度: " + 
            Arrays.stream(words).mapToInt(String::length).average().orElse(0));
    }
}

運(yùn)行結(jié)果:

詞頻統(tǒng)計(jì):
  stream: 3
  a: 3
  processing: 2
  the: 2
  api: 2
  declarative: 1
  provides: 1
  approach: 1
  process: 1
  collections: 1

最長(zhǎng)的單詞: processing (長(zhǎng)度: 10)

單詞長(zhǎng)度分布:
  長(zhǎng)度1: 0個(gè)
  長(zhǎng)度2: 0個(gè)
  長(zhǎng)度3: 1個(gè)
  長(zhǎng)度4: 6個(gè)
  長(zhǎng)度5: 4個(gè)
  長(zhǎng)度6: 3個(gè)
  長(zhǎng)度7: 1個(gè)
  長(zhǎng)度8: 2個(gè)
  長(zhǎng)度10: 2個(gè)
  長(zhǎng)度11: 1個(gè)

以'p'開(kāi)頭的單詞: [processing, provides, process, pipelines, parallel]

關(guān)鍵詞檢查:
  stream: 存在
  api: 存在
  data: 存在
  parallel: 存在

所有單詞(排序后):
  a, and, api, approach, be, both, can, chains, collections, data, declarative, for, form, is, it, operations, pipelines, powerful, process, processing, provides, sequential, stream, supports, the, tool

文本統(tǒng)計(jì):
  單詞數(shù): 26
  句子數(shù): 4
  字符數(shù): 194
  平均單詞長(zhǎng)度: 5.846153846153846

案例四:?jiǎn)T工信息管理

場(chǎng)景描述: 管理員工信息,進(jìn)行查詢(xún)、分組、統(tǒng)計(jì)分析。

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
class Employee {
    String id;
    String name;
    String department;
    String position;
    int salary;
    LocalDate hireDate;
    int age;
    Employee(String id, String name, String department, String position, 
             int salary, LocalDate hireDate, int age) {
        this.id = id;
        this.name = name;
        this.department = department;
        this.position = position;
        this.salary = salary;
        this.hireDate = hireDate;
        this.age = age;
    }
    // Getters
    public String getId() { return id; }
    public String getName() { return name; }
    public String getDepartment() { return department; }
    public String getPosition() { return position; }
    public int getSalary() { return salary; }
    public LocalDate getHireDate() { return hireDate; }
    public int getAge() { return age; }
    // 計(jì)算工齡(年)
    public int getYearsOfService() {
        return LocalDate.now().getYear() - hireDate.getYear();
    }
    @Override
    public String toString() {
        return String.format("%s(%s) - %s, 薪資:%d", name, department, position, salary);
    }
}
public class EmployeeManagement {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(
            new Employee("E001", "張三", "技術(shù)部", "高級(jí)工程師", 25000, 
                       LocalDate.of(2018, 3, 15), 32),
            new Employee("E002", "李四", "技術(shù)部", "中級(jí)工程師", 18000, 
                       LocalDate.of(2020, 7, 1), 28),
            new Employee("E003", "王五", "技術(shù)部", "初級(jí)工程師", 12000, 
                       LocalDate.of(2022, 1, 10), 25),
            new Employee("E004", "趙六", "市場(chǎng)部", "市場(chǎng)經(jīng)理", 22000, 
                       LocalDate.of(2019, 5, 20), 35),
            new Employee("E005", "孫七", "市場(chǎng)部", "銷(xiāo)售代表", 10000, 
                       LocalDate.of(2021, 9, 1), 26),
            new Employee("E006", "周八", "財(cái)務(wù)部", "財(cái)務(wù)經(jīng)理", 20000, 
                       LocalDate.of(2017, 11, 15), 38),
            new Employee("E007", "吳九", "技術(shù)部", "架構(gòu)師", 30000, 
                       LocalDate.of(2016, 2, 1), 36),
            new Employee("E008", "鄭十", "市場(chǎng)部", "市場(chǎng)專(zhuān)員", 9000, 
                       LocalDate.of(2023, 3, 1), 24)
        );
        // 1. 按部門(mén)統(tǒng)計(jì)員工數(shù)量和平均薪資
        Map<String, Map<String, Object>> deptStats = employees.stream()
            .collect(Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.collectingAndThen(
                    Collectors.toList(),
                    empList -> {
                        Map<String, Object> stats = new HashMap<>();
                        stats.put("人數(shù)", empList.size());
                        stats.put("平均薪資", empList.stream()
                            .collect(Collectors.averagingInt(Employee::getSalary)));
                        stats.put("薪資總和", empList.stream()
                            .mapToInt(Employee::getSalary).sum());
                        return stats;
                    }
                )
            ));
        System.out.println("部門(mén)統(tǒng)計(jì):");
        deptStats.forEach((dept, stats) -> 
            System.out.printf("  %s: 人數(shù)=%d, 平均薪資=%.0f, 總和=%d\n",
                dept, stats.get("人數(shù)"), stats.get("平均薪資"), stats.get("薪資總和")));
        // 2. 找出薪資前3的員工
        List<Employee> topSalaries = employees.stream()
            .sorted(Comparator.comparingInt(Employee::getSalary).reversed())
            .limit(3)
            .collect(Collectors.toList());
        System.out.println("\n薪資前3的員工:");
        topSalaries.forEach(emp -> System.out.println("  " + emp));
        // 3. 找出技術(shù)部工齡超過(guò)5年的員工
        List<Employee> techLongService = employees.stream()
            .filter(emp -> emp.getDepartment().equals("技術(shù)部"))
            .filter(emp -> emp.getYearsOfService() > 5)
            .collect(Collectors.toList());
        System.out.println("\n技術(shù)部工齡超過(guò)5年的員工:");
        techLongService.forEach(emp -> System.out.println("  " + emp + 
            ", 工齡:" + emp.getYearsOfService() + "年"));
        // 4. 按薪資區(qū)間分組
        Map<String, List<Employee>> salaryRanges = employees.stream()
            .collect(Collectors.groupingBy(emp -> {
                int salary = emp.getSalary();
                if (salary >= 25000) return "25000+";
                else if (salary >= 20000) return "20000-24999";
                else if (salary >= 15000) return "15000-19999";
                else return "<15000";
            }));
        System.out.println("\n按薪資區(qū)間分組:");
        salaryRanges.forEach((range, empList) -> 
            System.out.println("  " + range + ": " + empList.size() + "人"));
        // 5. 統(tǒng)計(jì)各職位的人數(shù)
        Map<String, Long> positionCount = employees.stream()
            .collect(Collectors.groupingBy(Employee::getPosition, Collectors.counting()));
        System.out.println("\n各職位人數(shù):");
        positionCount.forEach((position, count) -> 
            System.out.println("  " + position + ": " + count + "人"));
        // 6. 找出年齡在30-35歲之間的員工
        List<Employee> ageRange = employees.stream()
            .filter(emp -> emp.getAge() >= 30 && emp.getAge() <= 35)
            .sorted(Comparator.comparingInt(Employee::getAge))
            .collect(Collectors.toList());
        System.out.println("\n年齡在30-35歲的員工:");
        ageRange.forEach(emp -> System.out.println("  " + emp + ", 年齡:" + emp.getAge()));
        // 7. 計(jì)算整體薪資分布
        IntSummaryStatistics salaryStats = employees.stream()
            .mapToInt(Employee::getSalary)
            .summaryStatistics();
        System.out.println("\n整體薪資統(tǒng)計(jì):");
        System.out.println("  人數(shù): " + salaryStats.getCount());
        System.out.println("  總和: " + salaryStats.getSum());
        System.out.println("  平均: " + (int)salaryStats.getAverage());
        System.out.println("  最高: " + salaryStats.getMax());
        System.out.println("  最低: " + salaryStats.getMin());
        // 8. 查找每個(gè)部門(mén)薪資最高的員工
        Map<String, Employee> highestPaidByDept = employees.stream()
            .collect(Collectors.toMap(
                Employee::getDepartment,
                emp -> emp,
                (e1, e2) -> e1.getSalary() > e2.getSalary() ? e1 : e2
            ));
        System.out.println("\n各部門(mén)薪資最高的員工:");
        highestPaidByDept.forEach((dept, emp) -> 
            System.out.println("  " + dept + ": " + emp.getName() + " (" + emp.getSalary() + ")"));
    }
}

運(yùn)行結(jié)果:

部門(mén)統(tǒng)計(jì):
  技術(shù)部: 人數(shù)=4, 平均薪資=21250, 總和=85000
  市場(chǎng)部: 人數(shù)=3, 平均薪資=13666, 總和=41000
  財(cái)務(wù)部: 人數(shù)=1, 平均薪資=20000, 總和=20000

薪資前3的員工:
  吳九(技術(shù)部) - 架構(gòu)師, 薪資:30000
  張三(技術(shù)部) - 高級(jí)工程師, 薪資:25000
  趙六(市場(chǎng)部) - 市場(chǎng)經(jīng)理, 薪資:22000

技術(shù)部工齡超過(guò)5年的員工:
  吳九(技術(shù)部) - 架構(gòu)師, 薪資:30000, 工齡:10年
  張三(技術(shù)部) - 高級(jí)工程師, 薪資:25000, 工齡:8年

按薪資區(qū)間分組:
  25000+: 2人
  20000-24999: 2人
  15000-19999: 1人
  <15000: 3人

各職位人數(shù):
  高級(jí)工程師: 1人
  中級(jí)工程師: 1人
  初級(jí)工程師: 1人
  市場(chǎng)經(jīng)理: 1人
  銷(xiāo)售代表: 1人
  財(cái)務(wù)經(jīng)理: 1人
  架構(gòu)師: 1人
  市場(chǎng)專(zhuān)員: 1人

年齡在30-35歲的員工:
  李四(技術(shù)部) - 中級(jí)工程師, 薪資:18000, 年齡:28
  趙六(市場(chǎng)部) - 市場(chǎng)經(jīng)理, 薪資:22000, 年齡:35

整體薪資統(tǒng)計(jì):
  人數(shù): 8
  總和: 146000
  平均: 18250
  最高: 30000
  最低: 9000

各部門(mén)薪資最高的員工:
  技術(shù)部: 吳九 (30000)
  市場(chǎng)部: 趙六 (22000)
  財(cái)務(wù)部: 周八 (20000)

六、注意事項(xiàng)與最佳實(shí)踐

6.1 Stream的特點(diǎn)與限制

Stream只能消費(fèi)一次

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
stream.count();  // 正確執(zhí)行
stream.count();  // 拋出IllegalStateException

解決方案: 每次需要使用Stream時(shí)重新創(chuàng)建

List<String> list = Arrays.asList("a", "b", "c");
list.stream().count();  // 第一次使用
list.stream().count();  // 第二次使用,重新創(chuàng)建Stream

Stream操作是惰性的

List<String> list = Arrays.asList("a", "bb", "ccc", "dddd");
Stream<String> stream = list.stream()
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.length() > 2;
    })
    .map(s -> {
        System.out.println("map: " + s);
        return s.toUpperCase();
    });  // 此時(shí)不會(huì)執(zhí)行任何操作

stream.collect(Collectors.toList());  // 觸發(fā)執(zhí)行

執(zhí)行結(jié)果:

filter: a
filter: bb
filter: ccc
map: ccc
filter: dddd
map: dddd

6.2 性能考量

適當(dāng)使用基本類(lèi)型Stream

// 避免裝箱操作
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 不推薦:使用Stream<Integer>
int sum1 = numbers.stream()
    .reduce(0, Integer::sum);  // 會(huì)發(fā)生裝箱拆箱
// 推薦:使用IntStream
int sum2 = numbers.stream()
    .mapToInt(Integer::intValue)
    .sum();  // 避免裝箱拆箱,性能更好

合理使用并行流

List<Integer> numbers = IntStream.range(1, 1000000).boxed().collect(Collectors.toList());
// 順序流
long start1 = System.currentTimeMillis();
long sum1 = numbers.stream().reduce(0L, Long::sum);
long time1 = System.currentTimeMillis() - start1;
// 并行流
long start2 = System.currentTimeMillis();
long sum2 = numbers.parallelStream().reduce(0L, Long::sum);
long time2 = System.currentTimeMillis() - start2;
System.out.println("順序流: " + time1 + "ms");
System.out.println("并行流: " + time2 + "ms");

使用并行流的注意事項(xiàng):

  • 數(shù)據(jù)量較大時(shí)(通常>10000元素)才考慮使用并行流
  • 數(shù)據(jù)源易于拆分(如ArrayList)時(shí)效果好
  • 避免在并行流中使用共享狀態(tài)
  • 操作本身耗時(shí)較長(zhǎng)時(shí),并行流優(yōu)勢(shì)更明顯

避免過(guò)度使用Stream

// 簡(jiǎn)單操作,傳統(tǒng)方式可能更清晰
List<String> names = Arrays.asList("張三", "李四", "王五");
// Stream方式
List<String> result = names.stream()
    .filter(name -> name.startsWith("張"))
    .collect(Collectors.toList());
// 傳統(tǒng)方式(更直接)
List<String> result2 = new ArrayList<>();
for (String name : names) {
    if (name.startsWith("張")) {
        result2.add(name);
    }
}

6.3 常見(jiàn)陷阱

避免在Stream中修改外部狀態(tài)

// 不推薦:修改外部變量
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int count = 0;
numbers.stream()
    .filter(n -> n % 2 == 0)
    .forEach(n -> count++);  // 并行流時(shí)可能出錯(cuò)
// 推薦:使用count()
long evenCount = numbers.stream()
    .filter(n -> n % 2 == 0)
    .count();

注意Optional的使用

List<String> names = Arrays.asList("張三", "李四", "王五");
// 安全地處理Optional
Optional<String> result = names.stream()
    .filter(name -> name.startsWith("趙"))
    .findFirst();
// 不推薦:直接get()
// String s = result.get();  // 可能拋出NoSuchElementException
// 推薦:使用orElse()或其他安全方法
String s = result.orElse("未找到");
String s2 = result.orElseGet(() -> "未找到");
result.ifPresent(name -> System.out.println("找到: " + name));

注意forEach的順序

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 順序流:保證順序
numbers.stream().forEach(n -> System.out.print(n + " "));  // 1 2 3 4 5
// 并行流:不保證順序
numbers.parallelStream().forEach(n -> System.out.print(n + " "));  // 順序不確定
// 并行流需要順序時(shí),使用forEachOrdered
numbers.parallelStream().forEachOrdered(n -> System.out.print(n + " "));  // 1 2 3 4 5

避免在filter中使用副作用

// 不推薦:filter中有副作用
List<String> names = new ArrayList<>();
List<String> input = Arrays.asList("a", "b", "c");
input.stream()
    .filter(s -> {
        names.add(s);  // 副作用,不可預(yù)測(cè)
        return s.length() > 1;
    })
    .collect(Collectors.toList());
// 推薦:分離操作
List<String> names2 = input.stream()
    .filter(s -> s.length() > 1)
    .collect(Collectors.toList());

6.4 最佳實(shí)踐總結(jié)

實(shí)踐說(shuō)明
使用方法引用String::lengths -> s.length() 更簡(jiǎn)潔
鏈?zhǔn)秸{(diào)用將多個(gè)操作串聯(lián)在一起,代碼更清晰
合理使用peek只在調(diào)試時(shí)使用,不要用于業(yè)務(wù)邏輯
善用Collectors熟練使用Collectors工具類(lèi)的各種方法
注意空值處理使用Optional處理可能為空的結(jié)果
考慮性能大數(shù)據(jù)集考慮并行流,小數(shù)據(jù)集使用順序流
保持簡(jiǎn)潔過(guò)長(zhǎng)的流水線(xiàn)考慮拆分
測(cè)試驗(yàn)證確保Stream操作的正確性

七、總結(jié)

7.1 Stream API的核心價(jià)值

Java Stream API 是現(xiàn)代Java開(kāi)發(fā)中不可或缺的工具,它帶來(lái)的核心價(jià)值包括:

  1. 代碼簡(jiǎn)潔性:聲明式的編程風(fēng)格讓代碼更加簡(jiǎn)潔、易讀
  2. 可讀性提升:鏈?zhǔn)秸{(diào)用清晰地表達(dá)了數(shù)據(jù)處理的意圖
  3. 并行處理能力:輕松實(shí)現(xiàn)并行計(jì)算,充分利用多核CPU
  4. 功能強(qiáng)大:提供了豐富的操作方法,滿(mǎn)足各種數(shù)據(jù)處理需求
  5. 函數(shù)式編程:推動(dòng)了Java向函數(shù)式編程范式的演進(jìn)

7.2 常用方法速查表

類(lèi)別方法說(shuō)明
創(chuàng)建stream() / parallelStream()從Collection創(chuàng)建
Arrays.stream()從數(shù)組創(chuàng)建
Stream.of()從值創(chuàng)建
篩選filter()過(guò)濾元素
distinct()去重
limit()限制數(shù)量
skip()跳過(guò)元素
映射map()元素轉(zhuǎn)換
flatMap()扁平化映射
排序sorted()排序
匹配allMatch() / anyMatch() / noneMatch()匹配檢查
findFirst() / findAny()查找元素
歸約reduce()歸約操作
收集collect()收集結(jié)果
統(tǒng)計(jì)count() / max() / min()統(tǒng)計(jì)操作

7.3 結(jié)語(yǔ)

Java Stream API 徹底改變了我們處理集合數(shù)據(jù)的方式。掌握Stream不僅能讓你的代碼更加優(yōu)雅,還能提高開(kāi)發(fā)效率。但要注意,Stream不是萬(wàn)能的,在簡(jiǎn)單場(chǎng)景下傳統(tǒng)方式可能更直接。選擇合適的工具,才能寫(xiě)出更好的代碼。

到此這篇關(guān)于Java Stream流常用方法歸納整理及案例解析的文章就介紹到這了,更多相關(guān)Java Stream流常用方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring Boot 實(shí)現(xiàn)程序的優(yōu)雅退出(詳細(xì)步驟)

    Spring Boot 實(shí)現(xiàn)程序的優(yōu)雅退出(詳細(xì)步驟)

    Spring Boot 為我們提供了優(yōu)雅退出的功能,使應(yīng)用程序能夠在關(guān)閉時(shí)正常處理完所有當(dāng)前請(qǐng)求,避免請(qǐng)求被中斷導(dǎo)致數(shù)據(jù)丟失或不一致等問(wèn)題,本文將全面介紹如何在 Spring Boot 應(yīng)用程序中實(shí)現(xiàn)優(yōu)雅退出,感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • Java分布式ID中Snowflake雪花算法應(yīng)用實(shí)現(xiàn)

    Java分布式ID中Snowflake雪花算法應(yīng)用實(shí)現(xiàn)

    Snowflake算法作為一種高效且易于實(shí)現(xiàn)的分布式ID生成方案,能夠很好地滿(mǎn)足分布式系統(tǒng)中對(duì)全局唯一ID的需求,本文就來(lái)介紹一下Java分布式ID中Snowflake雪花算法應(yīng)用實(shí)現(xiàn),感興趣的可以了解一下
    2024-07-07
  • SpringBoot實(shí)現(xiàn)日志文件分隔(根據(jù)日期和文件大小)

    SpringBoot實(shí)現(xiàn)日志文件分隔(根據(jù)日期和文件大小)

    文章簡(jiǎn)要介紹了如何在Spring Boot項(xiàng)目中配置日志文件路徑,包括在resource目錄下創(chuàng)建logback-spring.xml文件,并在yml配置文件中設(shè)置logging.file.path屬性來(lái)指定日志文件的輸出路徑
    2026-01-01
  • Spring Boot 全局異常處理策略設(shè)計(jì)之@ExceptionHandler 與 @ControllerAdvice 生效原理源碼解析

    Spring Boot 全局異常處理策略設(shè)計(jì)之@ExceptionHandler 與&nb

    SpringBoot全局異常處理策略設(shè)計(jì)@ExceptionHandler與@ControllerAdvice生效原理源碼解析,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2026-01-01
  • Springcloud seata nacos環(huán)境搭建過(guò)程圖解

    Springcloud seata nacos環(huán)境搭建過(guò)程圖解

    這篇文章主要介紹了Springcloud seata nacos環(huán)境搭建過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 關(guān)于FileChannel的transferFrom()方法的使用及說(shuō)明

    關(guān)于FileChannel的transferFrom()方法的使用及說(shuō)明

    這篇文章主要介紹了關(guān)于FileChannel的transferFrom()方法的使用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • Spring?IOC容器Bean注解創(chuàng)建對(duì)象組件掃描

    Spring?IOC容器Bean注解創(chuàng)建對(duì)象組件掃描

    這篇文章主要為大家介紹了Spring?IOC容器Bean注解創(chuàng)建對(duì)象組件掃描,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Spring Boot 4 與 Spring Framework 7新特性、升級(jí)要點(diǎn)與實(shí)戰(zhàn)指南

    Spring Boot 4 與 Spring Framework&nb

    SpringBoot4和SpringFramework7帶來(lái)了大量新特性,包括升級(jí)到JakartaEE11、支持Java21、增強(qiáng)模塊化、優(yōu)化測(cè)試、增加彈性功能等,本文介紹Spring Boot 4 與 Spring Framework 7新特性、升級(jí)要點(diǎn)與實(shí)戰(zhàn)指南,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • 23種設(shè)計(jì)模式(14)java迭代器模式

    23種設(shè)計(jì)模式(14)java迭代器模式

    這篇文章主要為大家詳細(xì)介紹了23種設(shè)計(jì)模式之java迭代器模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Redisson分布式鎖原理深入分析

    Redisson分布式鎖原理深入分析

    文章介紹了Redisson分布式鎖的工作原理,并詳細(xì)解釋了加鎖、續(xù)期、解鎖的核心流程,Redisson利用Redis的單線(xiàn)程、自動(dòng)續(xù)期和Lua腳本原子性等特點(diǎn),避免了傳統(tǒng)鎖常見(jiàn)的死鎖、鎖爭(zhēng)用和誤刪等問(wèn)題,此外,還總結(jié)了使用Redisson分布式鎖時(shí)的注意事項(xiàng)和避坑點(diǎn)
    2026-04-04

最新評(píng)論

龙山县| 石门县| 阿城市| 手游| 晋中市| 旌德县| 五河县| 淮北市| 福安市| 金乡县| 惠东县| 务川| 阳原县| 邛崃市| 岳阳县| 河北区| 岳阳市| 肥东县| 枣庄市| 宁晋县| 台山市| 东明县| 信丰县| 沙田区| 车险| 黔西| 嵊州市| 建湖县| 青田县| 鄄城县| 伽师县| 吐鲁番市| 时尚| 泰兴市| 资溪县| 教育| 扬中市| 乌兰察布市| 南陵县| 佛山市| 隆林|