Java编程中的字段、方法及异常处理要点
立即解锁
发布时间: 2025-08-18 02:21:27 阅读量: 2 订阅数: 15 

### Java编程中的字段、方法及异常处理要点
#### 1. 系统引发的参数检查文档记录
在Java编程里,系统引发的参数检查所抛出的运行时异常,应当像显式参数检查那样进行文档记录。无论异常是在方法或构造函数开头的参数检查中显式抛出,还是在方法或构造函数体的后续部分由运行时系统隐式抛出,都属于接口契约的一部分。实际上,记录系统引发的参数检查所抛出的运行时异常更为重要,因为查看源代码时,显式抛出的异常较易发现。
#### 2. 关于常量引用(const References)
在Java中,常量引用的实现主要依靠不可变类型(而非不可变对象)。尽管有人认为Java应像C++那样支持常量参数,但这是不可能实现的。不可变对象在很大程度上是Java对常量引用的解决方案。
##### 2.1 不可变类型的问题与解决方案
使用不可变类型作为常量引用存在一些问题,例如同时拥有类的可变和不可变版本不符合面向对象设计原则。以银行账户为例,其天然接口是可变的,传递类似常量(安全读取)的引用需要一个不包含任何修改方法的单独不可变类型。若不可变类型被声明得与天然接口同等重要甚至更突出,就会破坏良好的面向对象设计。
为解决这个问题,可以将不可变类型设为内部类。这样做的好处是可以访问可变类的私有成员,且不会扭曲类的层次结构。以下是一个示例代码:
```java
class Account {
private long balance;
public Account(long initialDeposit) {
balance = initialDeposit;
}
public synchronized long balance() {
return balance;
}
public synchronized void debit(long amount)
throws InsufficientFundsException {
credit(-amount);
}
public synchronized void credit(long amount)
throws InsufficientFundsException {
if (amount >= 0 || balance >= -amount)
balance += amount;
else
throw new InsufficientFundsException();
}
private ImmutableAccount immutable;
public ImmutableAccount immutable() {
if (immutable == null)
return immutable = new Immutable();
return immutable;
}
private final class Immutable implements ImmutableAccount {
public synchronized long balance() {
return balance;
}
}
}
public interface ImmutableAccount {
long balance();
}
class AccountRecorder { // A logging facility
public void recordBalance(ImmutableAccount a) {
System.out.println(a.balance()); //or record in file
}
}
class AccountHolder {
private Account account = new Account(0);
private AccountRecorder recorder;
public AccountHolder(AccountRecorder r) {
recorder = r;
}
public synchronized void acceptMoney(long amount) {
try {
account.credit(amount);
recorder.recordBalance(account.immutable());
}
catch (InsufficientFundsException e) {
System.out.println("Cannot accept negative amount.");
}
}
}
```
##### 2.2 准修改器(Would - Be Mutators)与不可变内部类(Immutable Inners)
准修改器和不可变内部类密切相关,它们都能为可变对象提供类似常量的引用。准修改器不会实际修改目标对象,而是返回目标对象被修改后的副本;不可变内部类则通过向不可信客户端传递不可变子接口来实现相同功能。选择使用哪种方式的标准是:先尝试使用准修改器,只有在因对大对象进行过多防御性复制而出现性能瓶颈时,再切换到不可变内部类。
#### 3. 防御性复制(Making Defensive Copies)
在Java中,访问权限要么全有要么全无。除非声明为`final`,否则有权访问字段的客户端程序员同时拥有读写权限,不存在只读访问。使用`final`关键字实现只读访问存在问题:对于基本数据类型,会遇到可变内联常量的问题;对于引用类型,`final`仅表示不能为变量分配不同的引用,但如果引用的对象是可变的,仍可使用该引用调用修改方法。
为实现可变对象的只读访问,需要进行更高程度的封装,即进行防御性复制。防御性复制主要有以下三种情况:
- 传入可变对象的引用:在方法调用或类实例创建表达式中传入可变对象时,需要对其进行防御性复制。
- 使用可变对象作为方法调用或类实例创建表达式的参数。
- 返回可变对象的引用。
##### 3.1 多线程应用中的防御性复制
在多线程应用中进行防御性复制时,需要注意“漏洞窗口”问题。例如,以下是一个有问题的`Period`构造函数:
```java
// BROKEN - Permits multithreaded attack!
public Period( Date start, Date end) {
if (start.compareTo( end) > 0)
throw new IllegalArgumentException( start + ">" + end);
// Window of vulnerability
this.start = new Date(start.getTime());
```
0
0
复制全文


