partitioningBy案例

wen java案例 1

本文目录导读:

partitioningBy案例

  1. Java 中 Collectors.partitioningBy 案例详解
  2. 基础用法
  3. 使用下游收集器
  4. 组合使用多个条件
  5. 与其他收集器组合
  6. 实际应用场景
  7. 性能优化与实际注意事项
  8. 嵌套分区

Java 中 Collectors.partitioningBy 案例详解

partitioningBy 是 Java Stream API 中的一个收集器,用于根据 Predicate 条件将元素分为两组(true 和 false),它返回一个 Map<Boolean, List<T>>

基础用法

案例1:按数字奇偶性分区

import java.util.*;
import java.util.stream.Collectors;
public class BasicPartitioning {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        // 按奇偶数分区
        Map<Boolean, List<Integer>> partitioned = numbers.stream()
            .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        System.out.println("偶数: " + partitioned.get(true));
        System.out.println("奇数: " + partitioned.get(false));
        // 输出:
        // 偶数: [2, 4, 6, 8, 10]
        // 奇数: [1, 3, 5, 7, 9]
    }
}

案例2:按字符串长度分区

public class StringPartitioning {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("Java", "Python", "C", "JS", "Kotlin", "Rust");
        // 按长度是否大于3分区
        Map<Boolean, List<String>> partitioned = words.stream()
            .collect(Collectors.partitioningBy(word -> word.length() > 3));
        System.out.println("长度>3的单词: " + partitioned.get(true));
        System.out.println("长度<=3的单词: " + partitioned.get(false));
        // 输出:
        // 长度>3的单词: [Java, Python, Kotlin, Rust]
        // 长度<=3的单词: [C, JS]
    }
}

使用下游收集器

案例3:分区后进行二次处理

import java.util.*;
import java.util.stream.Collectors;
public class DownstreamCollector {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        // 分区后统计每组的个数
        Map<Boolean, Long> countByParity = numbers.stream()
            .collect(Collectors.partitioningBy(
                n -> n % 2 == 0,
                Collectors.counting()
            ));
        System.out.println("偶数个数: " + countByParity.get(true));
        System.out.println("奇数个数: " + countByParity.get(false));
        // 分区后求和
        Map<Boolean, Integer> sumByParity = numbers.stream()
            .collect(Collectors.partitioningBy(
                n -> n % 2 == 0,
                Collectors.summingInt(Integer::intValue)
            ));
        System.out.println("偶数和: " + sumByParity.get(true));
        System.out.println("奇数和: " + sumByParity.get(false));
    }
}

案例4:复杂对象的分区处理

import java.util.*;
import java.util.stream.Collectors;
class Person {
    private String name;
    private int age;
    private double salary;
    public Person(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    public String getName() { return name; }
    public int getAge() { return age; }
    public double getSalary() { return salary; }
    @Override
    public String toString() {
        return name + "(" + age + "岁, " + salary + "元)";
    }
}
public class ObjectPartitioning {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("张三", 25, 8000),
            new Person("李四", 35, 15000),
            new Person("王五", 30, 12000),
            new Person("赵六", 28, 6000),
            new Person("孙七", 45, 20000)
        );
        // 按是否超过30岁分区
        Map<Boolean, List<Person>> byAge = people.stream()
            .collect(Collectors.partitioningBy(p -> p.getAge() > 30));
        System.out.println("30岁以上: " + byAge.get(true));
        System.out.println("30岁及以下: " + byAge.get(false));
        // 分区并按工资排序
        Map<Boolean, List<Person>> bySalarySorted = people.stream()
            .collect(Collectors.partitioningBy(
                p -> p.getSalary() > 10000,
                Collectors.collectingAndThen(
                    Collectors.toList(),
                    list -> list.stream()
                        .sorted(Comparator.comparingDouble(Person::getSalary))
                        .collect(Collectors.toList())
                )
            ));
        System.out.println("\n高薪员工(按工资排序): " + bySalarySorted.get(true));
        System.out.println("低薪员工(按工资排序): " + bySalarySorted.get(false));
    }
}

组合使用多个条件

案例5:多个条件组合分区

public class ComplexCondition {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
        // 同时满足:能被2整除且大于5
        Map<Boolean, List<Integer>> complex = numbers.stream()
            .collect(Collectors.partitioningBy(
                n -> n % 2 == 0 && n > 5
            ));
        System.out.println("满足条件(偶数且>5): " + complex.get(true));
        System.out.println("不满足条件: " + complex.get(false));
    }
}

与其他收集器组合

案例6:分区后使用 joining

public class JoiningPartitioning {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
        // 分区后连接成字符串
        Map<Boolean, String> joined = words.stream()
            .collect(Collectors.partitioningBy(
                s -> s.length() > 5,
                Collectors.joining(", ", "[", "]")
            ));
        System.out.println("长单词: " + joined.get(true));
        System.out.println("短单词: " + joined.get(false));
        // 分区后转成 Set
        Map<Boolean, Set<String>> sets = words.stream()
            .collect(Collectors.partitioningBy(
                s -> s.contains("a"),
                Collectors.toSet()
            ));
        System.out.println("含'a'的单词: " + sets.get(true));
        System.out.println("不含'a'的单词: " + sets.get(false));
    }
}

实际应用场景

案例7:数据分析

public class DataAnalysis {
    public static void main(String[] args) {
        List<Double> scores = Arrays.asList(85.5, 92.0, 78.5, 95.5, 60.0, 45.5, 88.0, 70.5, 55.0, 90.5);
        // 及格/不及格分组
        Map<Boolean, List<Double>> byPass = scores.stream()
            .collect(Collectors.partitioningBy(score -> score >= 60));
        // 统计各组成绩的平均值
        Map<Boolean, Double> averages = scores.stream()
            .collect(Collectors.partitioningBy(
                score -> score >= 60,
                Collectors.averagingDouble(Double::doubleValue)
            ));
        System.out.println("及格人数: " + byPass.get(true).size());
        System.out.println("不及格人数: " + byPass.get(false).size());
        System.out.println("及格平均分: " + averages.get(true));
        System.out.println("不及格平均分: " + averages.get(false));
    }
}

性能优化与实际注意事项

案例8:处理大量数据

public class PerformanceExample {
    public static void main(String[] args) {
        // 生成100万个随机数
        Random random = new Random();
        List<Integer> data = random.ints(1_000_000, 1, 1000000)
            .boxed()
            .collect(Collectors.toList());
        // 方式1:partitioningBy(推荐)
        long start1 = System.currentTimeMillis();
        Map<Boolean, Long> count1 = data.stream()
            .collect(Collectors.partitioningBy(
                n -> n > 500000,
                Collectors.counting()
            ));
        long end1 = System.currentTimeMillis();
        System.out.println("partitioningBy耗时: " + (end1 - start1) + "ms");
        // 方式2:groupingBy(等价的替代方案)
        long start2 = System.currentTimeMillis();
        Map<String, Long> count2 = data.stream()
            .collect(Collectors.groupingBy(
                n -> n > 500000 ? "big" : "small",
                Collectors.counting()
            ));
        long end2 = System.currentTimeMillis();
        System.out.println("groupingBy耗时: " + (end2 - start2) + "ms");
    }
}

嵌套分区

案例9:多级分区

public class NestedPartitioning {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
        // 先按奇偶分,再按是否大于6分
        Map<Boolean, Map<Boolean, List<Integer>>> nested = numbers.stream()
            .collect(Collectors.partitioningBy(
                n -> n % 2 == 0,  // 外层:奇偶
                Collectors.partitioningBy(n -> n > 6)  // 内层:大小
            ));
        System.out.println("偶数且>6: " + nested.get(true).get(true));
        System.out.println("偶数且<=6: " + nested.get(true).get(false));
        System.out.println("奇数且>6: " + nested.get(false).get(true));
        System.out.println("奇数且<=6: " + nested.get(false).get(false));
    }
}

partitioningBy 的优势:

  1. 语义明确:专门用于二元分组
  2. 性能优化:比 groupingBy 更高效,因为只有两个键
  3. 结果可预测:返回的 Map 一定包含 true/false 两个键
  4. 支持下游收集器:可以进行复杂的二次处理

适用场景:

  • 布尔条件的二元分类(是否、存在、满足等)
  • 数据统计分析(分组统计、分组求值)
  • 复杂业务规则的条件划分

注意事项:

  • 返回的 Map 类型是 HashMap,不保证顺序
  • 如果不需要下游收集器,直接使用即可
  • 适合处理二元逻辑,多分类请使用 groupingBy

抱歉,评论功能暂时关闭!