深入探索Java编程的高效之道
立即解锁
发布时间: 2025-08-18 00:25:47 阅读量: 1 订阅数: 4 

# 深入探索 Java 编程的高效之道
## 1. Java 编程资源的赞誉与推荐
众多业内人士对 Java 编程资源给予了高度评价,以下是一些代表性的观点:
- **James Gosling**:Java 编程语言的发明者,他表示真希望十年前就有这样的资源,尽管有人认为他不需要 Java 书籍,但他觉得这个资源是必需的。
- **Gilad Bracha**:Cadence Design Systems 的杰出工程师,也是《The Java™ Language Specification, Third Edition》的合著者,他认为这是一本优秀的资源,充满了关于使用 Java 编程语言和面向对象编程的良好建议。
- **Peter Tran**:JavaRanch.com 的工作人员,他给这个资源打了 10 分,认为任何想要编写让他人易于阅读和维护的优秀 Java 代码的人都应该拥有它,而且其中的信息不会因 JDK 库的后续版本而过时。
## 2. Java 系列资源概览
Java 领域有丰富的学习资源,涵盖了从基础语法到高级应用的各个方面,以下是部分资源的介绍:
| 资源名称 | 主要内容 |
| --- | --- |
| 《The Java™ Programming Language, Fourth Edition》 | 由 Ken Arnold、James Gosling 和 David Holmes 编写,深入讲解 Java 编程语言的语法和特性。 |
| 《Effective Java™ Programming Language Guide》《Effective Java,™ Second Edition》 | Joshua Bloch 的作品,提供了关于 Java 编程的实用建议和最佳实践。 |
| 《The J2EE™ Tutorial, Second Edition》 | Stephanie Bodoff、Dale Green、Kim Haase 和 Eric Jendrock 所著,介绍 J2EE 平台的相关知识。 |
| 《The Java™ Tutorial, Third Edition: A Short Course on the Basics》 | Mary Campione、Kathy Walrath 和 Alison Huml 编写,是 Java 基础的入门教程。 |
## 3. Java 编程的关键要素
学习一门编程语言需要掌握三个关键要素,就像学习第二语言一样:
- **语法结构**:了解语言的基本规则和结构,例如 Java 是面向对象的,具有单继承特性,并且在每个方法中支持命令式(面向语句)的编码风格。
- **词汇**:熟悉标准库提供的数据结构、操作和功能,例如 Java 库涵盖了图形显示支持、网络、分布式计算和安全等方面。
- **习惯用法**:掌握编写代码的惯用和有效方式,这有助于提高代码的可读性、可维护性和可扩展性。
下面是一个简单的 mermaid 流程图,展示了学习 Java 编程的基本流程:
```mermaid
graph LR
A[学习语法结构] --> B[掌握词汇]
B --> C[熟悉习惯用法]
C --> D[编写高质量代码]
```
## 4. Java 平台的发展与变化
自 2001 年以来,Java 平台发生了许多重大变化:
- **语言特性的增强**:Java 5 引入了泛型、枚举类型、注解、自动装箱和 for - each 循环等重要特性,这些特性使得 Java 代码更加简洁、安全和易于维护。
- **并发库的更新**:Java 5 还发布了新的并发库 `java.util.concurrent`,为多线程编程提供了更强大的支持。
- **开发工具的普及**:现代集成开发环境(IDE)如 Eclipse、IntelliJ IDEA 和 NetBeans 得到了广泛应用,静态分析工具如 FindBugs 也帮助开发者提高代码质量。
## 5. 编写高质量 Java 代码的建议
为了编写高质量的 Java 代码,有以下一些实用建议:
### 5.1 创建和销毁对象
- **考虑使用静态工厂方法而非构造函数**:静态工厂方法可以提供更具描述性的方法名,并且可以控制对象的创建过程。
- **面对多个构造函数参数时考虑使用构建器**:当一个类有多个可选参数时,使用构建器模式可以使代码更易于阅读和维护。
- **使用私有构造函数或枚举类型来实现单例属性**:确保一个类只有一个实例,并提供全局访问点。
- **使用私有构造函数来强制不可实例化**:对于工具类等不需要实例化的类,可以使用私有构造函数来防止意外实例化。
- **避免创建不必要的对象**:尽量复用对象,减少内存开销。
- **消除过时的对象引用**:及时释放不再使用的对象引用,避免内存泄漏。
- **避免使用终结器**:终结器的执行时间不确定,可能会导致性能问题。
### 5.2 所有对象通用的方法
- **重写 equals 方法时遵守通用约定**:确保 equals 方法满足自反性、对称性、传递性和一致性。
- **重写 equals 方法时总是重写 hashCode 方法**:保证相等的对象具有相同的哈希码,以便在哈希表中正确工作。
- **总是重写 toString 方法**:提供对象的字符串表示,方便调试和日志记录。
- **谨慎重写 clone 方法**:clone 方法的实现需要谨慎处理,确保对象的深拷贝。
- **考虑实现 Comparable 接口**:使对象可以进行比较和排序。
### 5.3 类和接口
- **最小化类和成员的可访问性**:遵循访问控制原则,减少类和成员的可见性,提高代码的安全性和可维护性。
- **在公共类中使用访问器方法而不是公共字段**:封装类的属性,提供更好的控制和可维护性。
- **最小化可变性**:创建不可变类可以减少程序的复杂性,提高线程安全性。
- **优先使用组合而不是继承**:组合可以提供更灵活的代码结构,避免继承带来的一些问题。
- **为继承设计并记录文档,否则禁止继承**:如果一个类设计为可继承,需要提供清晰的文档和合适的方法。
- **优先使用接口而不是抽象类**:接口可以实现多继承,提供更大的灵活性。
- **仅使用接口来定义类型**:避免使用接口来定义常量等非类型相关的内容。
- **优先使用类层次结构而不是标记类**:类层次结构可以提供更清晰的代码结构和更好的可扩展性。
- **使用函数对象来表示策略**:函数对象可以实现策略模式,使代码更加灵活。
- **优先使用静态成员类而不是非静态成员类**:静态成员类不依赖于外部类的实例,减少内存开销。
### 5.4 泛型
- **在新代码中不使用原始类型**:使用泛型可以提高代码的类型安全性。
- **消除未检查的警告**:确保代码中没有未检查的类型转换警告。
- **优先使用列表而不是数组**:列表提供了更好的类型安全性和灵活性。
- **优先使用泛型类型**:泛型类型可以提高代码的复用性和类型安全性。
- **优先使用泛型方法**:泛型方法可以在不同类型上使用相同的逻辑。
- **使用有界通配符来增加 API 的灵活性**:有界通配符可以使泛型代码更加灵活。
- **考虑使用类型安全的异构容器**:类型安全的异构容器可以存储不同类型的对象。
### 5.5 枚举和注解
- **使用枚举而不是 int 常量**:枚举类型提供了更好的类型安全性和可读性。
- **使用实例字段而不是序号**:避免使用枚举的序号来表示其状态,使用实例字段更具可读性。
- **使用 EnumSet 而不是位字段**:EnumSet 提供了更高效和类型安全的位操作。
- **使用 EnumMap 而不是序号索引**:EnumMap 可以提高代码的可读性和性能。
- **使用接口来模拟可扩展枚举**:通过接口可以实现枚举的扩展。
- **优先使用注解而不是命名模式**:注解可以提供更清晰和灵活的元数据。
- **始终使用 Override 注解**:确保重写方法的正确性。
- **使用标记接口来定义类型**:标记接口可以为类添加额外的类型信息。
### 5.6 方法
- **检查参数的有效性**:在方法开始时检查参数的有效性,避免运行时错误。
- **在需要时进行防御性复制**:防止外部对象修改内部状态。
- **仔细设计方法签名**:方法名和参数应该具有清晰的含义,易于理解和使用。
- **谨慎使用重载**:重载方法应该具有明确的语义,避免造成混淆。
- **谨慎使用可变参数**:可变参数应该谨慎使用,确保代码的可读性和性能。
- **返回空数组或集合而不是 null**:避免返回 null 导致的空指针异常。
- **为所有暴露的 API 元素编写文档注释**:提高代码的可维护性和可理解性。
### 5.7 通用编程
- **最小化局部变量的作用域**:减少变量的生命周期,提高代码的可读性和可维护性。
- **优先使用 for - each 循环而不是传统的 for 循环**:for - each 循环更加简洁和安全。
- **了解并使用库**:充分利用 Java 标准库提供的功能,提高开发效率。
- **如果需要精确答案,避免使用 float 和 double**:float 和 double 可能会导致精度问题,使用 BigDecimal 等类型。
- **优先使用基本类型而不是包装类型**:基本类型的性能更高。
- **在其他类型更合适的地方避免使用字符串**:字符串操作可能会导致性能问题,选择合适的数据类型。
- **注意字符串拼接的性能**:使用 StringBuilder 或 StringBuffer 进行字符串拼接,避免使用 + 运算符。
- **通过接口引用对象**:提高代码的灵活性和可扩展性。
- **优先使用接口而不是反射**:反射可能会导致性能问题,尽量使用接口来实现动态调用。
- **谨慎使用本地方法**:本地方法的使用需要谨慎,确保其安全性和性能。
- **谨慎优化**:在进行优化之前,先进行性能分析,确保优化的有效性。
- **遵循公认的命名约定**:提高代码的可读性和可维护性。
### 5.8 异常
- **仅在异常情况下使用异常**:异常应该用于处理意外情况,而不是正常的控制流。
- **使用受检查异常处理可恢复的情况,使用运行时异常处理编程错误**:合理分类异常,提高代码的健壮性。
- **避免不必要地使用受检查异常**:减少代码的复杂性。
- **优先使用标准异常**:提高代码的可读性和可维护性。
- **抛出与抽象层次相适应的异常**:异常应该反映问题的本质。
- **记录每个方法抛出的所有异常**:提高代码的可维护性。
- **在详细消息中包含失败捕获信息**:方便调试和定位问题。
- **努力实现失败原子性**:确保方法在出现异常时能够保持数据的一致性。
- **不要忽略异常**:捕获异常后应该进行适当的处理。
### 5.9 并发
- **同步对共享可变数据的访问**:确保多线程环境下数据的一致性。
- **避免过度同步**:过度同步会导致性能问题。
- **优先使用执行器和任务而不是线程**:执行器和任务提供了更高级的线程管理功能。
- **优先使用并发工具而不是 wait 和 notify**:并发工具提供了更简单和安全的并发编程方式。
- **记录线程安全性**:提高代码的可维护性。
- **谨慎使用延迟初始化**:延迟初始化需要考虑线程安全问题。
- **不要依赖线程调度器**:线程调度是不确定的,编写健壮的代码。
- **避免使用线程组**:线程组的使用场景有限,并且可能会导致一些问题。
### 5.10 序列化
- **谨慎实现 Serializable 接口**:实现 Serializable 接口需要考虑版本兼容性等问题。
- **考虑使用自定义序列化形式**:自定义序列化形式可以提高性能和安全性。
- **防御性地编写 readObject 方法**:防止反序列化时的数据损坏。
- **对于实例控制,优先使用枚举类型而不是 readResolve**:枚举类型提供了更好的实例控制。
- **考虑使用序列化代理而不是序列化实例**:序列化代理可以提高序列化的安全性。
通过遵循这些建议,可以编写出更加高效、可靠和易于维护的 Java 代码,充分发挥 Java 平台的优势。
## 6. 编写高质量 Java 代码建议的详细说明
### 6.1 创建和销毁对象
| 建议 | 说明 |
| --- | --- |
| 考虑使用静态工厂方法而非构造函数 | 静态工厂方法可提供更具描述性的方法名,如 `Boolean.valueOf(boolean b)` ,能清晰表达方法用途,还可控制对象创建过程,如单例模式中可确保只创建一个实例。 |
| 面对多个构造函数参数时考虑使用构建器 | 当类有多个可选参数,如 `Person` 类有姓名、年龄、性别等参数,使用构建器模式可使代码更易读和维护。示例代码如下:
```java
public class Person {
private final String name;
private final int age;
private final String gender;
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.gender = builder.gender;
}
public static class Builder {
private String name;
private int age;
private String gender;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
public Person build() {
return new Person(this);
}
}
}
```
使用方式:
```java
Person person = new Person.Builder()
.name("John")
.age(30)
.gender("Male")
.build();
```
| 使用私有构造函数或枚举类型来实现单例属性 | 单例模式确保类只有一个实例,如使用枚举类型实现单例:
```java
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("Doing something...");
}
}
```
调用方式:`Singleton.INSTANCE.doSomething();` |
| 使用私有构造函数来强制不可实例化 | 对于工具类,如 `Math` 类,使用私有构造函数防止实例化:
```java
public class UtilityClass {
private UtilityClass() {
throw new AssertionError();
}
public static int add(int a, int b) {
return a + b;
}
}
```
| 避免创建不必要的对象 | 可复用对象,如 `String` 类的 `valueOf` 方法,避免每次都创建新的 `String` 对象。 |
| 消除过时的对象引用 | 例如在一个栈类中,弹出元素后及时将引用置为 `null` ,避免内存泄漏:
```java
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // 消除过时引用
return result;
}
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
```
| 避免使用终结器 | 终结器执行时间不确定,可能影响性能,尽量不使用。 |
### 6.2 所有对象通用的方法
以下是重写 `equals`、`hashCode` 和 `toString` 方法的示例:
```java
public class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return x == point.x && y == point.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
", y=" + y +
'}';
}
}
```
`clone` 方法重写需谨慎,以下是一个简单示例:
```java
public class CloneableExample implements Cloneable {
private int value;
public CloneableExample(int value) {
this.value = value;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int getValue() {
return value;
}
}
```
实现 `Comparable` 接口的示例:
```java
public class Student implements Comparable<Student> {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public int compareTo(Student other) {
return Integer.compare(this.score, other.score);
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
}
```
### 6.3 类和接口
#### 访问控制和封装
- 最小化类和成员的可访问性,如将类的成员变量设为 `private` ,并提供公共的访问器方法。
- 在公共类中使用访问器方法而不是公共字段,示例代码如下:
```java
public class Circle {
private double radius;
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
if (radius < 0) {
throw new IllegalArgumentException("Radius cannot be negative");
}
this.radius = radius;
}
}
```
#### 可变性和组合
- 最小化可变性,创建不可变类,如 `String` 类。
- 优先使用组合而不是继承,示例如下:
```java
// 接口
interface Shape {
double area();
}
// 具体类
class Rectangle implements Shape {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public double area() {
return length * width;
}
}
// 组合类
class Square {
private Rectangle rectangle;
public Square(double side) {
this.rectangle = new Rectangle(side, side);
}
public double area() {
return rectangle.area();
}
}
```
#### 接口和类层次结构
- 优先使用接口而不是抽象类,接口可实现多继承,示例如下:
```java
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck is flying");
}
@Override
public void swim() {
System.out.println("Duck is swimming");
}
}
```
- 仅使用接口来定义类型,避免用接口定义常量。
- 优先使用类层次结构而不是标记类,类层次结构更清晰,示例如下:
```java
abstract class Shape {
abstract double area();
}
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
class Triangle extends Shape {
private double base;
private double height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
}
```
#### 函数对象和静态成员类
- 使用函数对象来表示策略,示例如下:
```java
interface Comparator<T> {
int compare(T o1, T o2);
}
class IntegerComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
}
```
- 优先使用静态成员类而不是非静态成员类,静态成员类不依赖外部类实例,示例如下:
```java
class Outer {
static class StaticInner {
public void printMessage() {
System.out.println("This is a static inner class");
}
}
}
```
### 6.4 泛型
以下是泛型的一些示例:
#### 泛型类型
```java
class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
```
#### 泛型方法
```java
public class GenericMethods {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.printf("%s ", element);
}
System.out.println();
}
}
```
#### 有界通配符
```java
import java.util.ArrayList;
import java.util.List;
class Fruit {}
class Apple extends Fruit {}
class Orange extends Fruit {}
public class WildcardExample {
public static void printFruits(List<? extends Fruit> fruits) {
for (Fruit fruit : fruits) {
System.out.println(fruit);
}
}
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
apples.add(new Apple());
printFruits(apples);
List<Orange> oranges = new ArrayList<>();
oranges.add(new Orange());
printFruits(oranges);
}
}
```
#### 类型安全的异构容器
```java
import java.util.HashMap;
import java.util.Map;
class Favorites {
private Map<Class<?>, Object> favorites = new HashMap<>();
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(type, type.cast(instance));
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}
```
### 6.5 枚举和注解
#### 枚举
```java
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
```
使用实例字段的枚举:
```java
enum Planet {
MERCURY(3.303e+23, 2.4397e6),
VENUS(4.869e+24, 6.0518e6),
EARTH(5.976e+24, 6.37814e6);
private final double mass;
private final double radius;
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
public double getMass() {
return mass;
}
public double getRadius() {
return radius;
}
}
```
#### 注解
```java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Test {
}
class MyTestClass {
@Test
public void testMethod() {
System.out.println("This is a test method");
}
}
```
### 6.6 方法
以下是方法相关建议的示例:
#### 参数有效性检查
```java
public class MathUtils {
public static int divide(int dividend, int divisor) {
if (divisor == 0) {
throw new IllegalArgumentException("Divisor cannot be zero");
}
return dividend / divisor;
}
}
```
#### 防御性复制
```java
import java.util.Date;
public class Period {
private final Date start;
private final Date end;
public Period(Date start, Date end) {
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0)
throw new IllegalArgumentException(start + " after " + end);
}
public Date start() {
return new Date(start.getTime());
}
public Date end() {
return new Date(end.getTime());
}
}
```
#### 方法签名设计
方法名和参数应清晰,例如:
```java
public class StringUtils {
public static String concatenate(String str1, String str2) {
return str1 + str2;
}
}
```
#### 重载和可变参数
```java
public class OverloadingExample {
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, int b, int c) {
return a + b + c;
}
public static int add(int... numbers) {
int sum = 0;
for (int num : numbers) {
sum += num;
}
return sum;
}
}
```
#### 返回空数组或集合
```java
import java.util.ArrayList;
import java.util.List;
public class CollectionExample {
public static List<String> getEmptyList() {
return new ArrayList<>();
}
}
```
#### 文档注释
```java
/**
* This class provides utility methods for string manipulation.
*/
public class StringManipulator {
/**
* Concatenates two strings.
*
* @param str1 the first string
* @param str2 the second string
* @return the concatenated string
*/
public static String concatenate(String str1, String str2) {
return str1 + str2;
}
}
```
### 6.7 通用编程
#### 局部变量
最小化局部变量作用域,示例如下:
```java
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// i 在此处不可用
```
#### for - each 循环
```java
import java.util.ArrayList;
import java.util.List;
public class ForEachExample {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
for (String name : names) {
System.out.println(name);
}
}
}
```
#### 使用库
```java
import java.util.Arrays;
public class LibraryExample {
public static void main(String[] args) {
int[] numbers = {3, 1, 4, 1, 5, 9};
Arrays.sort(numbers);
for (int num : numbers) {
System.out.print(num + " ");
}
}
}
```
#### 避免使用 float 和 double
```java
import java.math.BigDecimal;
public class BigDecimalExample {
public static void main(String[] args) {
BigDecimal num1 = new BigDecimal("0.1");
BigDecimal num2 = new BigDecimal("0.2");
BigDecimal sum = num1.add(num2);
System.out.println(sum);
}
}
```
#### 优先使用基本类型
```java
public class PrimitiveVsWrapper {
public static void main(String[] args) {
int a = 10;
Integer b = 20;
int sum = a + b;
System.out.println(sum);
}
}
```
#### 避免使用字符串
在合适的地方使用其他类型,例如使用 `int` 表示年龄。
#### 字符串拼接
```java
public class StringConcatenation {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
String result = sb.toString();
System.out.println(result);
}
}
```
#### 通过接口引用对象
```java
import java.util.ArrayList;
import java.util.List;
public class InterfaceReference {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
}
}
```
#### 优先使用接口而不是反射
```java
interface Shape {
void draw();
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
public class InterfaceVsReflection {
public static void main(String[] args) {
Shape shape = new Circle();
shape.draw();
}
}
```
#### 谨慎使用本地方法
本地方法使用需谨慎,以下是一个简单示例:
```java
public class NativeExample {
static {
System.loadLibrary("NativeExample");
}
public native void nativeMethod();
public static void main(String[] args) {
NativeExample example = new NativeExample();
example.nativeMethod();
}
}
```
#### 谨慎优化
在优化前进行性能分析,可使用工具如 VisualVM 等。
#### 遵循命名约定
类名使用大驼峰,方法名和变量名使用小驼峰,常量名使用全大写,单词间用下划线分隔。
### 6.8 异常
以下是异常处理相关建议的示例:
#### 异常使用场景
```java
public class ExceptionExample {
public static int divide(int dividend, int divisor) {
if (divisor == 0) {
throw new ArithmeticException("Divisor cannot be zero");
}
return dividend / divisor;
}
public static void main(String[] args) {
try {
int result = divide(10, 0);
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
```
#### 受检查异常和运行时异常
```java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class CheckedVsRuntime {
public static void readFile() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("nonexistent.txt");
}
public static void main(String[] args) {
try {
readFile();
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
}
}
}
```
#### 标准异常
```java
public class StandardExceptionExample {
public static int getElement(int[] array, int index) {
if (index < 0 || index >= array.length) {
throw new IndexOutOfBoundsException("Index out of bounds");
}
return array[index];
}
}
```
#### 异常记录和失败捕获信息
```java
import java.io.IOException;
public class ExceptionLogging {
public static void readFile() {
try {
java.io.FileInputStream fis = new java.io.FileInputStream("nonexistent.txt");
} catch (IOException e) {
System.err.println("Failed to read file: " + e.getMessage());
}
}
}
```
### 6.9 并发
以下是并发相关建议的示例:
#### 同步对共享可变数据的访问
```java
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
```
#### 避免过度同步
```java
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FineGrainedLocking {
private final Lock lock = new ReentrantLock();
private int value = 0;
public void increment() {
lock.lock();
try {
value++;
} finally {
lock.unlock();
}
}
public int getValue() {
lock.lock();
try {
return value;
} finally {
lock.unlock();
}
}
}
```
#### 优先使用执行器和任务而不是线程
```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {
System.out.println("Task 1 is running");
});
executor.submit(() -> {
System.out.println("Task 2 is running");
});
executor.shutdown();
}
}
```
#### 优先使用并发工具而不是 wait 和 notify
```java
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(2);
Thread t1 = new Thread(() -> {
System.out.println("Task 1 started");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task 1 completed");
latch.countDown();
});
Thread t2 = new Thread(() -> {
System.out.println("Task 2 started");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task 2 completed");
latch.countDown();
});
t1.start();
t2.start();
latch.await();
System.out.println("All tasks completed");
}
}
```
#### 线程安全性记录
在类的文档注释中说明线程安全性。
#### 延迟初始化
```java
public class LazyInitialization {
private static volatile LazyInitialization instance;
private LazyInitialization() {}
public static LazyInitialization getInstance() {
if (instance == null) {
synchronized (LazyInitialization.class) {
if (instance == null) {
instance = new LazyInitialization();
}
}
}
return instance;
}
}
```
#### 不依赖线程调度器
编写健壮代码,不依赖线程调度的不确定性。
#### 避免使用线程组
线程组使用场景有限,尽量不使用。
### 6.10 序列化
以下是序列化相关建议的示例:
#### 谨慎实现 Serializable 接口
```java
import java.io.Serializable;
class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
```
#### 自定义序列化形式
```java
import java.io.*;
class CustomSerialization implements Serializable {
private int value;
public CustomSerialization(int value) {
this.value = value;
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeInt(value * 2);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
value = in.readInt() / 2;
}
}
```
#### 防御性地编写 readObject 方法
```java
import java.io.*;
class DefensiveReadObject implements Serializable {
private Date start;
private Date end;
public DefensiveReadObject(Date start, Date end) {
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0)
throw new IllegalArgumentException(start + " after " + end);
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
start = new Date(start.getTime());
end = new Date(end.getTime());
if (start.compareTo(end) > 0)
throw new InvalidObjectException(start + " after " + end);
}
}
```
#### 枚举类型用于实例控制
```java
enum SingletonEnum {
INSTANCE;
public void doSomething() {
System.out.println("Doing something...");
}
}
```
#### 序列化代理
```java
import java.io.*;
class SerializationProxyExample implements Serializable {
private final int value;
public SerializationProxyExample(int value) {
this.value = value;
}
private static class SerializationProxy implements Serializable {
private final int value;
SerializationProxy(SerializationProxyExample example) {
this.value = example.value;
}
private Object readResolve() {
return new SerializationProxyExample(value);
}
}
private Object writeReplace() {
return new SerializationProxy(this);
}
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Proxy required");
}
}
```
通过遵循上述这些建议和示例,开发者可以编写出更加高效、可靠和易于维护的 Java 代码,充分发挥 Java 平台的优势,在实际项目中取得更好的效果。
下面是一个 mermaid 流程图,展示了编写高质量 Java 代码的整体流程:
```mermaid
graph LR
A[学习 Java 基础] --> B[掌握关键要素]
B --> C[遵循编写建议]
C --> D[不断实践和优化]
D --> E[编写出高质量代码]
```
0
0
复制全文
相关推荐









