0
点赞
收藏
分享

微信扫一扫

如何安全过滤List中的混合类型数据


✅ 核心挑战

  1. 类型不安全:直接强转可能抛出 ClassCastException
  2. null 值干扰null 无法判断类型
  3. 数字类型混淆IntegerLongDouble 如何统一处理?
  4. 可维护性差if-else 堆砌,代码难以扩展

✅ 策略一:使用 instanceof 进行类型过滤(基础但可靠)

需求:从 List<Object> 中提取所有字符串。

实现:

List<Object> mixed = ... // 混合数据

List<String> strings = mixed.stream()
    .filter(Objects::nonNull)
    .filter(item -> item instanceof String)
    .map(item -> (String) item)
    .collect(Collectors.toList());

✅ 提取所有数字(Integer, Long, Double 等)

List<Number> numbers = mixed.stream()
    .filter(Objects::nonNull)
    .filter(item -> item instanceof Number)
    .map(item -> (Number) item)
    .collect(Collectors.toList());

NumberIntegerLongDouble 等的父类,可统一处理。

✅ 策略二:按“语义类型”分组过滤(高级分类)

需求:将混合数据按“字符串、数字、布尔、其他”分类。

实现:

Map<String, List<Object>> grouped = mixed.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.groupingBy(item -> {
        if (item instanceof String) return "string";
        else if (item instanceof Number) return "number";
        else if (item instanceof Boolean) return "boolean";
        else return "other";
    }));

// 使用
List<Object> strings = grouped.get("string");
List<Object> numbers = grouped.get("number");

✅ 封装为通用分类器

public enum DataType {
    STRING, NUMBER, BOOLEAN, DATE, OTHER;

    public static DataType of(Object value) {
        if (value == null) return OTHER;
        if (value instanceof String) return STRING;
        if (value instanceof Number) return NUMBER;
        if (value instanceof Boolean) return BOOLEAN;
        if (value instanceof LocalDate || value instanceof Instant) return DATE;
        return OTHER;
    }
}

// 使用
Map<DataType, List<Object>> classified = mixed.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.groupingBy(DataType::of));

✅ 策略三:数字类型的精细化过滤(范围筛选)

需求:从所有数字中筛选出值在 100 ~ 500 之间的项。

实现:

List<Number> filteredNumbers = mixed.stream()
    .filter(Objects::nonNull)
    .filter(item -> item instanceof Number)
    .map(item -> (Number) item)
    .filter(num -> {
        double value = num.doubleValue(); // 统一转为 double 比较
        return value >= 100 && value <= 500;
    })
    .collect(Collectors.toList());

✅ 注意事项:

  • 使用 doubleValue() 可避免 Long 超出 Integer 范围的问题。
  • 对精度要求高时,可用 BigDecimal.valueOf(num.doubleValue())

✅ 策略四:字符串的模式匹配过滤(正则 + 条件)

需求:从字符串中筛选出符合邮箱格式的项。

实现:

Pattern emailPattern = Pattern.compile("\\w+@\\w+\\.\\w+");

List<String> emails = mixed.stream()
    .filter(Objects::nonNull)
    .filter(item -> item instanceof String)
    .map(String::valueOf)
    .filter(s -> !s.trim().isEmpty())
    .filter(emailPattern.asPredicate())
    .collect(Collectors.toList());

✅ 扩展:识别并转换数字字符串

// 筛选出能转为整数的字符串
List<Integer> intStrings = mixed.stream()
    .filter(Objects::nonNull)
    .filter(item -> item instanceof String)
    .map(String::valueOf)
    .filter(s -> s.matches("\\d+"))
    .map(Integer::parseInt)
    .collect(Collectors.toList());

✅ 策略五:构建类型安全的“过滤管道”(Pipeline)

为了提升可维护性,我们可以构建一个类型过滤管道

public class ObjectFilterPipeline<T> {
    private final List<T> data;

    public ObjectFilterPipeline(List<T> data) {
        this.data = new ArrayList<>(data);
    }

    public ObjectFilterPipeline<T> ofType(Class<T> type) {
        return new ObjectFilterPipeline<>(
            data.stream()
                .filter(item -> type.isInstance(item))
                .collect(Collectors.toList())
        );
    }

    public ObjectFilterPipeline<String> strings() {
        return (ObjectFilterPipeline<String>) ofType(String.class);
    }

    public ObjectFilterPipeline<Number> numbers() {
        return (ObjectFilterPipeline<Number>) ofType(Number.class);
    }

    public ObjectFilterPipeline<T> where(Predicate<T> condition) {
        return new ObjectFilterPipeline<>(
            data.stream()
                .filter(condition)
                .collect(Collectors.toList())
        );
    }

    public List<T> result() {
        return new ArrayList<>(data);
    }
}

✅ 使用方式(流式调用):

List<Object> result = new ObjectFilterPipeline<>(mixedData)
    .numbers()
    .where(num -> num.doubleValue() > 100)
    .result(); // 返回 List<Number>

List<String> emails = new ObjectFilterPipeline<>(mixedData)
    .strings()
    .where(s -> s.contains("@"))
    .result();

✅ 优势:链式调用,语义清晰,类型安全(在转换后)。

✅ 5种策略对比速查表

策略

适用场景

优点

缺点

instanceof

基础类型过滤

简单直接,性能好

重复代码多

分组分类

数据清洗、统计

一次性分类,便于分析

内存占用略高

数字范围

金额、评分、数量筛选

精准控制数值条件

需统一数值类型

正则匹配

字符串模式识别

灵活,支持复杂规则

正则性能开销

过滤管道

复杂业务逻辑链

链式调用,可扩展

需要额外封装


举报

相关推荐

0 条评论