Java编程中的标记接口、Lambda表达式与方法引用
立即解锁
发布时间: 2025-08-18 00:29:01 阅读量: 12 订阅数: 21 


Effective Java:编写高效Java代码的最佳实践
# Java编程中的标记接口、Lambda表达式与方法引用
## 1. 标记接口与标记注解
### 1.1 标记接口的定义
标记接口是一种不包含任何方法声明的接口,它的作用仅仅是标记实现该接口的类具有某种属性。例如,`Serializable` 接口,一个类实现了这个接口,就表明它的实例可以被写入 `ObjectOutputStream` 进行序列化。
### 1.2 标记接口与标记注解的比较
#### 1.2.1 标记接口的优势
- **定义类型**:标记接口定义了一个类型,标记类的实例会实现这个类型。这使得在编译时就能捕获一些错误,而使用标记注解则要到运行时才能发现。例如,Java 的序列化机制使用 `Serializable` 标记接口来表明一个类型是可序列化的。如果 `ObjectOutputStream.writeObject` 方法的参数类型是 `Serializable`,那么尝试序列化一个不适合的对象时,编译时就能通过类型检查发现错误。但实际上该方法的参数声明为 `Object` 类型,所以序列化不可序列化对象的错误要到运行时才会出现。
- **更精确的目标定位**:标记接口可以更精确地定位目标。如果一个注解类型的目标是 `ElementType.TYPE`,它可以应用于任何类或接口。但如果一个标记只适用于某个特定接口的实现,将其定义为标记接口,让它扩展该特定接口,就能保证所有标记类型也是该特定接口的子类型。例如,`Set` 接口可以看作是一个受限的标记接口,它只适用于 `Collection` 的子类型,且除了 `Collection` 定义的方法外没有添加新方法。
#### 1.2.2 标记注解的优势
标记注解是更大的注解工具的一部分,因此能在基于注解的框架中保证一致性。
### 1.3 选择标记注解还是标记接口
- 如果标记要应用于类或接口之外的程序元素,必须使用注解,因为只有类和接口才能实现或扩展接口。
- 如果标记只应用于类和接口,问自己是否想编写一个或多个只接受带有此标记的对象的方法。如果是,优先使用标记接口,这样可以将接口作为方法的参数类型,实现编译时类型检查。
- 如果确定永远不会编写只接受带有此标记的对象的方法,那么使用标记注解可能更好。如果标记是一个大量使用注解的框架的一部分,标记注解是明确的选择。
## 2. Lambda 表达式与匿名类
### 2.1 匿名类的使用
历史上,具有单个抽象方法的接口(或很少情况下的抽象类)被用作函数类型,其实例称为函数对象,代表函数或动作。自 1997 年 JDK 1.1 发布以来,创建函数对象的主要方式是匿名类。例如,使用匿名类创建排序比较函数对字符串列表按长度排序:
```java
// Anonymous class instance as a function object - obsolete!
Collections.sort(words, new Comparator<String>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
```
### 2.2 Lambda 表达式的引入
在 Java 8 中,语言将具有单个抽象方法的接口正式定义为特殊的功能接口,并允许使用 Lambda 表达式创建这些接口的实例。Lambda 表达式与匿名类功能相似,但更简洁。上述代码用 Lambda 表达式替换匿名类后如下:
```java
// Lambda expression as function object (replaces anonymous class)
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
```
### 2.3 Lambda 表达式的类型推断
Lambda 表达式的类型、参数类型和返回值类型通常由编译器根据上下文推断得出。但在某些情况下,编译器无法确定类型,需要手动指定。同时,使用 Lambda 表达式时,要遵循不使用原始类型、优先使用泛型类型和泛型方法的建议,因为编译器进行类型推断的大部分类型信息来自泛型。例如,如果 `words` 变量声明为原始类型 `List` 而不是参数化类型 `List<String>`,上述代码将无法编译。
### 2.4 Lambda 表达式在枚举中的应用
在枚举类型中,使用 Lambda 表达式可以更简单地实现特定常量的行为。例如,对于 `Operation` 枚举类型,原本使用常量特定类体和重写 `apply` 方法的代码如下:
```java
// Enum type with constant-specific class bodies & data
public enum Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
},
TIMES("*") {
public double apply(double x, double y) { return x * y; }
},
DIVIDE("/
```
0
0
复制全文
相关推荐









