Java包容性案例

wen java案例 1

本文目录导读:

Java包容性案例

  1. 集合与Stream处理中的包容性(避免 NullPointerException)
  2. 策略模式中的包容性(处理未知或未定义的输入)
  3. 数值计算与精度包容性(防止溢出和精度丢失)
  4. 多线程与并发中的包容性(优雅降级与超时控制)
  5. Java包容性代码的黄金法则

这是一个非常具有实践意义的主题,在Java开发中,“包容性”通常指代码的健壮性可扩展性以及对各种边界情况的友好处理。

下面提供几个不同层面的“包容性”案例,从代码编写到框架设计。

集合与Stream处理中的包容性(避免 NullPointerException)

这是最常见的场景,在处理大量数据时,集合中含有 null 元素或 null 引用是常态,包容性强的代码不会直接崩溃。

❌ 非包容性写法:

import java.util.Arrays;
import java.util.List;
public class NonInclusive {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", null, "Bob");
        // 会抛出 NullPointerException
        names.stream()
             .map(String::toUpperCase) // 当元素为null时,调用方法报错
             .forEach(System.out::println);
    }
}

✅ 包容性写法(使用 filter + Optional):

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class Inclusive {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", null, "Bob");
        names.stream()
             .map(Optional::ofNullable)        // 将 null 包装成 Optional.empty()
             .filter(Optional::isPresent)      // 过滤掉空值
             .map(opt -> opt.get().toUpperCase()) // 安全地处理非空值
             .forEach(System.out::println);
        // 输出: ALICE \n BOB
    }
}

原理: 使用 Optional 显式地标记“可能为空”,避免了隐式的 null 传递和后续的空指针崩溃。


策略模式中的包容性(处理未知或未定义的输入)

当程序遇到无法识别的输入时,一个包容性的系统不会直接抛出 IllegalArgumentException 或返回错误结果,而是提供一个“默认”或“降级”策略。

场景: 根据不同的支付方式(支付宝、微信、银行卡)计算手续费,如果系统新增了一种支付方式(如“Apple Pay”),但代码未更新。

✅ 包容性设计(使用默认策略):

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
// 策略接口
interface FeeStrategy {
    double calculate(double amount);
}
// 具体策略
class AlipayStrategy implements FeeStrategy {
    public double calculate(double amount) { return amount * 0.006; }
}
class WechatStrategy implements FeeStrategy {
    public double calculate(double amount) { return amount * 0.008; }
}
// 包容性的策略工厂
class FeeCalculator {
    private final Map<String, FeeStrategy> strategyMap = new HashMap<>();
    // 默认策略:当未知支付方式时,按最高标准或固定值收费
    private final FeeStrategy defaultStrategy = amount -> amount * 0.01; // 1% 保底
    public FeeCalculator() {
        strategyMap.put("alipay", new AlipayStrategy());
        strategyMap.put("wechat", new WechatStrategy());
    }
    public double calculateFee(String paymentMethod, double amount) {
        // 包容性:如果找不到,使用默认策略
        FeeStrategy strategy = strategyMap.getOrDefault(paymentMethod, defaultStrategy);
        return strategy.calculate(amount);
    }
}
// 使用示例
public class Main {
    public static void main(String[] args) {
        FeeCalculator calculator = new FeeCalculator();
        System.out.println(calculator.calculateFee("alipay", 100));    // 0.6
        System.out.println(calculator.calculateFee("unknown_pay", 100)); // 1.0 (包容性处理)
        // 不会抛出 NullPointerException 或 "不支持该支付方式" 的异常
    }
}

数值计算与精度包容性(防止溢出和精度丢失)

在金融或科学计算中,直接使用 intfloat 可能导致灾难性错误,包容性代码会主动检查范围并使用合适的类型。

❌ 非包容性(溢出):

int max = Integer.MAX_VALUE; // 2147483647
int result = max + 1; 
System.out.println(result); // 输出 -2147483648 (溢出,完全错误)

✅ 包容性(使用 BigDecimal 并防溢出检查):

import java.math.BigDecimal;
public class SafeCalculation {
    public static BigDecimal safeAdd(BigDecimal a, BigDecimal b) {
        // 包容性:处理null值
        a = (a == null) ? BigDecimal.ZERO : a;
        b = (b == null) ? BigDecimal.ZERO : b;
        return a.add(b); // BigDecimal 不会溢出
    }
    public static void main(String[] args) {
        BigDecimal large1 = new BigDecimal("99999999999999999999");
        BigDecimal large2 = new BigDecimal("11111111111111111111");
        // 不会溢出,精确计算
        System.out.println(safeAdd(large1, large2)); 
        // 输出: 111111111111111111110
    }
}

多线程与并发中的包容性(优雅降级与超时控制)

当依赖外部服务(如数据库、API)时,包容性系统不应该因为一个环节卡住而让整个系统崩溃。

场景: 从缓存获取数据,如果缓存挂了,不应该抛异常,而应该去数据库查询。

✅ 包容性设计(借助 CompletableFuture + 超时 + 降级):

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class ResilientService {
    public String getUserData(String userId) {
        // 尝试从缓存获取,包容性:如果缓存超时或异常,则降级到数据库
        return CompletableFuture
                .supplyAsync(() -> fetchFromCache(userId))
                .orTimeout(100, TimeUnit.MILLISECONDS) // 设置超时
                .exceptionally(ex -> {
                    // 包容性处理:记录日志,然后降级
                    System.err.println("Cache failed, falling back to DB: " + ex.getMessage());
                    return fetchFromDatabase(userId);
                })
                .join();
    }
    private String fetchFromCache(String userId) {
        // 模拟缓存可能很慢或抛出异常
        if (Math.random() > 0.5) {
            throw new RuntimeException("Cache unavailable");
        }
        return "Cached data for " + userId;
    }
    private String fetchFromDatabase(String userId) {
        return "DB data for " + userId;
    }
    // 不会因为缓存故障而抛异常给调用方
}

Java包容性代码的黄金法则

  1. 防御性编程:不信任外部输入,避免 nullOptional.ofNullable)。
  2. 优雅降级:在策略、服务调用中总是提供 fallback(默认值或降级方法)。
  3. 容错处理:使用 try-catch 包裹可能异常的 IO 或解析操作,而不是让线程挂掉。
  4. 边界控制:数组长度、集合大小、数值溢出、整数除零等。
  5. 文档与契约:明确标注 @Nullable@NonNull,让调用者知道如何处理。

如果你希望了解更具体的场景(如文件系统处理、API参数校验等),可以告诉我,我可以提供更具针对性的案例。

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