Java关键字终极指南:从入门到精通

这是一份非常详细、实用、通俗易懂,权威、全面的 Java 关键字指南。


目录

  1. Java 关键字概述

    • 1.1 什么是关键字?
    • 1.2 关键字的作用与重要性
    • 1.3 Java 关键字列表 (Java 17)
    • 1.4 注意事项:保留字与关键字
  2. 访问控制关键字

    • 2.1 public
      • 原理与作用域
      • 最佳实践与代码示例
    • 2.2 private
      • 原理与作用域 (封装的核心)
      • 最佳实践与代码示例
    • 2.3 protected
      • 原理与作用域 (包与子类)
      • 最佳实践与代码示例
    • 2.4 默认访问权限 (无关键字)
      • 原理与作用域 (包内可见)
      • 最佳实践与代码示例
  3. 类、方法、变量定义相关关键字

    • 3.1 class
      • 原理:类的蓝图
      • 定义与使用示例
    • 3.2 interface
      • 原理:契约与多继承
      • 定义与实现 (implements) 示例
    • 3.3 enum
      • 原理:类型安全的常量集合
      • 定义与使用示例
    • 3.4 abstract
      • 原理:抽象类与抽象方法
      • 定义 (abstract class, abstract method) 与继承 (extends) 示例
    • 3.5 final
      • 原理:不可变性 (final class, final method, final variable)
      • 最佳实践与代码示例 (常量、防止继承/重写)
    • 3.6 static
      • 原理:类级别成员 (static variable, static method, static block)
      • 最佳实践与代码示例 (工具类、单例模式雏形)
    • 3.7 void
      • 原理:无返回值方法
      • 方法声明示例
    • 3.8 new
      • 原理:对象实例化
      • 对象创建示例
    • 3.9 this
      • 原理:当前对象引用
      • 使用场景示例 (区分成员与局部变量、链式调用)
    • 3.10 super
      • 原理:父类对象引用
      • 使用场景示例 (调用父类构造方法、访问父类成员)
  4. 流程控制关键字

    • 4.1 if / else / else if
      • 原理:条件分支
      • 最佳实践与代码示例
    • 4.2 switch / case / default
      • 原理:多路选择 (支持 String, enum 等)
      • 最佳实践与代码示例 (避免 fall-through, Java 12+ switch 表达式)
    • 4.3 for
      • 原理:循环控制 (传统 for, 增强 for - for-each)
      • 最佳实践与代码示例 (遍历数组、集合)
    • 4.4 while / do...while
      • 原理:循环控制 (前判断、后判断)
      • 最佳实践与代码示例 (输入验证、不确定次数循环)
    • 4.5 break
      • 原理:跳出循环或 switch
      • 使用场景示例 (提前终止循环)
    • 4.6 continue
      • 原理:跳过当前循环迭代
      • 使用场景示例 (跳过特定条件)
    • 4.7 return
      • 原理:方法返回 (值或控制权)
      • 使用场景示例 (结束方法执行、返回结果)
  5. 异常处理关键字

    • 5.1 try
      • 原理:异常监控块
      • 结构基础
    • 5.2 catch
      • 原理:捕获并处理特定异常
      • 最佳实践与代码示例 (捕获特定异常类型、多重 catch)
    • 5.3 finally
      • 原理:资源清理块 (无论是否发生异常都执行)
      • 最佳实践与代码示例 (关闭文件流、数据库连接)
    • 5.4 throw
      • 原理:主动抛出异常
      • 最佳实践与代码示例 (自定义异常、参数校验)
    • 5.5 throws
      • 原理:声明方法可能抛出的异常
      • 最佳实践与代码示例 (方法签名声明)
  6. 类型相关关键字

    • 6.1 instanceof
      • 原理:对象类型检查
      • 使用场景示例 (向下转型前的安全校验)
    • 6.2 extends
      • 原理:类继承
      • 定义子类示例 (class Child extends Parent)
    • 6.3 implements
      • 原理:接口实现
      • 类实现接口示例 (class MyClass implements MyInterface)
    • 6.4 import
      • 原理:引入其他包中的类/接口
      • 使用示例 (import java.util.List;)
  7. 其他重要关键字

    • 7.1 package
      • 原理:定义类所属的包 (命名空间管理)
      • 定义包示例 (package com.example.mypackage;)
    • 7.2 native
      • 原理:本地方法 (JNI)
      • 声明示例 (public native void nativeMethod();)
    • 7.3 strictfp
      • 原理:严格的浮点计算 (平台一致性)
      • 使用示例 (public strictfp class StrictFloatCalc {})
    • 7.4 transient
      • 原理:序列化排除字段
      • 使用场景示例 (敏感信息、临时状态)
    • 7.5 volatile
      • 原理:变量可见性与指令重排 (轻量级同步)
      • 使用场景示例 (状态标志位)
    • 7.6 synchronized
      • 原理:线程同步 (方法、代码块)
      • 最佳实践与代码示例 (防止竞态条件)
    • 7.7 const (保留字,未使用)
    • 7.8 goto (保留字,未使用)
  8. Java 10+ 新增上下文关键字

    • 8.1 var (Java 10)
      • 原理:局部变量类型推断
      • 最佳实践与代码示例 (简化局部变量声明,提高可读性)
    • 8.2 record (Java 14 - 预览,Java 16 - 正式)
      • 原理:透明数据载体类
      • 定义与使用示例 (简化 POJO 定义)
  9. 综合实战案例:简易用户管理系统

    • 9.1 需求分析
    • 9.2 系统设计 (package, class, interface, enum)
    • 9.3 核心类实现 (public, private, static, final, this, new, if, for, while, return, try, catch, finally, throw, throws, instanceof, extends, implements, import, switch, record/POJO)
    • 9.4 异常处理设计 (RuntimeException, CustomException)
    • 9.5 主程序与测试

1. Java 关键字概述

1.1 什么是关键字? 关键字是 Java 语言预先定义的、具有特殊含义和用途的英文单词。它们是 Java 语法的基础构件,编译器会识别它们并执行特定的操作。不能将关键字用作变量名、方法名、类名或任何其他标识符。

1.2 关键字的作用与重要性 关键字定义了程序的结构、控制流程、数据封装、继承、多态、异常处理等核心概念。它们是编写符合 Java 语法规则的程序所必需的。理解每个关键字的含义和用法是掌握 Java 编程的基础。

1.3 Java 关键字列表 (Java 17) 以下是 Java 17 中所有关键字(不包括上下文关键字 varrecord):

复制代码
abstract   continue   for          new         switch
assert     default    if           package     synchronized
boolean    do         goto         private     this
break      double     implements   protected   throw
byte       else       import       public      throws
case       enum       instanceof   return      transient
catch      extends    int          short       try
char       final      interface    static      void
class      finally    long         strictfp    volatile
const      float      native       super       while

1.4 注意事项:保留字与关键字

  • constgoto :这两个词是 Java 的保留字,虽然目前未被使用,但也不能用作标识符。
  • nulltruefalse :虽然看起来像关键字,但它们实际上是字面量(常量值),可以用于赋值等操作,但不能用作标识符。
  • 上下文关键字 (var, record):在 Java 10 和 14/16 引入,它们只在特定的语法上下文中具有关键字含义,在其他地方可以用作标识符(但不推荐)。本指南将其视为重要概念进行介绍。

2. 访问控制关键字

访问控制关键字用于设置类、接口、变量和方法的可见性范围,是面向对象封装特性的核心实现。

2.1 public

  • 原理与作用域 :访问权限最宽松。标记为 public 的类、接口、方法或变量可以被任何其他类访问,无论它们是否在同一个包中。
  • 最佳实践与代码示例 :常用于定义程序的入口点 (main 方法)、需要被广泛使用的工具类方法、常量类、API 的接口定义等。
java 复制代码
// PublicClass.java (必须与文件名同名)
public class PublicClass {
    public int publicField = 10; // 公有字段 (通常不推荐直接暴露字段,这里仅为示例)

    public void publicMethod() {
        System.out.println("This is a public method.");
    }
}

// AnotherClass.java (可能在不同包)
import com.example.PublicClass; // 需要import

public class AnotherClass {
    public static void main(String[] args) {
        PublicClass obj = new PublicClass();
        System.out.println(obj.publicField); // 可以直接访问
        obj.publicMethod(); // 可以直接调用
    }
}

2.2 private

  • 原理与作用域 (封装的核心) :访问权限最严格。标记为 private 的变量、方法或构造方法只能在其定义的类内部被访问。外部类无法直接访问或调用。
  • 最佳实践与代码示例 :这是实现封装的关键。通常将类的成员变量声明为 private,然后提供 publicgettersetter 方法来控制对它们的访问(即数据隐藏)。构造方法有时也声明为 private 用于单例模式。
java 复制代码
public class BankAccount {
    private double balance; // 私有字段,外部无法直接访问

    // 公有构造方法
    public BankAccount(double initialBalance) {
        if (initialBalance >= 0) {
            this.balance = initialBalance;
        }
    }

    // 公有getter方法 (访问)
    public double getBalance() {
        return balance;
    }

    // 公有setter方法 (修改,通常加入校验)
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }

    // 私有方法,辅助内部逻辑,外部无法调用
    private void logTransaction(String type, double amount) {
        System.out.println("Transaction: " + type + " $" + amount);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000);
        // account.balance = 500; // 错误!private字段无法直接访问
        System.out.println("Balance: $" + account.getBalance()); // 通过getter访问
        account.deposit(200); // 通过公有方法修改
        account.withdraw(50); // 通过公有方法修改
        System.out.println("New Balance: $" + account.getBalance());
        // account.logTransaction("Test", 10); // 错误!private方法无法调用
    }
}

2.3 protected

  • 原理与作用域 (包与子类) :标记为 protected 的变量、方法或构造方法可以在同一个包内 的其他类访问,也可以被不同包中的子类 访问。这是介于 publicprivate 之间的一种权限,强调继承关系。
  • 最佳实践与代码示例 :常用于设计可继承的基类,将一些希望被子类访问或重写的成员声明为 protected。有时也用于包内协作。
java 复制代码
// Animal.java (包: com.example.animals)
package com.example.animals;

public class Animal {
    protected String name; // 子类和同包类可访问

    public Animal(String name) {
        this.name = name;
    }

    protected void eat() { // 子类可访问和重写
        System.out.println(name + " is eating.");
    }
}

// Dog.java (包: com.example.animals, 同包)
package com.example.animals;

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void eat() {
        super.eat(); // 可以访问父类的protected方法
        System.out.println(name + " is eating dog food."); // 可以访问父类的protected字段
    }
}

// VetClinic.java (包: com.example.animals, 同包)
package com.example.animals;

public class VetClinic {
    public void examineAnimal(Animal animal) {
        System.out.println("Examining: " + animal.name); // 同包,可以访问protected字段
        animal.eat(); // 同包,可以调用protected方法
    }
}

// 不同包的子类 (如果存在) 也能访问其父类中的protected成员

2.4 默认访问权限 (无关键字)

  • 原理与作用域 (包内可见) :如果一个类、接口、变量或方法没有任何访问修饰符 ,则它具有默认访问权限(有时称为包私有)。它只能在同一个包内的其他类中被访问。
  • 最佳实践与代码示例:适用于那些只在包内部使用的辅助类、工具类或内部实现细节。外部包无法访问它们。
java 复制代码
// Helper.java (包: com.example.utilities)
package com.example.utilities;

class Helper { // 默认访问权限,无public
    static void help() {
        System.out.println("Offering help within the package.");
    }
}

// MainApp.java (包: com.example.utilities, 同包)
package com.example.utilities;

public class MainApp {
    public static void main(String[] args) {
        Helper.help(); // 可以访问,同包
    }
}

// 如果AnotherClass在com.example.other包中,则无法访问Helper类

3. 类、方法、变量定义相关关键字

3.1 class

  • 原理:类的蓝图class 关键字用于声明一个类。类是创建对象的模板,定义了对象的属性(字段)和行为(方法)。
  • 定义与使用示例
java 复制代码
public class Car { // 使用class定义类
    // 字段 (属性)
    private String brand;
    private String model;
    private int year;

    // 构造方法 (使用new调用时执行)
    public Car(String brand, String model, int year) {
        this.brand = brand;
        this.model = model;
        this.year = year;
    }

    // 方法 (行为)
    public void startEngine() {
        System.out.println("The " + brand + " " + model + "'s engine is starting.");
    }

    public void displayInfo() {
        System.out.println("Brand: " + brand + ", Model: " + model + ", Year: " + year);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Car myCar = new Car("Toyota", "Camry", 2023); // new关键字创建对象
        myCar.startEngine();
        myCar.displayInfo();
    }
}

3.2 interface

  • 原理:契约与多继承interface 关键字用于声明一个接口。接口定义了一组抽象方法 (没有实现的方法),形成一个契约。类通过 implements 关键字实现接口,并必须提供这些方法的实现。一个类可以实现多个接口,从而间接实现多继承。
  • 定义与实现 (implements) 示例
java 复制代码
// 定义接口
public interface Driveable {
    void start(); // 抽象方法,无方法体
    void stop();
    void accelerate(int speed);
}

public interface Fuelable {
    void refuel();
}

// 类实现接口
public class Car implements Driveable, Fuelable { // 实现多个接口
    @Override
    public void start() {
        System.out.println("Car started.");
    }

    @Override
    public void stop() {
        System.out.println("Car stopped.");
    }

    @Override
    public void accelerate(int speed) {
        System.out.println("Accelerating to " + speed + " km/h");
    }

    @Override
    public void refuel() {
        System.out.println("Refueling the car.");
    }
}

// 使用接口类型引用
public class Main {
    public static void main(String[] args) {
        Driveable vehicle = new Car(); // 多态
        vehicle.start();
        vehicle.accelerate(60);
        vehicle.stop();

        Fuelable fuelCar = (Fuelable) vehicle; // 类型转换,因为Car也实现了Fuelable
        fuelCar.refuel();
    }
}

3.3 enum

  • 原理:类型安全的常量集合enum 关键字用于定义一个枚举类型。枚举是一种特殊的类,它的实例是预先定义的、有限的常量对象。它比传统的常量 (public static final) 更安全、更强大,可以有自己的字段、方法和构造方法。
  • 定义与使用示例
java 复制代码
// 简单枚举
public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

// 带字段和方法的枚举
public enum Planet {
    MERCURY(3.303e+23, 2.4397e6), // 调用构造方法
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6),
    MARS(6.421e+23, 3.3972e6),
    JUPITER(1.9e+27, 7.1492e7),
    SATURN(5.688e+26, 6.0268e7),
    URANUS(8.686e+25, 2.5559e7),
    NEPTUNE(1.024e+26, 2.4746e7);

    private final double mass; // 枚举常量自己的字段
    private final double radius;

    Planet(double mass, double radius) { // 枚举的构造方法 (总是private)
        this.mass = mass;
        this.radius = radius;
    }

    public double getMass() {
        return mass;
    }

    public double getRadius() {
        return radius;
    }

    public double getSurfaceGravity() {
        return G * mass / (radius * radius); // 假设G是常量
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Day today = Day.WEDNESDAY;
        System.out.println("Today is: " + today); // 输出 WEDNESDAY

        Planet earth = Planet.EARTH;
        System.out.println("Earth mass: " + earth.getMass() + " kg");
        System.out.println("Earth gravity: " + earth.getSurfaceGravity() + " m/s²");

        // 在switch中使用枚举 (安全,不会匹配错误字符串)
        switch (today) {
            case MONDAY:
                System.out.println("It's Monday!");
                break;
            case FRIDAY:
                System.out.println("TGIF!");
                break;
            default:
                System.out.println("Another day.");
        }
    }
}

3.4 abstract

  • 原理:抽象类与抽象方法abstract 修饰的类称为抽象类,它不能被实例化 (不能创建对象)。抽象类可以包含抽象方法(使用 abstract 声明且没有方法体的方法),也可以包含普通方法。子类必须实现父抽象类中的所有抽象方法(除非子类也是抽象类)。
  • 定义 (abstract class, abstract method) 与继承 (extends) 示例
java 复制代码
// 抽象类
public abstract class Shape {
    protected String color;

    public Shape(String color) {
        this.color = color;
    }

    // 抽象方法 (无实现体)
    public abstract double getArea();

    public abstract double getPerimeter();

    // 普通方法 (有实现)
    public String getColor() {
        return color;
    }
}

// 具体子类继承抽象类
public class Circle extends Shape {
    private double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override // 必须实现抽象方法
    public double getArea() {
        return Math.PI * radius * radius;
    }

    @Override // 必须实现抽象方法
    public double getPerimeter() {
        return 2 * Math.PI * radius;
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        // Shape shape = new Shape("Red"); // 错误!抽象类不能实例化
        Shape circle = new Circle("Blue", 5.0);
        System.out.println("Circle Area: " + circle.getArea());
        System.out.println("Circle Perimeter: " + circle.getPerimeter());
        System.out.println("Color: " + circle.getColor());
    }
}

3.5 final

  • 原理:不可变性 (final class, final method, final variable)
    • final class:该类不能被继承 。例如 StringMath 类。
    • final method:该方法不能被子类重写
    • final variable:该变量一旦被赋值,其值就不能被修改(常量)。
  • 最佳实践与代码示例 (常量、防止继承/重写)
java 复制代码
// final类
public final class UtilityClass {
    private UtilityClass() {} // 私有构造方法防止实例化

    // final变量 (常量)
    public static final double PI_APPROXIMATE = 3.14;

    // final方法
    public final static void utilityMethod() {
        System.out.println("This method cannot be overridden.");
    }
}

// 尝试继承会报错
// class SubUtil extends UtilityClass {} // 编译错误: 无法继承final类

// final变量
public class FinalExample {
    public final int MAX_VALUE = 100; // 实例常量

    public static final String DEFAULT_NAME = "Unknown"; // 类常量 (static final)

    public void tryChange() {
        // MAX_VALUE = 200; // 编译错误: 无法为final变量赋值
        // DEFAULT_NAME = "NewName"; // 编译错误
    }
}

// final参数
public void processData(final int id) {
    // id = 10; // 编译错误: 无法修改final参数
}

3.6 static

  • 原理:类级别成员 (static variable, static method, static block)static 修饰的成员(变量、方法、代码块)属于类本身 ,而不是属于类的某个实例对象。它们在类加载时初始化,所有实例共享同一份 static 成员。
    • static variable (类变量):所有实例共享。
    • static method (类方法):可以通过类名直接调用,不能直接访问非 static 成员(因为没有 this 上下文)。
    • static block (静态初始化块):在类加载时执行一次,用于初始化 static 变量或执行其他静态初始化任务。
  • 最佳实践与代码示例 (工具类、单例模式雏形)
java 复制代码
public class Counter {
    // static变量 (类变量)
    private static int count = 0;

    // 实例变量
    private int instanceId;

    public Counter() {
        instanceId = ++count; // 访问static变量
    }

    // static方法 (类方法)
    public static int getTotalCount() {
        return count;
    }

    public int getInstanceId() {
        return instanceId;
    }

    // static块 (静态初始化块)
    static {
        System.out.println("Counter class is loaded. Initializing...");
        // 可以在这里进行更复杂的static变量初始化
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        System.out.println("Total Count (before): " + Counter.getTotalCount()); // 通过类名调用static方法

        Counter c1 = new Counter();
        Counter c2 = new Counter();

        System.out.println("c1 ID: " + c1.getInstanceId());
        System.out.println("c2 ID: " + c2.getInstanceId());
        System.out.println("Total Count (after): " + Counter.getTotalCount()); // 输出2,两个实例共享count
    }
}
// 输出顺序:
// Counter class is loaded. Initializing...
// Total Count (before): 0
// c1 ID: 1
// c2 ID: 2
// Total Count (after): 2

3.7 void

  • 原理:无返回值方法void 用于声明一个方法不返回任何值
  • 方法声明示例
java 复制代码
public class Printer {
    public void printMessage(String message) { // 方法返回类型为void
        System.out.println(message);
    }

    public int calculateSum(int a, int b) { // 返回int类型
        return a + b;
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.printMessage("Hello, World!"); // 调用void方法,不能用于赋值

        int sum = printer.calculateSum(5, 3); // 调用有返回值方法,可以赋值
        System.out.println("Sum: " + sum);
    }
}

3.8 new

  • 原理:对象实例化new 关键字用于创建类的实例(对象)。它在堆内存中分配空间,并调用类的构造方法初始化对象。
  • 对象创建示例ClassName objectName = new ClassName(arguments);
java 复制代码
public class Book {
    private String title;
    private String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }
    // ... getters
}

public class Main {
    public static void main(String[] args) {
        Book myBook = new Book("The Lord of the Rings", "J.R.R. Tolkien"); // 使用new创建对象
        System.out.println(myBook.getTitle());
    }
}

3.9 this

  • 原理:当前对象引用this 关键字代表当前对象的引用。在类的实例方法或构造方法中,this 指向调用该方法的那个对象实例。
  • 使用场景示例 (区分成员与局部变量、链式调用)
java 复制代码
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name; // 使用this区分成员变量name和参数name
        this.age = age;
    }

    public Person setName(String name) {
        this.name = name;
        return this; // 返回当前对象,用于链式调用
    }

    public Person setAge(int age) {
        this.age = age;
        return this;
    }

    public void introduce() {
        System.out.println("Hello, I'm " + this.name + ", " + this.age + " years old."); // this可省略,但显式更好
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice", 30);
        person.introduce();

        // 链式调用 (因为setter返回this)
        person.setName("Bob").setAge(35).introduce();
    }
}

3.10 super

  • 原理:父类对象引用super 关键字代表当前对象的父类对象的引用。它用于在子类中访问父类的成员(字段、方法),特别是当子类重写了父类方法时,调用父类的原始实现。它也用于在子类构造方法中调用父类的构造方法。
  • 使用场景示例 (调用父类构造方法、访问父类成员)
java 复制代码
public class Vehicle {
    protected String brand;

    public Vehicle(String brand) {
        this.brand = brand;
    }

    public void display() {
        System.out.println("Brand: " + brand);
    }
}

public class Car extends Vehicle {
    private String model;

    public Car(String brand, String model) {
        super(brand); // 调用父类(Vehicle)的构造方法,必须放在子类构造方法第一行
        this.model = model;
    }

    @Override
    public void display() {
        super.display(); // 调用父类的display方法
        System.out.println("Model: " + model);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Car myCar = new Car("Toyota", "Camry");
        myCar.display(); // 输出 Brand: Toyota \n Model: Camry
    }
}

4. 流程控制关键字

4.1 if / else / else if

  • 原理:条件分支 :根据布尔表达式的值 (truefalse) 决定执行哪一段代码块。
  • 最佳实践与代码示例 :使用清晰的布尔表达式,避免嵌套过深。使用 else if 处理多个条件分支。
java 复制代码
public class GradeEvaluator {
    public static void main(String[] args) {
        int score = 85;

        if (score >= 90) {
            System.out.println("Grade: A");
        } else if (score >= 80) { // 注意条件范围,避免重叠和遗漏
            System.out.println("Grade: B");
        } else if (score >= 70) {
            System.out.println("Grade: C");
        } else if (score >= 60) {
            System.out.println("Grade: D");
        } else {
            System.out.println("Grade: F");
        }

        // 嵌套if示例 (谨慎使用)
        boolean hasPrerequisite = true;
        if (score >= 70) {
            if (hasPrerequisite) {
                System.out.println("You can take the advanced course.");
            } else {
                System.out.println("You need to complete the prerequisite.");
            }
        }
    }
}

4.2 switch / case / default

  • 原理:多路选择 (支持 String, enum 等) :根据一个表达式的值,匹配不同的 case 分支执行。支持 intcharString (Java 7+)、enum (Java 5+) 等类型。default 分支是可选的,当没有匹配的 case 时执行。
  • 最佳实践与代码示例 (避免 fall-through, Java 12+ switch 表达式)
    • 传统 switch (使用 break 防止 fall-through):
java 复制代码
public class DaySelector {
    public static void main(String[] args) {
        int dayOfWeek = 3; // 假设1=Sunday, 2=Monday,...,7=Saturday

        switch (dayOfWeek) {
            case 1:
                System.out.println("Sunday");
                break; // 必须break,否则会继续执行下一个case
            case 2:
                System.out.println("Monday");
                break;
            case 3:
                System.out.println("Tuesday");
                break;
            case 4:
                System.out.println("Wednesday");
                break;
            case 5:
                System.out.println("Thursday");
                break;
            case 6:
                System.out.println("Friday");
                break;
            case 7:
                System.out.println("Saturday");
                break;
            default:
                System.out.println("Invalid day");
        }

        // 使用String (Java 7+)
        String fruit = "Apple";
        switch (fruit) {
            case "Apple":
                System.out.println("Selected Apple");
                break;
            case "Banana":
                System.out.println("Selected Banana");
                break;
            default:
                System.out.println("Unknown fruit");
        }

        // 使用enum (更安全)
        Day today = Day.WEDNESDAY;
        switch (today) {
            case MONDAY:
                System.out.println("Start of work week");
                break;
            case FRIDAY:
                System.out.println("Almost weekend!");
                break;
            case SATURDAY:
            case SUNDAY: // 合并多个case
                System.out.println("Weekend!");
                break;
            default:
                System.out.println("Midweek");
        }
    }
}
复制代码
*   Java 12+ `switch` 表达式 (更简洁,支持返回值,避免 `break`):
java 复制代码
public class EnhancedSwitch {
    public static void main(String[] args) {
        int month = 4;
        int days = switch (month) {
            case 1, 3, 5, 7, 8, 10, 12 -> 31; // 使用箭头语法,不需要break
            case 4, 6, 9, 11 -> 30;
            case 2 -> {
                System.out.println("Checking leap year...");
                yield 28; // 如果是闰年,这里可能需要逻辑判断,yield返回值
            }
            default -> 0;
        }; // switch表达式有返回值,需要分号结束

        System.out.println("Days in month " + month + ": " + days);
    }
}

4.3 for

  • 原理:循环控制 (传统 for, 增强 for - for-each) :用于重复执行一段代码块。
    • 传统 for 循环 :适用于知道循环次数或需要控制索引的情况。结构:for (初始化; 条件; 迭代) { ... }
    • 增强 for 循环 (for-each) :适用于遍历数组或集合 (Iterable 对象),语法更简洁:for (元素类型 变量名 : 数组或集合) { ... }
  • 最佳实践与代码示例 (遍历数组、集合)
java 复制代码
public class ForLoopExamples {
    public static void main(String[] args) {
        // 传统for循环
        for (int i = 0; i < 5; i++) {
            System.out.println("i = " + i);
        }

        // 遍历数组 (传统)
        int[] numbers = {10, 20, 30, 40, 50};
        for (int i = 0; i < numbers.length; i++) {
            System.out.print(numbers[i] + " ");
        }
        System.out.println();

        // 遍历数组 (for-each)
        for (int num : numbers) {
            System.out.print(num + " ");
        }
        System.out.println();

        // 遍历集合 (for-each)
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        for (String name : names) {
            System.out.print(name + " ");
        }
        System.out.println();
    }
}

4.4 while / do...while

  • 原理:循环控制 (前判断、后判断)
    • while 循环:先检查条件,如果为 true 则执行循环体。可能一次都不执行。
    • do...while 循环:先执行循环体一次,再检查条件。至少执行一次。
  • 最佳实践与代码示例 (输入验证、不确定次数循环)
java 复制代码
import java.util.Scanner;

public class WhileLoops {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // while循环:用户输入验证 (可能多次询问)
        int validInput = -1;
        while (validInput < 0 || validInput > 100) {
            System.out.print("Enter a number between 0 and 100: ");
            validInput = scanner.nextInt();
        }
        System.out.println("Valid input: " + validInput);

        // do...while循环:菜单选择 (至少显示一次菜单)
        int choice;
        do {
            System.out.println("1. Option 1");
            System.out.println("2. Option 2");
            System.out.println("3. Exit");
            System.out.print("Choose: ");
            choice = scanner.nextInt();

            switch (choice) {
                case 1:
                    System.out.println("Option 1 selected.");
                    break;
                case 2:
                    System.out.println("Option 2 selected.");
                    break;
                case 3:
                    System.out.println("Exiting...");
                    break;
                default:
                    System.out.println("Invalid choice.");
            }
        } while (choice != 3);

        scanner.close();
    }
}

4.5 break

  • 原理:跳出循环或 switchbreak 用于立即终止当前所在的 switch 语句或循环 (for, while, do...while) 的执行,并跳出该结构。
  • 使用场景示例 (提前终止循环)
java 复制代码
public class BreakExample {
    public static void main(String[] args) {
        // 在switch中使用break (防止fall-through)
        // ... (见switch部分的例子)

        // 在循环中使用break (找到目标后提前退出)
        int[] numbers = {2, 5, 8, 10, 15};
        int target = 10;
        boolean found = false;

        for (int num : numbers) {
            if (num == target) {
                found = true;
                break; // 找到目标,跳出循环
            }
        }
        System.out.println("Target " + target + " found: " + found);

        // 跳出多层循环 (使用标签label)
        outerLoop: // 定义标签
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                System.out.println("i=" + i + ", j=" + j);
                if (i == 1 && j == 1) {
                    break outerLoop; // 跳出外层循环
                }
            }
        }
    }
}

4.6 continue

  • 原理:跳过当前循环迭代continue 用于立即跳过当前循环迭代的剩余语句,直接进入下一次迭代 (对于 for 循环,会先执行迭代部分)。
  • 使用场景示例 (跳过特定条件)
java 复制代码
public class ContinueExample {
    public static void main(String[] args) {
        // 打印1-10的奇数
        for (int i = 1; i <= 10; i++) {
            if (i % 2 == 0) { // 如果是偶数
                continue; // 跳过本次循环剩余部分,进入下一次迭代
            }
            System.out.println(i);
        }

        // 处理集合时跳过某些元素
        List<String> words = Arrays.asList("apple", "banana", null, "orange", "grape");
        for (String word : words) {
            if (word == null) {
                continue; // 跳过null元素
            }
            System.out.println(word.toUpperCase()); // 安全,因为null已被跳过
        }
    }
}

4.7 return

  • 原理:方法返回 (值或控制权)return 用于从方法中退出。
    • 如果方法有返回值类型(非 void),return 后面必须跟一个与返回值类型兼容的表达式。
    • 如果方法返回类型是 voidreturn 后面不能跟表达式,或者可以省略 return(方法执行到最后一行自动返回)。
  • 使用场景示例 (结束方法执行、返回结果)
java 复制代码
public class ReturnExamples {
    // void方法
    public void greet(String name) {
        if (name == null || name.isEmpty()) {
            return; // 提前退出方法,不执行后面的语句
        }
        System.out.println("Hello, " + name + "!");
    }

    // 有返回值方法
    public int max(int a, int b) {
        if (a > b) {
            return a; // 返回结果并退出
        }
        return b; // 返回结果并退出
    }

    public static void main(String[] args) {
        ReturnExamples examples = new ReturnExamples();
        examples.greet("Alice"); // 输出 Hello, Alice!
        examples.greet(""); // 无输出,因为return提前退出

        int larger = examples.max(10, 20);
        System.out.println("Larger number: " + larger); // 输出 20
    }
}

5. 异常处理关键字

5.1 try

  • 原理:异常监控块try 关键字用于定义一个代码块,该块内的代码是可能抛出异常的代码。它是异常处理结构 (try-catch-finally) 的开始。
  • 结构基础
java 复制代码
try {
    // 可能抛出异常的代码
} catch (ExceptionType1 e1) {
    // 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2 类型的异常
} finally {
    // 无论是否发生异常都会执行的代码 (资源清理)
}

5.2 catch

  • 原理:捕获并处理特定异常catch 块紧跟在 try 块之后,用于捕获 try 块中抛出的特定类型的异常,并提供处理逻辑。可以有多个 catch 块来处理不同类型的异常。异常类型应该从具体到一般(子类到父类)排列。
  • 最佳实践与代码示例 (捕获特定异常类型、多重 catch)
java 复制代码
public class CatchExample {
    public static void main(String[] args) {
        try {
            int[] nums = {1, 2, 3};
            System.out.println(nums[3]); // 可能抛出 ArrayIndexOutOfBoundsException
            String s = null;
            System.out.println(s.length()); // 可能抛出 NullPointerException (但上面已抛异常,不会执行到这里)
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage());
        } catch (NullPointerException e) {
            System.out.println("Caught NullPointerException: " + e.getMessage());
        } catch (Exception e) { // 捕获所有其他异常 (一般放最后)
            System.out.println("Caught general Exception: " + e.getMessage());
        }

        // Java 7+ 多重捕获
        try {
            // 可能抛出多种IO异常
        } catch (FileNotFoundException | IOException e) { // 使用 | 分隔
            System.out.println("IO error occurred: " + e.getMessage());
        }
    }
}

5.3 finally

  • 原理:资源清理块 (无论是否发生异常都执行)finally 块用于放置无论 try 块中是否发生异常都必须执行的代码。常用于关闭文件、释放数据库连接、释放网络连接等资源清理操作,以确保资源不会泄漏。
  • 最佳实践与代码示例 (关闭文件流、数据库连接)
java 复制代码
import java.io.*;

public class FinallyExample {
    public static void main(String[] args) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader("test.txt"));
            String line = reader.readLine();
            while (line != null) {
                System.out.println(line);
                line = reader.readLine();
            }
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        } finally {
            // 无论是否发生异常,都要关闭reader
            try {
                if (reader != null) {
                    reader.close(); // 关闭资源
                }
            } catch (IOException e) {
                System.out.println("Error closing reader: " + e.getMessage());
            }
        }

        // Java 7+ try-with-resources (自动关闭资源,隐式包含finally关闭)
        try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        } // 无需显式finally关闭,资源自动关闭
    }
}

5.4 throw

  • 原理:主动抛出异常throw 关键字用于在代码中显式地抛出一个异常 对象。通常用于:
    • 当检测到程序无法继续执行的错误条件时。
    • 将底层异常重新包装为更合适的业务异常。
    • 在自定义异常类中抛出实例。
  • 最佳实践与代码示例 (自定义异常、参数校验)
java 复制代码
// 自定义异常类
public class InsufficientFundsException extends Exception {
    private double amount;

    public InsufficientFundsException(double amount) {
        super("Insufficient funds. Required: $" + amount);
        this.amount = amount;
    }

    public double getAmount() {
        return amount;
    }
}

public class Account {
    private double balance;

    public void withdraw(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException(amount - balance); // 主动抛出异常
        }
        balance -= amount;
    }

    // 参数校验
    public void setInterestRate(double rate) {
        if (rate < 0) {
            throw new IllegalArgumentException("Interest rate cannot be negative."); // 抛出运行时异常
        }
        // ... set rate
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Account account = new Account(100);
        try {
            account.withdraw(150); // 可能抛出受检异常
        } catch (InsufficientFundsException e) {
            System.err.println("Error: " + e.getMessage());
            System.err.println("Shortage: $" + e.getAmount());
        }

        // 参数校验 (运行时异常)
        try {
            account.setInterestRate(-0.5);
        } catch (IllegalArgumentException e) {
            System.err.println("Invalid rate: " + e.getMessage());
        }
    }
}

5.5 throws

  • 原理:声明方法可能抛出的异常throws 关键字用在方法签名中,用于声明 该方法在执行过程中可能抛出 的受检异常 (Checked Exception) 类型。调用该方法的代码必须处理这些异常(使用 try-catch)或继续向上声明 (throws)。
  • 最佳实践与代码示例 (方法签名声明)
java 复制代码
import java.io.*;

public class ThrowsExample {
    // 声明方法可能抛出IOException
    public void readFile(String filename) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(filename));
        // ... 读取操作
        reader.close();
    }

    // 声明可能抛出多个异常
    public void processFile(String filename) throws FileNotFoundException, IOException {
        // ... 文件处理逻辑
    }

    // 调用声明了受检异常的方法,必须处理或声明
    public static void main(String[] args) {
        ThrowsExample example = new ThrowsExample();
        try {
            example.readFile("data.txt");
        } catch (IOException e) {
            System.err.println("File error: " + e.getMessage());
        }

        // 或者main方法也声明抛出
        // public static void main(String[] args) throws IOException {
        //     example.readFile("data.txt");
        // }
    }
}

6. 类型相关关键字

6.1 instanceof

  • 原理:对象类型检查instanceof 是一个二元运算符,用于检查一个对象是否是指定类或其子类的实例 ,或者是否实现了指定的接口。返回 boolean 值 (truefalse)。
  • 使用场景示例 (向下转型前的安全校验)
java 复制代码
public class InstanceofExample {
    public static void main(String[] args) {
        Object obj = "Hello"; // 字符串对象

        if (obj instanceof String) {
            String str = (String) obj; // 安全向下转型
            System.out.println("String length: " + str.length());
        }

        if (obj instanceof Integer) { // 不会成立
            System.out.println("It's an Integer");
        }

        // Java 16+ 模式匹配 instanceof (简化)
        if (obj instanceof String s) { // 直接声明变量s
            System.out.println("String length: " + s.length()); // 直接使用s
        }
    }
}

6.2 extends

  • 原理:类继承extends 关键字用于表示一个类继承自另一个类(称为父类或超类)。子类继承父类的非 private 字段和方法,并可以添加新的字段和方法,或重写父类的方法。Java 支持单继承(一个类只能有一个直接父类)。
  • 定义子类示例 (class Child extends Parent)
java 复制代码
public class Animal {
    public void eat() {
        System.out.println("Animal is eating");
    }
}

public class Dog extends Animal { // Dog 继承 Animal
    @Override
    public void eat() {
        System.out.println("Dog is eating dog food");
    }

    public void bark() {
        System.out.println("Dog is barking");
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.eat(); // 调用重写后的方法
        myDog.bark(); // 调用子类新增方法

        Animal animal = new Dog(); // 多态
        animal.eat(); // 实际调用Dog的eat()
        // animal.bark(); // 错误!Animal引用没有bark方法
    }
}

6.3 implements

  • 原理:接口实现implements 关键字用于表示一个类实现了一个或多个接口。实现接口的类必须提供接口中所有抽象方法的实现(除非该类是抽象类)。
  • 类实现接口示例 (class MyClass implements MyInterface)
java 复制代码
public interface Drawable {
    void draw();
}

public interface Resizable {
    void resize(int factor);
}

public class Circle implements Drawable, Resizable { // 实现多个接口
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }

    @Override
    public void resize(int factor) {
        System.out.println("Resizing circle by factor " + factor);
    }
}

// 使用
public class Main {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.draw();
        circle.resize(2);

        Drawable drawable = circle;
        drawable.draw();
        // drawable.resize(2); // 错误!Drawable引用没有resize方法
    }
}

6.4 import

  • 原理:引入其他包中的类/接口import 语句用于在编译时告诉编译器去哪里找程序中使用的类或接口。它简化了代码书写,避免了在每次使用类时都要写完整的包名。
  • 使用示例 (import java.util.List;)
java 复制代码
import java.util.List; // 导入单个类
import java.util.ArrayList;
import java.util.*; // 导入java.util包下的所有类 (谨慎使用,可能导致命名冲突)
import com.example.myapp.utils.StringUtils; // 导入自定义包中的类

public class ImportExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(); // 可以直接使用List和ArrayList
        list.add("Item");

        String reversed = StringUtils.reverse("Hello"); // 使用自定义工具类
        System.out.println(reversed);
    }
}
// 注意:java.lang包下的类 (如String, System) 会自动导入,无需显式import。

7. 其他重要关键字

7.1 package

  • 原理:定义类所属的包 (命名空间管理)package 语句用于声明当前 Java 文件中的类或接口所属的包。它必须是文件的第一条非注释语句(import 语句之前)。包名通常采用逆域名格式(如 com.example.myapp),用于组织类、避免命名冲突、控制访问权限。
  • 定义包示例 (package com.example.mypackage;)
java 复制代码
// 在文件 MyClass.java 的第一行
package com.example.mypackage;

public class MyClass {
    // ...
}

7.2 native

  • 原理:本地方法 (JNI)native 修饰的方法表示该方法不是用 Java 实现的,而是用其他语言(如 C、C++)编写的本地代码。它通过 Java Native Interface (JNI) 调用。native 方法没有方法体,以分号 ; 结束。
  • 声明示例 (public native void nativeMethod();)
java 复制代码
public class NativeExample {
    // 声明一个native方法
    public native void performNativeOperation();

    // 加载包含native方法实现的动态链接库
    static {
        System.loadLibrary("NativeLib"); // 在Windows上可能是NativeLib.dll,Linux上是libNativeLib.so
    }

    public static void main(String[] args) {
        NativeExample example = new NativeExample();
        example.performNativeOperation(); // 调用native方法
    }
}

7.3 strictfp

  • 原理:严格的浮点计算 (平台一致性)strictfp 修饰的类、接口或方法,会确保其内部的浮点运算(floatdouble)在任何平台上都遵循 IEEE 754 标准,从而保证计算结果的一致性。在需要高度可移植性的数值计算中可能会用到。
  • 使用示例 (public strictfp class StrictFloatCalc {})
java 复制代码
public strictfp class StrictFloatCalculator {
    public static strictfp double calculate(double a, double b) {
        return a * b; // 这个乘法运算将严格遵守IEEE 754标准
    }
}

7.4 transient

  • 原理:序列化排除字段transient 修饰的字段在对象被序列化(例如使用 ObjectOutputStream)时会被跳过。常用于标记那些不需要持久化或传输的敏感信息(如密码)、临时状态或重建时容易计算的字段。
  • 使用场景示例 (敏感信息、临时状态)
java 复制代码
import java.io.*;

public class User implements Serializable {
    private String username;
    private transient String password; // 不会被序列化
    private transient int loginAttempts; // 临时状态,不需要保存

    public User(String username, String password) {
        this.username = username;
        this.password = password;
        this.loginAttempts = 0;
    }

    // ... getters, setters
}

public class TransientExample {
    public static void main(String[] args) {
        User user = new User("admin", "secret123");

        // 序列化
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"))) {
            oos.writeObject(user);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 反序列化
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"))) {
            User deserializedUser = (User) ois.readObject();
            System.out.println("Username: " + deserializedUser.getUsername()); // 输出 admin
            System.out.println("Password: " + deserializedUser.getPassword()); // 输出 null (transient)
            System.out.println("LoginAttempts: " + deserializedUser.getLoginAttempts()); // 输出 0 (默认值)
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

7.5 volatile

  • 原理:变量可见性与指令重排 (轻量级同步)volatile 修饰的变量保证了:
    • 可见性 :当一个线程修改了 volatile 变量的值,新值会立即对其他线程可见。
    • 禁止指令重排序 :编译器或处理器不会对 volatile 变量的读写操作进行重排序优化(相对于其他内存操作)。
  • 使用场景示例 (状态标志位) :常用于简单的状态标志、中断请求等场景。对于复杂的原子性操作(如 i++),volatile 不能保证原子性,需要使用 synchronizedjava.util.concurrent.atomic 包中的类。
java 复制代码
public class VolatileExample {
    private volatile boolean running = true; // 状态标志位

    public void stop() {
        running = false; // 一个线程修改
    }

    public void doWork() {
        while (running) { // 另一个线程读取,保证看到最新值
            // 执行工作
        }
        System.out.println("Worker stopped.");
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileExample example = new VolatileExample();
        Thread workerThread = new Thread(example::doWork);
        workerThread.start();

        Thread.sleep(1000); // 主线程等待1秒
        example.stop(); // 主线程通知停止
        workerThread.join(); // 等待worker线程结束
    }
}

7.6 synchronized

  • 原理:线程同步 (方法、代码块)synchronized 是 Java 内置的锁机制,用于实现线程同步,确保多线程环境下共享资源的互斥访问。
    • 同步方法public synchronized void method() { ... }。锁对象是当前实例 (this)。
    • 同步静态方法public static synchronized void staticMethod() { ... }。锁对象是类的 Class 对象。
    • 同步代码块synchronized (lockObject) { ... }。可以指定任意对象作为锁。
  • 最佳实践与代码示例 (防止竞态条件)
java 复制代码
public class SynchronizedCounter {
    private int count = 0;

    // 同步方法 (锁是当前实例)
    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }

    // 使用同步代码块 (锁可以是任意对象)
    private Object lock = new Object();
    private int anotherCount = 0;

    public void incrementAnother() {
        synchronized (lock) {
            anotherCount++;
        }
    }

    public int getAnotherCount() {
        synchronized (lock) {
            return anotherCount;
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        SynchronizedCounter counter = new SynchronizedCounter();
        int numThreads = 100;
        int incrementsPerThread = 1000;

        Thread[] threads = new Thread[numThreads];
        for (int i = 0; i < numThreads; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < incrementsPerThread; j++) {
                    counter.increment();
                }
            });
            threads[i].start();
        }

        for (Thread thread : threads) {
            thread.join();
        }

        System.out.println("Final count (should be " + (numThreads * incrementsPerThread) + "): " + counter.getCount());
    }
}

7.7 const (保留字,未使用) Java 中 const 是保留字,但未被使用。Java 使用 final 来定义常量。

7.8 goto (保留字,未使用) Java 中 goto 是保留字,但未被使用。Java 使用结构化控制语句 (if, for, while, break, continue) 来控制流程。

8. Java 10+ 新增上下文关键字

8.1 var (Java 10)

  • 原理:局部变量类型推断var 用于声明局部变量,其类型由编译器根据初始化表达式自动推断 。它旨在减少冗余代码,提高可读性(当类型名称较长或重复时)。var 不是一个类型,它只是一个占位符。
  • 最佳实践与代码示例 (简化局部变量声明,提高可读性)
    • 适用于:初始化表达式类型清晰的情况(如 new 对象、调用方法返回值)。
    • 不适用于:字段、方法参数、返回类型、未初始化的局部变量。
    • 谨慎使用:当类型不明显或影响可读性时,建议显式声明类型。
java 复制代码
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class VarExample {
    public static void main(String[] args) {
        // 传统写法
        List<String> names = new ArrayList<>();
        Map<Integer, String> idToNameMap = new HashMap<>();
        String message = "Hello, var!";

        // 使用var
        var namesList = new ArrayList<String>(); // 推断为 ArrayList<String>
        var idMap = new HashMap<Integer, String>(); // 推断为 HashMap<Integer, String>
        var greeting = "Hello, var!"; // 推断为 String

        // 结合泛型
        var entries = idMap.entrySet(); // 推断为 Set<Map.Entry<Integer, String>>

        // 在for-each循环中
        for (var entry : entries) { // 推断为 Map.Entry<Integer, String>
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }

        // 注意:var不能用于以下情况
        // var x; // 错误:必须初始化
        // public var y = 10; // 错误:不能用于字段
        // public static void method(var param) {} // 错误:不能用于参数
        // public var method() { return 10; } // 错误:不能用于返回类型

        // 可读性考虑
        var result = calculateComplexResult(); // 如果calculateComplexResult返回类型不直观,可能降低可读性
    }

    private static ComplexResultType calculateComplexResult() {
        // ... 复杂计算
        return new ComplexResultType();
    }

    static class ComplexResultType {
    }
}

8.2 record (Java 14 - 预览,Java 16 - 正式)

  • 原理:透明数据载体类record 是一种特殊的类,用于声明不可变的数据载体 。编译器会自动为其生成:
    • 私有 final 字段(对应记录组件)。
    • 公共构造方法(规范构造方法)。
    • 每个组件的访问器方法(component() 形式,非传统的 getComponent())。
    • equals()hashCode()toString() 方法(基于所有组件)。
  • 定义与使用示例 (简化 POJO 定义)
java 复制代码
// 传统POJO
public class PointClass {
    private final int x;
    private final int y;

    public PointClass(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public boolean equals(Object o) { ... } // 冗长的手写实现
    @Override
    public int hashCode() { ... } // 冗长的手写实现
    @Override
    public String toString() { ... } // 冗长的手写实现
}

// 使用record
public record Point(int x, int y) { } // 一行搞定!编译器自动生成字段、构造方法、访问器、equals、hashCode、toString

// 使用
public class RecordExample {
    public static void main(String[] args) {
        Point p1 = new Point(3, 4);
        Point p2 = new Point(3, 4);

        System.out.println(p1); // 输出: Point[x=3, y=4]
        System.out.println("p1.x: " + p1.x()); // 访问器方法: x() 而不是 getX()
        System.out.println("p1 equals p2: " + p1.equals(p2)); // true

        // record是final的,不能继承
        // record可以声明静态字段、静态方法、实例方法、构造方法
        record Person(String name, int age) {
            // 自定义构造方法 (委托给规范构造方法)
            public Person {
                if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
                // name = name; 和 age = age; 是隐式赋值的
            }

            // 实例方法
            public String greeting() {
                return "Hello, my name is " + name;
            }
        }

        Person alice = new Person("Alice", 30);
        System.out.println(alice.greeting());
        // Person invalid = new Person("Bob", -5); // 抛出异常
    }
}

9. 综合实战案例:简易用户管理系统

9.1 需求分析 设计一个简单的用户管理系统,实现以下功能:

  1. 用户信息:用户名 (唯一)、密码、邮箱、角色 (ADMIN, USER)。
  2. 用户注册。
  3. 用户登录验证。
  4. 查询所有用户 (仅 ADMIN 角色)。
  5. 根据用户名查询用户 (仅 ADMIN 角色)。
  6. 修改用户密码 (需验证旧密码)。
  7. 删除用户 (仅 ADMIN 角色)。
  8. 使用文件存储用户数据 (模拟持久层)。
  9. 基本的异常处理 (用户已存在、用户不存在、密码错误、权限不足、文件操作错误)。

9.2 系统设计

  • 包结构com.example.usermanagement
  • 核心类/接口/枚举
    • User (record): 用户数据载体。
    • UserRole (enum): 用户角色枚举。
    • UserDao (interface): 用户数据访问接口 (持久层)。
    • FileUserDao (class): 基于文件的 UserDao 实现。
    • UserService (class): 用户业务逻辑服务。
    • UserManagementApp (class): 主程序 (控制台交互)。
  • 异常类
    • UserAlreadyExistsException (extends Exception)
    • UserNotFoundException (extends Exception)
    • PasswordMismatchException (extends Exception)
    • PermissionDeniedException (extends Exception)
    • DataAccessException (extends Exception)

9.3 核心类实现 (展示多个关键字应用)

java 复制代码
// UserRole.java
package com.example.usermanagement;

public enum UserRole {
    ADMIN, USER
}
java 复制代码
// User.java (使用record)
package com.example.usermanagement;

public record User(String username, String password, String email, UserRole role) {
    // 自定义构造方法进行校验
    public User {
        if (username == null || username.isBlank()) throw new IllegalArgumentException("Username cannot be blank");
        if (password == null || password.isBlank()) throw new IllegalArgumentException("Password cannot be blank");
        if (email == null || !email.contains("@")) throw new IllegalArgumentException("Invalid email");
    }
}
java 复制代码
// UserDao.java (接口)
package com.example.usermanagement;

import java.util.List;
import java.util.Optional;

public interface UserDao {
    void saveUser(User user) throws DataAccessException;
    Optional<User> findByUsername(String username) throws DataAccessException;
    List<User> findAllUsers() throws DataAccessException;
    void updateUser(User user) throws DataAccessException;
    void deleteUser(String username) throws DataAccessException;
}
java 复制代码
// FileUserDao.java (部分实现,展示关键字)
package com.example.usermanagement;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

public class FileUserDao implements UserDao {
    private static final String FILE_PATH = "users.dat";
    private final Map<String, User> userMap = new HashMap<>(); // 内存缓存

    public FileUserDao() throws DataAccessException {
        loadFromFile(); // 构造时加载文件数据
    }

    private void loadFromFile() throws DataAccessException {
        File file = new File(FILE_PATH);
        if (!file.exists()) return; // 文件不存在则跳过

        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
            Object data = ois.readObject();
            if (data instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, User> loadedMap = (Map<String, User>) data;
                userMap.clear();
                userMap.putAll(loadedMap);
            }
        } catch (IOException | ClassNotFoundException e) {
            throw new DataAccessException("Error loading users from file", e);
        }
    }

    private void saveToFile() throws DataAccessException {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH))) {
            oos.writeObject(userMap);
        } catch (IOException e) {
            throw new DataAccessException("Error saving users to file", e);
        }
    }

    @Override
    public void saveUser(User user) throws DataAccessException {
        if (userMap.containsKey(user.username())) {
            throw new UserAlreadyExistsException("Username '" + user.username() + "' already exists");
        }
        userMap.put(user.username(), user);
        saveToFile();
    }

    @Override
    public Optional<User> findByUsername(String username) throws DataAccessException {
        return Optional.ofNullable(userMap.get(username));
    }

    @Override
    public List<User> findAllUsers() throws DataAccessException {
        return new ArrayList<>(userMap.values());
    }

    @Override
    public void updateUser(User user) throws DataAccessException {
        if (!userMap.containsKey(user.username())) {
            throw new UserNotFoundException("User '" + user.username() + "' not found");
        }
        userMap.put(user.username(), user);
        saveToFile();
    }

    @Override
    public void deleteUser(String username) throws DataAccessException {
        if (!userMap.containsKey(username)) {
            throw new UserNotFoundException("User '" + username + "' not found");
        }
        userMap.remove(username);
        saveToFile();
    }
}
java 复制代码
// UserService.java (业务逻辑)
package com.example.usermanagement;

import java.util.List;

public class UserService {
    private final UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public void registerUser(User newUser) throws UserAlreadyExistsException, DataAccessException {
        userDao.saveUser(newUser);
    }

    public User login(String username, String password) throws UserNotFoundException, PasswordMismatchException, DataAccessException {
        User user = userDao.findByUsername(username)
                .orElseThrow(() -> new UserNotFoundException("User not found: " + username));
        if (!user.password().equals(password)) {
            throw new PasswordMismatchException("Incorrect password for user: " + username);
        }
        return user;
    }

    public List<User> listAllUsers(User currentUser) throws PermissionDeniedException, DataAccessException {
        if (currentUser.role() != UserRole.ADMIN) {
            throw new PermissionDeniedException("Only ADMIN can list all users");
        }
        return userDao.findAllUsers();
    }

    public User findUserByUsername(String username, User currentUser) throws PermissionDeniedException, UserNotFoundException, DataAccessException {
        if (currentUser.role() != UserRole.ADMIN && !currentUser.username().equals(username)) {
            throw new PermissionDeniedException("You can only query your own information");
        }
        return userDao.findByUsername(username)
                .orElseThrow(() -> new UserNotFoundException("User not found: " + username));
    }

    public void changePassword(String username, String oldPassword, String newPassword, User currentUser)
            throws UserNotFoundException, PasswordMismatchException, PermissionDeniedException, DataAccessException {
        if (!currentUser.username().equals(username) && currentUser.role() != UserRole.ADMIN) {
            throw new PermissionDeniedException("You can only change your own password");
        }
        User user = userDao.findByUsername(username)
                .orElseThrow(() -> new UserNotFoundException("User not found: " + username));
        if (!user.password().equals(oldPassword)) {
            throw new PasswordMismatchException("Old password is incorrect");
        }
        User updatedUser = new User(user.username(), newPassword, user.email(), user.role());
        userDao.updateUser(updatedUser);
    }

    public void deleteUser(String username, User currentUser) throws PermissionDeniedException, UserNotFoundException, DataAccessException {
        if (currentUser.role() != UserRole.ADMIN) {
            throw new PermissionDeniedException("Only ADMIN can delete users");
        }
        if (currentUser.username().equals(username)) {
            throw new PermissionDeniedException("Cannot delete yourself");
        }
        userDao.deleteUser(username);
    }
}
java 复制代码
// 自定义异常示例 (UserNotFoundException.java)
package com.example.usermanagement;

public class UserNotFoundException extends Exception {
    public UserNotFoundException(String message) {
        super(message);
    }
}
// 其他异常类类似定义
java 复制代码
// UserManagementApp.java (主程序,控制台交互 - 简化版)
package com.example.usermanagement;

import java.util.Scanner;

public class UserManagementApp {
    private final UserService userService;
    private final Scanner scanner;
    private User currentUser;

    public UserManagementApp(UserDao userDao) {
        this.userService = new UserService(userDao);
        this.scanner = new Scanner(System.in);
    }

    public static void main(String[] args) {
        try {
            UserDao userDao = new FileUserDao();
            UserManagementApp app = new UserManagementApp(userDao);
            app.run();
        } catch (DataAccessException e) {
            System.err.println("Fatal error: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public void run() {
        boolean running = true;
        while (running) {
            if (currentUser == null) {
                showLoginMenu();
            } else {
                showMainMenu();
            }
        }
        scanner.close();
    }

    private void showLoginMenu() {
        System.out.println("\n=== User Management System ===");
        System.out.println("1. Login");
        System.out.println("2. Register");
        System.out.println("3. Exit");
        System.out.print("Choose: ");
        int choice = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        try {
            switch (choice) {
                case 1:
                    loginUser();
                    break;
                case 2:
                    registerUser();
                    break;
                case 3:
                    System.out.println("Exiting...");
                    System.exit(0);
                    break;
                default:
                    System.out.println("Invalid choice.");
            }
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

    private void loginUser() throws Exception {
        System.out.print("Username: ");
        String username = scanner.nextLine();
        System.out.print("Password: ");
        String password = scanner.nextLine();
        currentUser = userService.login(username, password);
        System.out.println("Login successful! Welcome, " + currentUser.username());
    }

    private void registerUser() throws Exception {
        System.out.print("Username: ");
        String username = scanner.nextLine();
        System.out.print("Password: ");
        String password = scanner.nextLine();
        System.out.print("Email: ");
        String email = scanner.nextLine();
        System.out.print("Role (ADMIN/USER): ");
        UserRole role = UserRole.valueOf(scanner.nextLine().toUpperCase());

        User newUser = new User(username, password, email, role);
        userService.registerUser(newUser);
        System.out.println("Registration successful!");
    }

    private void showMainMenu() {
        System.out.println("\n=== Main Menu (" + currentUser.username() + " - " + currentUser.role() + ") ===");
        System.out.println("1. View My Info");
        System.out.println("2. Change Password");
        if (currentUser.role() == UserRole.ADMIN) {
            System.out.println("3. List All Users");
            System.out.println("4. Find User by Username");
            System.out.println("5. Delete User");
        }
        System.out.println("6. Logout");
        System.out.print("Choose: ");
        int choice = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        try {
            switch (choice) {
                case 1:
                    viewMyInfo();
                    break;
                case 2:
                    changePassword();
                    break;
                case 3:
                    if (currentUser.role() == UserRole.ADMIN) listAllUsers();
                    else System.out.println("Invalid choice.");
                    break;
                case 4:
                    if (currentUser.role() == UserRole.ADMIN) findUser();
                    else System.out.println("Invalid choice.");
                    break;
                case 5:
                    if (currentUser.role() == UserRole.ADMIN) deleteUser();
                    else System.out.println("Invalid choice.");
                    break;
                case 6:
                    currentUser = null;
                    System.out.println("Logged out.");
                    break;
                default:
                    System.out.println("Invalid choice.");
            }
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

    private void viewMyInfo() throws Exception {
        User user = userService.findUserByUsername(currentUser.username(), currentUser);
        System.out.println("Username: " + user.username());
        System.out.println("Email: " + user.email());
        System.out.println("Role: " + user.role());
        // 不显示密码
    }

    private void changePassword() throws Exception {
        System.out.print("Current Password: ");
        String oldPass = scanner.nextLine();
        System.out.print("New Password: ");
        String newPass = scanner.nextLine();
        userService.changePassword(currentUser.username(), oldPass, newPass, currentUser);
        System.out.println("Password changed successfully!");
    }

    private void listAllUsers() throws Exception {
        List<User> users = userService.listAllUsers(currentUser);
        System.out.println("=== All Users ===");
        for (User user : users) {
            System.out.println(user.username() + " - " + user.email() + " - " + user.role());
        }
    }

    private void findUser() throws Exception {
        System.out.print("Enter username to find: ");
        String username = scanner.nextLine();
        User user = userService.findUserByUsername(username, currentUser);
        System.out.println("Username: " + user.username());
        System.out.println("Email: " + user.email());
        System.out.println("Role: " + user.role());
    }

    private void deleteUser() throws Exception {
        System.out.print("Enter username to delete: ");
        String username = scanner.nextLine();
        userService.deleteUser(username, currentUser);
        System.out.println("User '" + username + "' deleted.");
    }
}

9.4 异常处理设计

  • 自定义异常类继承 Exception (受检异常) 或 RuntimeException (运行时异常)。本案例主要使用受检异常。
  • UserDao 实现中捕获底层 IOException 等,包装为 DataAccessException 抛出。
  • UserService 中根据业务规则抛出 UserAlreadyExistsExceptionUserNotFoundException 等业务异常。
  • 在主程序 (UserManagementApp) 中捕获所有异常,向用户显示友好错误信息。

9.5 主程序与测试

  • 运行 UserManagementAppmain 方法启动控制台程序。
  • 按照菜单提示进行注册、登录、修改密码、查询用户 (ADMIN)、删除用户 (ADMIN) 等操作。
  • 测试各种异常场景:注册同名用户、登录错误密码、非ADMIN尝试删除用户等。

这份指南涵盖了 Java 关键字的方方面面,结合原理、最佳实践和代码示例进行了详细讲解,并通过一个综合案例展示了关键字的实际应用。希望这份指南对你有所帮助!

相关推荐
西门吹雪分身2 小时前
JUC之线程中断
java
CSD资源分享2 小时前
Claude Code 国内API配置完整指南
java·windows·claude·claude code
悟能不能悟2 小时前
SimpleDateFormat 为什么线程不安全
开发语言·安全
砚边数影2 小时前
线性回归实战(一):房价预测数据集入库KingbaseES,表结构设计
java·数据库·人工智能·深度学习·机器学习·线性回归·金仓数据库
czlczl200209252 小时前
工作流 Flowable 全流程
java·spring boot·后端
李少兄2 小时前
IntelliJ IDEA 全局搜索完全指南:从高效使用到快捷键失效排查
java·intellij-idea·策略模式
沉默-_-2 小时前
掌握Maven:高效Java项目构建与管理
java·开发语言·后端·maven
一晌小贪欢2 小时前
Python 魔术方法实战:深度解析 Queue 模块的模块化设计与实现
开发语言·分布式·爬虫·python·python爬虫·爬虫分布式
wangbing11252 小时前
从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
java·开发语言