1. Java基础语法概述
Java作为一门面向对象的编程语言,其基础语法构成了整个Java生态的基石。对于初学者而言,掌握这些基础概念就像学习一门新语言的字母和单词一样重要。Java语法融合了C++的许多特性,但去掉了指针等复杂概念,使得它更易于上手。
Java程序的基本结构由类(class)和方法(method)组成。每个Java程序至少包含一个类,而每个类中可以包含多个方法。最经典的例子就是每个Java初学者都会写的"Hello World"程序:
java复制public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
这个简单的程序展示了几个关键语法元素:类定义、方法声明、语句和输出。理解这些基础构件是后续学习更复杂Java特性的前提。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 变量与数据类型
2.1 基本数据类型
Java是强类型语言,这意味着每个变量都必须先声明其类型才能使用。Java提供了8种基本数据类型:
- 整型:byte(1字节)、short(2字节)、int(4字节)、long(8字节)
- 浮点型:float(4字节)、double(8字节)
- 字符型:char(2字节)
- 布尔型:boolean(1位)
在实际开发中,int和double是最常用的数值类型。对于需要精确计算的场景,比如金融应用,应该使用BigDecimal而不是float或double,因为浮点数存在精度问题。
注意:Java中char类型使用Unicode编码,可以表示大多数语言的字符,这与C/C++中的char(1字节)不同。
2.2 变量声明与初始化
变量声明的基本语法是:数据类型 变量名;。例如:
java复制int age;
double salary;
char grade;
变量可以在声明时直接初始化:
java复制int count = 10;
double pi = 3.14159;
boolean isActive = true;
Java也支持同时声明多个同类型变量:
java复制int x = 1, y = 2, z = 3;
2.3 类型转换
Java中的类型转换分为自动类型转换(隐式)和强制类型转换(显式):
-
自动类型转换:从小范围类型向大范围类型转换时发生
java复制int i = 100; long l = i; // 自动转换为long -
强制类型转换:从大范围类型向小范围类型转换时需要显式转换
java复制double d = 100.04; int i = (int)d; // 结果为100,小数部分被截断
在实际编码中,应该尽量避免不必要的类型转换,特别是可能造成精度损失的强制转换。
3. 运算符与表达式
3.1 算术运算符
Java支持基本的算术运算符:
- 加法(+)
- 减法(-)
- 乘法(*)
- 除法(/)
- 取模(%)
需要注意整数除法的特性:
java复制int a = 5 / 2; // 结果为2,不是2.5
double b = 5 / 2.0; // 结果为2.5
3.2 关系与逻辑运算符
关系运算符用于比较两个值:
- 等于(==)
- 不等于(!=)
- 大于(>)
- 小于(<)
- 大于等于(>=)
- 小于等于(<=)
逻辑运算符用于组合布尔表达式:
- 逻辑与(&&)
- 逻辑或(||)
- 逻辑非(!)
提示:&&和||具有短路特性,即如果左边的表达式已经能确定结果,右边的表达式将不会被执行。
3.3 赋值运算符
除了基本的赋值(=),Java还提供了复合赋值运算符:
java复制int a = 10;
a += 5; // 等价于 a = a + 5
a *= 2; // 等价于 a = a * 2
3.4 位运算符
Java支持对整数类型进行位操作:
- 按位与(&)
- 按位或(|)
- 按位异或(^)
- 按位取反(~)
- 左移(<<)
- 右移(>>)
- 无符号右移(>>>)
位运算在底层编程、性能优化等场景中非常有用,但在日常业务开发中使用较少。
4. 控制流程语句
4.1 条件语句
Java提供了两种主要的条件语句:
- if-else语句:
java复制if (condition) {
// 条件为真时执行
} else {
// 条件为假时执行
}
- switch语句:
java复制switch (expression) {
case value1:
// 代码块1
break;
case value2:
// 代码块2
break;
default:
// 默认代码块
}
从Java 12开始,switch表达式得到了增强,支持更简洁的语法和箭头表达式:
java复制String dayType = switch (day) {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> "Weekday";
case "Saturday", "Sunday" -> "Weekend";
default -> throw new IllegalArgumentException("Invalid day: " + day);
};
4.2 循环语句
Java提供了三种循环结构:
- while循环:
java复制while (condition) {
// 循环体
}
- do-while循环:
java复制do {
// 循环体
} while (condition);
- for循环:
java复制for (初始化; 条件; 更新) {
// 循环体
}
此外,Java还提供了增强型for循环(foreach),用于遍历数组或集合:
java复制for (元素类型 变量名 : 数组或集合) {
// 循环体
}
4.3 跳转语句
Java支持三种跳转语句:
- break:退出当前循环或switch语句
- continue:跳过当前循环的剩余部分,进入下一次循环
- return:从方法中返回
在嵌套循环中,可以使用带标签的break和continue:
java复制outerLoop:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (i * j > 50) {
break outerLoop; // 跳出外层循环
}
}
}
5. 方法与参数传递
5.1 方法定义
方法的基本语法:
java复制修饰符 返回类型 方法名(参数列表) {
// 方法体
return 返回值; // 如果返回类型不是void
}
示例:
java复制public static int add(int a, int b) {
return a + b;
}
5.2 方法重载
Java支持方法重载(overload),即同一个类中可以定义多个同名方法,只要它们的参数列表不同:
java复制public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
}
5.3 参数传递机制
Java中的参数传递是按值传递的,这意味着方法内对参数的修改不会影响原始变量。但对于对象引用,传递的是引用的值,所以可以通过引用修改对象的状态:
java复制public class ParameterTest {
public static void changeValue(int x) {
x = 10;
}
public static void changeObject(ArrayList list) {
list.add("new element");
}
public static void main(String[] args) {
int a = 5;
changeValue(a);
System.out.println(a); // 输出5,值未改变
ArrayList<String> myList = new ArrayList<>();
changeObject(myList);
System.out.println(myList); // 输出[new element],对象状态改变了
}
}
5.4 可变参数
Java支持可变参数(varargs),用省略号(...)表示:
java复制public static int sum(int... numbers) {
int total = 0;
for (int num : numbers) {
total += num;
}
return total;
}
可变参数实际上是一个数组,调用时可以传入任意数量的参数:
java复制sum(1, 2, 3); // 返回6
sum(1, 2, 3, 4, 5); // 返回15
6. 数组与字符串
6.1 数组基础
数组是存储固定大小同类型元素的容器。声明和初始化数组有多种方式:
java复制// 声明后初始化
int[] arr1 = new int[5];
arr1[0] = 1;
// 声明时初始化
int[] arr2 = {1, 2, 3, 4, 5};
// 匿名数组
int[] arr3 = new int[]{1, 2, 3};
Java数组是对象,具有length属性表示数组长度:
java复制int length = arr2.length; // 5
6.2 多维数组
Java支持多维数组,最常见的是二维数组:
java复制// 声明二维数组
int[][] matrix = new int[3][3];
// 初始化二维数组
int[][] matrix2 = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
Java中的多维数组实际上是数组的数组,因此可以有不规则数组:
java复制int[][] irregular = new int[3][];
irregular[0] = new int[2];
irregular[1] = new int[3];
irregular[2] = new int[1];
6.3 字符串处理
String是Java中最常用的类之一。字符串是不可变的,任何修改操作都会创建新的字符串对象。
常用字符串操作:
java复制String s = "Hello";
int len = s.length(); // 5
char c = s.charAt(1); // 'e'
String sub = s.substring(1, 3); // "el"
String upper = s.toUpperCase(); // "HELLO"
String concat = s.concat(" World"); // "Hello World"
boolean contains = s.contains("ell"); // true
从Java 8开始,String类加入了join方法,方便拼接字符串:
java复制String joined = String.join(", ", "A", "B", "C"); // "A, B, C"
7. 面向对象基础
7.1 类与对象
类是对象的蓝图,对象是类的实例。定义类的语法:
java复制public class Person {
// 字段(属性)
private String name;
private int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 方法
public void sayHello() {
System.out.println("Hello, my name is " + name);
}
}
创建对象:
java复制Person p = new Person("Alice", 25);
p.sayHello();
7.2 封装与访问控制
Java通过访问修饰符实现封装:
- private:仅本类可见
- protected:本类、同包和子类可见
- default(无修饰符):本类和同包可见
- public:所有类可见
良好的封装实践:
java复制public class BankAccount {
private double balance;
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
}
7.3 继承与多态
继承使用extends关键字:
java复制public class Employee extends Person {
private String department;
public Employee(String name, int age, String department) {
super(name, age); // 调用父类构造方法
this.department = department;
}
@Override
public void sayHello() {
super.sayHello();
System.out.println("I work in " + department);
}
}
多态允许子类对象被当作父类对象使用:
java复制Person p = new Employee("Bob", 30, "IT");
p.sayHello(); // 调用的是Employee的sayHello方法
7.4 抽象类与接口
抽象类用abstract修饰,可以包含抽象方法:
java复制public abstract class Shape {
public abstract double area();
public void printArea() {
System.out.println("Area: " + area());
}
}
接口定义了一组方法的契约:
java复制public interface Drawable {
void draw();
void setColor(String color);
}
从Java 8开始,接口可以包含默认方法和静态方法:
java复制public interface Calculator {
int add(int a, int b);
default int subtract(int a, int b) {
return a - b;
}
static int multiply(int a, int b) {
return a * b;
}
}
8. 异常处理
8.1 异常分类
Java异常分为两大类:
- 检查型异常(Checked Exception):必须处理或声明抛出
- 非检查型异常(Unchecked Exception):RuntimeException及其子类
常见的异常类:
- IOException:输入输出异常
- NullPointerException:空指针异常
- ArrayIndexOutOfBoundsException:数组越界异常
- ClassCastException:类型转换异常
8.2 try-catch-finally
基本异常处理结构:
java复制try {
// 可能抛出异常的代码
} catch (ExceptionType1 e1) {
// 处理ExceptionType1异常
} catch (ExceptionType2 e2) {
// 处理ExceptionType2异常
} finally {
// 无论是否发生异常都会执行的代码
}
从Java 7开始,支持try-with-resources语法,自动关闭资源:
java复制try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
8.3 自定义异常
可以创建自己的异常类:
java复制public class InsufficientFundsException extends Exception {
private double amount;
public InsufficientFundsException(double amount) {
super("Insufficient funds: " + amount);
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
使用自定义异常:
java复制public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount - balance);
}
balance -= amount;
}
9. 集合框架
9.1 主要接口
Java集合框架的核心接口:
- Collection:所有集合类的根接口
- List:有序集合,允许重复
- Set:不包含重复元素的集合
- Map:键值对集合
9.2 常用实现类
List接口的主要实现类:
- ArrayList:基于动态数组,随机访问快
- LinkedList:基于链表,插入删除快
Set接口的主要实现类:
- HashSet:基于哈希表,无序
- LinkedHashSet:保持插入顺序
- TreeSet:基于红黑树,有序
Map接口的主要实现类:
- HashMap:基于哈希表,无序
- LinkedHashMap:保持插入顺序
- TreeMap:基于红黑树,按键排序
9.3 集合操作示例
java复制// List示例
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
System.out.println(list.get(1)); // "Banana"
// Set示例
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(1); // 重复元素不会被添加
System.out.println(set.size()); // 2
// Map示例
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 25);
map.put("Bob", 30);
System.out.println(map.get("Alice")); // 25
9.4 泛型与集合
泛型提供了编译时类型安全:
java复制List<String> strings = new ArrayList<>();
strings.add("Hello");
// strings.add(123); // 编译错误
String s = strings.get(0); // 不需要强制类型转换
自定义泛型类:
java复制public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
10. 输入输出与文件操作
10.1 标准输入输出
Java通过System类提供标准I/O流:
java复制// 标准输出
System.out.println("Hello"); // 输出并换行
System.out.print("World"); // 输出不换行
// 标准输入
Scanner scanner = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.println("Hello, " + name);
10.2 文件读写
使用File类表示文件:
java复制File file = new File("test.txt");
System.out.println("File exists: " + file.exists());
System.out.println("File size: " + file.length() + " bytes");
使用BufferedReader读取文本文件:
java复制try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
使用BufferedWriter写入文本文件:
java复制try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
bw.write("Hello, World!");
bw.newLine();
bw.write("This is a test.");
} catch (IOException e) {
e.printStackTrace();
}
10.3 对象序列化
Java对象可以通过实现Serializable接口来支持序列化:
java复制public class Person implements Serializable {
private String name;
private int age;
// 构造方法、getter、setter等
}
序列化对象到文件:
java复制Person p = new Person("Alice", 25);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"))) {
oos.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
}
从文件反序列化对象:
java复制try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"))) {
Person p = (Person) ois.readObject();
System.out.println(p.getName()); // "Alice"
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
11. 日期时间API
11.1 旧版Date类
Java 8之前的日期时间API主要使用Date和Calendar类:
java复制Date now = new Date(); // 当前日期时间
System.out.println(now);
Calendar cal = Calendar.getInstance();
cal.set(2023, Calendar.JANUARY, 1); // 2023年1月1日
Date newYear = cal.getTime();
11.2 Java 8新日期时间API
Java 8引入了java.time包,提供了更强大的日期时间处理能力:
- LocalDate:只包含日期
java复制LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1990, Month.JANUARY, 1);
- LocalTime:只包含时间
java复制LocalTime now = LocalTime.now();
LocalTime noon = LocalTime.of(12, 0);
- LocalDateTime:包含日期和时间
java复制LocalDateTime current = LocalDateTime.now();
LocalDateTime meeting = LocalDateTime.of(2023, 3, 15, 14, 30);
- 日期时间计算
java复制LocalDate tomorrow = today.plusDays(1);
LocalDateTime inTwoHours = current.plusHours(2);
- 格式化与解析
java复制DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String formatted = current.format(formatter);
LocalDateTime parsed = LocalDateTime.parse("2023-03-15 14:30", formatter);
12. Lambda表达式与函数式编程
12.1 Lambda表达式基础
Lambda表达式是Java 8引入的重要特性,用于简化匿名内部类的写法:
java复制// 传统方式
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// Lambda方式
Runnable r2 = () -> System.out.println("Hello");
Lambda表达式语法:
code复制(parameters) -> expression
或
(parameters) -> { statements; }
12.2 函数式接口
函数式接口是只包含一个抽象方法的接口,可以用@FunctionalInterface注解标记:
java复制@FunctionalInterface
interface Greeting {
void sayHello(String name);
}
Java内置了多个常用函数式接口:
- Predicate
:接受一个参数,返回boolean - Function<T,R>:接受一个参数,返回一个结果
- Consumer
:接受一个参数,无返回值 - Supplier
:无参数,返回一个结果
12.3 方法引用
方法引用是Lambda表达式的简写形式,有四种类型:
- 静态方法引用:
ClassName::staticMethod - 实例方法引用:
instance::method - 任意对象的实例方法引用:
ClassName::method - 构造方法引用:
ClassName::new
示例:
java复制List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(System.out::println); // 实例方法引用
List<Integer> lengths = names.stream()
.map(String::length) // 任意对象的实例方法引用
.collect(Collectors.toList());
12.4 Stream API
Stream API提供了一种声明式处理集合数据的方式:
java复制List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 过滤和转换
List<String> longNames = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
// 统计
long count = names.stream()
.filter(name -> name.startsWith("A"))
.count();
// 排序
List<String> sorted = names.stream()
.sorted()
.collect(Collectors.toList());
// 分组
Map<Integer, List<String>> grouped = names.stream()
.collect(Collectors.groupingBy(String::length));
13. 多线程编程
13.1 线程创建
创建线程的两种方式:
- 继承Thread类:
java复制class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread running");
}
}
MyThread t = new MyThread();
t.start();
- 实现Runnable接口:
java复制class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable running");
}
}
Thread t = new Thread(new MyRunnable());
t.start();
Java 8以后,可以使用Lambda表达式简化Runnable的实现:
java复制Thread t = new Thread(() -> System.out.println("Lambda thread"));
t.start();
13.2 线程同步
当多个线程访问共享资源时,需要使用同步机制:
- synchronized方法:
java复制public synchronized void increment() {
count++;
}
- synchronized代码块:
java复制public void increment() {
synchronized(this) {
count++;
}
}
- Lock接口:
java复制private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
13.3 线程间通信
使用wait()和notify()/notifyAll()实现线程间通信:
java复制class SharedResource {
private boolean ready = false;
public synchronized void produce() {
ready = true;
notifyAll();
}
public synchronized void consume() throws InterruptedException {
while (!ready) {
wait();
}
System.out.println("Consumed");
}
}
13.4 线程池
Java提供了Executor框架来管理线程池:
java复制ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executor.execute(() -> {
System.out.println("Task executed by " + Thread.currentThread().getName());
});
}
executor.shutdown();
Java 8引入了CompletableFuture,简化异步编程:
java复制CompletableFuture.supplyAsync(() -> {
// 异步任务
return "Result";
}).thenAccept(result -> {
// 处理结果
System.out.println(result);
});
14. 反射与注解
14.1 反射基础
反射允许在运行时检查类、接口、字段和方法:
java复制Class<?> clazz = Class.forName("java.lang.String");
// 获取类信息
System.out.println("Class name: " + clazz.getName());
System.out.println("Simple name: " + clazz.getSimpleName());
// 获取字段
Field[] fields = clazz.getDeclaredFields();
// 获取方法
Method[] methods = clazz.getDeclaredMethods();
14.2 通过反射操作对象
java复制Class<?> clazz = Person.class;
// 创建实例
Person p = (Person) clazz.getConstructor(String.class, int.class)
.newInstance("Alice", 25);
// 访问字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 访问私有字段
nameField.set(p, "Bob");
// 调用方法
Method sayHello = clazz.getMethod("sayHello");
sayHello.invoke(p);
14.3 注解基础
Java注解是元数据,可以添加到代码元素上:
java复制@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String value() default "";
int priority() default 0;
}
使用注解:
java复制public class MyClass {
@MyAnnotation(value = "important", priority = 1)
public void importantMethod() {
// ...
}
}
14.4 处理注解
通过反射可以读取和处理注解:
java复制Method method = MyClass.class.getMethod("importantMethod");
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
if (annotation != null) {
System.out.println("Value: " + annotation.value());
System.out.println("Priority: " + annotation.priority());
}
15. Java模块系统(Java 9+)
15.1 模块基础
Java 9引入了模块系统,模块通过module-info.java文件定义:
java复制module com.example.myapp {
requires java.base; // 隐式依赖
requires java.sql;
requires transitive com.example.mylib; // 传递依赖
exports com.example.myapp.api;
exports com.example.myapp.internal to com.example.tests;
opens com.example.myapp.model to hibernate.core;
}
15.2 模块描述符指令
主要模块指令:
- requires:声明依赖
- requires transitive:声明传递依赖
- exports:导出包
- exports...to:限定导出
- opens:开放反射访问
- opens...to:限定开放
- provides...with:提供服务实现
- uses:声明服务消费者
15.3 模块化开发实践
模块化开发的主要步骤:
- 将代码组织到模块中
- 为每个模块创建module-info.java
- 使用requires声明依赖关系
- 使用exports控制API暴露
- 使用mvn或gradle构建模块化应用
模块化带来的好处:
- 更强的封装性
- 更清晰的依赖管理
- 更小的运行时镜像(通过jlink)
- 更好的可维护性
16. Java新特性概览
16.1 Java 10-17重要特性
- 局部变量类型推断(var, Java 10):
java复制var list = new ArrayList<String>(); // 推断为ArrayList<String>
var stream = list.stream(); // 推断为Stream<String>
- 文本块(Java 13, 15成为标准特性):
java复制String json = """
{
"name": "Alice",
"age": 25,
"address": {
"street": "Main St",
"city": "New York"
}
}
""";
- switch表达式(Java 14成为标准特性):
java复制String dayType = switch (day) {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> "Weekday";
case "Saturday", "Sunday" -> "Weekend";
default -> throw new IllegalArgumentException("Invalid day: " + day);
};
- 记录类(record, Java 16成为标准特性):
java复制public record Point(int x, int y) {
// 自动生成构造方法、equals、hashCode、toString等
}
Point p = new Point(10, 20);
System.out.println(p.x()); // 10
System.out.println(p); // Point[x=10, y=20]
- 密封类(sealed, Java 17成为标准特性):
java复制public sealed class Shape permits Circle, Square, Rectangle {
// ...
}
public final class Circle extends Shape {
private double radius;
// ...
}
public non-sealed class Square extends Shape {
private double side;
// ...
}
16.2 Java 18-21预览特性
- 模式匹配增强(Java 18+):
java复制// instanceof模式匹配
if (obj instanceof String s) {
System.out.println(s.length());
}
// switch模式匹配
String formatted = switch (obj) {
case Integer i -> String.format("int %d", i);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
- 虚拟线程(Java 19预览, 21成为标准特性):
java复制try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
System.out.println("Running on virtual thread");
});
}
- 结构化并发(Java 19预览):
java复制try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> findUser());
Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join(); // 等待所有任务
scope.throwIfFailed(); // 如果有失败则抛出异常
System.out.println("User: " + user.resultNow() + ", order: " + order.resultNow());
}
17. 编码规范与最佳实践
17.1 命名规范
-
类名:大驼峰,名词
java复制public class BankAccount {} -
方法名:小驼峰,动词或动词短语
java复制public void calculateInterest() {} -
变量名:小驼峰,有意义
java复制int accountBalance; -
常量名:全大写,下划线分隔
java复制public static final double INTEREST_RATE = 0.05;
17.2 代码组织
-
类成员顺序:
- 静态字段
- 实例字段
- 构造方法
- 工厂方法
- 其他方法(公共→受保护→私有)
- 内部类/接口
-
方法长度:建议不超过20-30行
-
类长度:建议不超过300-500行
17.3 异常处理最佳实践
-
不要忽略异常:
java复制// 不好 try { // ... } catch (Exception e) { // 什么都不做 } // 好 try { // ... } catch (Exception e) { log.error("Error occurred", e); } -
使用特定的异常类型:
java复制// 不好 throw new Exception("File not found"); // 好 throw new FileNotFoundException("config.properties not found"); -
异常包含有用信息:
java复制// 不好 throw new IllegalArgumentException("Invalid argument"); // 好 throw new IllegalArgumentException("Age cannot be negative: " + age);
17.4 性能注意事项
-
字符串拼接使用StringBuilder:
java复制// 不好(会产生多个中间字符串) String result = ""; for (String s : strings) { result += s; } // 好 StringBuilder sb = new StringBuilder(); for (String s : strings) { sb.append(s); } String result = sb.toString(); -
避免不必要的对象创建:
java复制// 不好(每次调用都创建新Pattern) boolean isValid(String input) { return Pattern.compile("\\d+").matcher(input).matches(); } // 好 private static final Pattern DIGITS = Pattern.compile("\\d+"); boolean isValid(String input) { return DIGITS.matcher(input).matches(); } -
使用基本类型而非包装类:
java复制// 不好 Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; // 自动装箱/拆箱 } // 好 long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; }
18. 调试与测试
18.1 调试技巧
-
使用IDE调试功能:
- 断点
- 条件断点
- 表达式求值
- 变量监视
-
日志调试:
java复制import java.util.logging.Logger; public class MyClass { private static final Logger LOG = Logger.getLogger(MyClass.class.getName()); public void doSomething() { LOG.info("Starting operation"); try { // ... LOG.fine("Detailed debug info"); } catch (Exception e) { LOG.severe("Error occurred: " + e.getMessage()); } } } -
使用断言:
java复制public double divide(double a, double b) { assert b != 0 : "Divisor cannot be zero"; return a / b; }
18.2 单元测试
使用JUnit 5编写测试:
java复制import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
@Test
void testAdd() {
Calculator calc = new Calculator();
assertEquals(5, calc.add(2, 3));
}
@Test
void testDivide() {
Calculator calc = new Calculator();
assertThrows(ArithmeticException.class, () -> calc.divide(1, 0));
}
}
18.3 测试驱动开发(TDD)
TDD基本流程:
- 编写一个失败的测试
- 实现最简单的代码使测试通过
- 重构代码,保持测试通过
- 重复
示例:
java复制// 第一步:编写测试
@Test
void testFibonacci() {
assertEquals(0
