Skip to content

PatternMatching

文件信息

  • 📄 原文件:PatternMatching.java
  • 🔤 语言:java

Java 模式匹配 本文件介绍 Java 中的模式匹配特性。

完整代码

java
import java.util.*;

/**
 * ============================================================
 *                    Java 模式匹配
 * ============================================================
 * 本文件介绍 Java 中的模式匹配特性。
 * ============================================================
 */
public class PatternMatching {

    public static void main(String[] args) {
        instanceofPattern();
        switchExpressions();
        switchPatterns();
        guardedPatterns();
        sealedTypesPattern();
    }

    /**
     * ============================================================
     *                    1. instanceof 模式匹配
     * ============================================================
     */
    public static void instanceofPattern() {
        System.out.println("=".repeat(60));
        System.out.println("1. instanceof 模式匹配");
        System.out.println("=".repeat(60));

        System.out.println("""
            instanceof 模式匹配(Java 16+)
            - 类型检查和类型转换合二为一
            - 模式变量的作用域由编译器推断
            """);

        // 【传统方式 vs 模式匹配】
        System.out.println("--- 传统方式 vs 模式匹配 ---");
        Object obj = "Hello, Pattern Matching!";

        // 传统方式
        if (obj instanceof String) {
            String s = (String) obj;
            System.out.println("传统方式: " + s.toUpperCase());
        }

        // 模式匹配
        if (obj instanceof String s) {
            System.out.println("模式匹配: " + s.toUpperCase());
        }

        // 【作用域规则】
        System.out.println("\n--- 作用域规则 ---");
        Object value = 42;

        // 模式变量在 true 分支中可用
        if (value instanceof Integer i) {
            System.out.println("整数: " + (i * 2));
        }

        // 在 false 分支后也可用(因为流程确定)
        if (!(value instanceof Integer i)) {
            System.out.println("不是整数");
        } else {
            System.out.println("是整数: " + i);
        }

        // 【与 && 组合】
        System.out.println("\n--- 与 && 组合 ---");
        Object data = "Hello";

        if (data instanceof String str && str.length() > 3) {
            System.out.println("长度大于3的字符串: " + str);
        }

        // 【处理多种类型】
        System.out.println("\n--- 处理多种类型 ---");
        Object[] items = {42, "Hello", 3.14, true, List.of(1, 2, 3)};

        for (Object item : items) {
            describeObject(item);
        }
    }

    public static void describeObject(Object obj) {
        String desc;
        if (obj instanceof Integer i) {
            desc = "整数: " + i + ", 平方: " + (i * i);
        } else if (obj instanceof String s) {
            desc = "字符串: " + s + ", 长度: " + s.length();
        } else if (obj instanceof Double d) {
            desc = "浮点数: " + d;
        } else if (obj instanceof Boolean b) {
            desc = "布尔值: " + b;
        } else if (obj instanceof List<?> list) {
            desc = "列表: " + list + ", 大小: " + list.size();
        } else {
            desc = "未知类型: " + obj.getClass().getSimpleName();
        }
        System.out.println("  " + desc);
    }

    /**
     * ============================================================
     *                    2. switch 表达式
     * ============================================================
     */
    public static void switchExpressions() {
        System.out.println("\n" + "=".repeat(60));
        System.out.println("2. switch 表达式");
        System.out.println("=".repeat(60));

        System.out.println("""
            switch 表达式(Java 14+)
            - 可以作为表达式返回值
            - 使用 -> 箭头语法
            - 不需要 break
            - yield 用于代码块中返回值
            """);

        // 【传统 switch vs switch 表达式】
        System.out.println("--- 传统 vs 表达式 ---");
        int day = 3;

        // 传统方式
        String dayName1;
        switch (day) {
            case 1:
                dayName1 = "周一";
                break;
            case 2:
                dayName1 = "周二";
                break;
            case 3:
                dayName1 = "周三";
                break;
            default:
                dayName1 = "其他";
        }

        // switch 表达式
        String dayName2 = switch (day) {
            case 1 -> "周一";
            case 2 -> "周二";
            case 3 -> "周三";
            case 4 -> "周四";
            case 5 -> "周五";
            case 6, 7 -> "周末";  // 多个标签
            default -> "无效";
        };

        System.out.println("传统: " + dayName1);
        System.out.println("表达式: " + dayName2);

        // 【yield 关键字】
        System.out.println("\n--- yield 关键字 ---");
        int month = 2;
        int days = switch (month) {
            case 1, 3, 5, 7, 8, 10, 12 -> 31;
            case 4, 6, 9, 11 -> 30;
            case 2 -> {
                // 复杂逻辑用代码块
                System.out.println("  计算二月天数...");
                yield 28;  // 简化,不考虑闰年
            }
            default -> throw new IllegalArgumentException("无效月份");
        };
        System.out.println(month + "月有 " + days + " 天");

        // 【enum switch】
        System.out.println("\n--- enum switch ---");
        DayOfWeek dow = DayOfWeek.WEDNESDAY;

        String type = switch (dow) {
            case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "工作日";
            case SATURDAY, SUNDAY -> "周末";
        };
        System.out.println(dow + " 是 " + type);

        // 【switch 表达式必须完备】
        System.out.println("\n【注意】switch 表达式必须覆盖所有情况(穷尽性)");
    }

    enum DayOfWeek {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }

    /**
     * ============================================================
     *                    3. switch 模式匹配
     * ============================================================
     */
    public static void switchPatterns() {
        System.out.println("\n" + "=".repeat(60));
        System.out.println("3. switch 模式匹配");
        System.out.println("=".repeat(60));

        System.out.println("""
            switch 模式匹配(Java 21+)
            - 支持类型模式
            - 支持 Record 模式
            - 支持 null 处理
            """);

        // 【类型模式】
        System.out.println("--- 类型模式 ---");
        Object[] values = {42, "hello", 3.14, true, null};

        for (Object value : values) {
            String result = formatValue(value);
            System.out.println("  " + result);
        }

        // 【Record 模式】
        System.out.println("\n--- Record 模式 ---");
        ShapeP[] shapes = {
            new CircleP(5),
            new RectangleP(4, 3),
            new SquareP(4)
        };

        for (ShapeP shape : shapes) {
            System.out.println("  " + describeShape(shape));
        }

        // 【嵌套 Record 模式】
        System.out.println("\n--- 嵌套 Record 模式 ---");
        Object wrapped = new Box(new CircleP(10));
        String desc = switch (wrapped) {
            case Box(CircleP(double r)) -> "盒子里有圆形,半径 " + r;
            case Box(RectangleP(double w, double h)) -> "盒子里有矩形," + w + "x" + h;
            case Box(SquareP(double s)) -> "盒子里有正方形,边长 " + s;
            default -> "未知内容";
        };
        System.out.println(desc);
    }

    public static String formatValue(Object value) {
        return switch (value) {
            case null -> "null 值";
            case Integer i -> "整数: " + i;
            case String s -> "字符串: \"" + s + "\"";
            case Double d -> "浮点数: " + d;
            case Boolean b -> "布尔: " + b;
            default -> "其他: " + value;
        };
    }

    public static String describeShape(ShapeP shape) {
        return switch (shape) {
            case CircleP(double r) -> String.format("圆形(r=%.1f), 面积=%.2f", r, Math.PI * r * r);
            case RectangleP(double w, double h) -> String.format("矩形(%.1fx%.1f), 面积=%.2f", w, h, w * h);
            case SquareP(double s) -> String.format("正方形(s=%.1f), 面积=%.2f", s, s * s);
        };
    }

    /**
     * ============================================================
     *                    4. 守卫模式
     * ============================================================
     */
    public static void guardedPatterns() {
        System.out.println("\n" + "=".repeat(60));
        System.out.println("4. 守卫模式 (when)");
        System.out.println("=".repeat(60));

        System.out.println("""
            守卫模式(Java 21+)
            - 使用 when 关键字添加条件
            - 可以进一步细化模式匹配
            """);

        // 【数值范围守卫】
        System.out.println("--- 数值范围守卫 ---");
        int[] scores = {95, 85, 75, 65, 45};

        for (int score : scores) {
            String grade = switch (score) {
                case Integer s when s >= 90 -> "A";
                case Integer s when s >= 80 -> "B";
                case Integer s when s >= 70 -> "C";
                case Integer s when s >= 60 -> "D";
                default -> "F";
            };
            System.out.println("  " + score + " -> " + grade);
        }

        // 【字符串守卫】
        System.out.println("\n--- 字符串守卫 ---");
        String[] inputs = {"hello", "WORLD", "", null};

        for (String input : inputs) {
            String desc = switch (input) {
                case null -> "空引用";
                case String s when s.isEmpty() -> "空字符串";
                case String s when s.equals(s.toUpperCase()) -> "全大写: " + s;
                case String s when s.equals(s.toLowerCase()) -> "全小写: " + s;
                case String s -> "混合大小写: " + s;
            };
            System.out.println("  " + desc);
        }

        // 【Record 守卫】
        System.out.println("\n--- Record 守卫 ---");
        ShapeP[] shapes = {
            new CircleP(5),
            new CircleP(0.5),
            new RectangleP(10, 2),
            new SquareP(3)
        };

        for (ShapeP shape : shapes) {
            String category = switch (shape) {
                case CircleP(double r) when r > 3 -> "大圆";
                case CircleP(double r) -> "小圆";
                case RectangleP(double w, double h) when w > h * 3 -> "细长矩形";
                case RectangleP r -> "普通矩形";
                case SquareP s -> "正方形";
            };
            System.out.println("  " + shape + " -> " + category);
        }
    }

    /**
     * ============================================================
     *                    5. 密封类型与模式匹配
     * ============================================================
     */
    public static void sealedTypesPattern() {
        System.out.println("\n" + "=".repeat(60));
        System.out.println("5. 密封类型与模式匹配");
        System.out.println("=".repeat(60));

        System.out.println("""
            密封类型(Java 17+)与模式匹配完美配合:
            - 编译器知道所有可能的子类型
            - switch 可以确保穷尽性
            - 无需 default 分支
            """);

        // 【密封接口 + switch】
        System.out.println("--- 密封类型的穷尽 switch ---");
        Expr[] expressions = {
            new Num(42),
            new Add(new Num(3), new Num(5)),
            new Mul(new Add(new Num(2), new Num(3)), new Num(4)),
            new Neg(new Num(10))
        };

        for (Expr expr : expressions) {
            int result = evaluate(expr);
            System.out.println("  " + format(expr) + " = " + result);
        }

        // 【类型安全的访问者模式替代】
        System.out.println("\n--- 替代访问者模式 ---");
        System.out.println("""
            传统的访问者模式复杂且难以扩展
            密封类型 + switch 提供了更简洁的替代方案
            """);
    }

    public static int evaluate(Expr expr) {
        return switch (expr) {
            case Num(int value) -> value;
            case Add(Expr left, Expr right) -> evaluate(left) + evaluate(right);
            case Mul(Expr left, Expr right) -> evaluate(left) * evaluate(right);
            case Neg(Expr operand) -> -evaluate(operand);
        };
    }

    public static String format(Expr expr) {
        return switch (expr) {
            case Num(int value) -> String.valueOf(value);
            case Add(Expr left, Expr right) -> "(" + format(left) + " + " + format(right) + ")";
            case Mul(Expr left, Expr right) -> "(" + format(left) + " * " + format(right) + ")";
            case Neg(Expr operand) -> "-" + format(operand);
        };
    }
}

// ============================================================
//                    辅助类型定义
// ============================================================

sealed interface ShapeP permits CircleP, RectangleP, SquareP {}
record CircleP(double radius) implements ShapeP {}
record RectangleP(double width, double height) implements ShapeP {}
record SquareP(double side) implements ShapeP {}

record Box(ShapeP content) {}

// 表达式树(密封类型)
sealed interface Expr permits Num, Add, Mul, Neg {}
record Num(int value) implements Expr {}
record Add(Expr left, Expr right) implements Expr {}
record Mul(Expr left, Expr right) implements Expr {}
record Neg(Expr operand) implements Expr {}

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布