多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 新旧对比 通常,传递给方法的数据不同,结果不同。如果我们希望方法在调用时行为不同,该怎么做呢?结论是:只要能将代码传递给方法,我们就可以控制它的行为。此前,我们通过在方法中创建包含所需行为的对象,然后将该对象传递给我们想要控制的方法来完成此操作。下面我们用传统形式和 Java 8 的方法引用、Lambda 表达式分别演示。代码示例: ~~~java // functional/Strategize.java interface Strategy { String approach(String msg); } class Soft implements Strategy { public String approach(String msg) { return msg.toLowerCase() + "?"; } } class Unrelated { static String twice(String msg) { return msg + " " + msg; } } public class Strategize { Strategy strategy; String msg; Strategize(String msg) { strategy = new Soft(); // [1] this.msg = msg; } void communicate() { System.out.println(strategy.approach(msg)); } void changeStrategy(Strategy strategy) { this.strategy = strategy; } public static void main(String[] args) { Strategy[] strategies = { new Strategy() { // [2] public String approach(String msg) { return msg.toUpperCase() + "!"; } }, msg -> msg.substring(0, 5), // [3] Unrelated::twice // [4] }; Strategize s = new Strategize("Hello there"); s.communicate(); for(Strategy newStrategy : strategies) { s.changeStrategy(newStrategy); // [5] s.communicate(); // [6] } } } ~~~ 输出结果: ~~~ hello there? HELLO THERE! Hello Hello there Hello there ~~~ **Strategy**接口提供了单一的`approach()`方法来承载函数式功能。通过创建不同的**Strategy**对象,我们可以创建不同的行为。 我们一般通过创建一个实现**Strategy**接口的类来实现这种行为,正如在**Soft**里所做的。 * **\[1\]**在**Strategize**中,你可以看到**Soft**作为默认策略,在构造函数中赋值。 * **\[2\]**一种较为简洁且更加自然的方法是创建一个**匿名内部类**。即便如此,仍有相当数量的冗余代码。你总需要仔细观察后才会发现:“哦,我明白了,原来这里使用了匿名内部类。” * **\[3\]**Java 8 的 Lambda 表达式,其参数和函数体被箭头`->`分隔开。箭头右侧是从 Lambda 返回的表达式。它与单独定义类和采用匿名内部类是等价的,但代码少得多。 * **\[4\]**Java 8 的**方法引用**,它以`::`为特征。`::`的左边是类或对象的名称,`::`的右边是方法的名称,但是没有参数列表。 * **\[5\]**在使用默认的**Soft**策略之后,我们逐步遍历数组中的所有**Strategy**,并通过调用`changeStrategy()`方法将每个**Strategy**传入变量`s`中。 * **\[6\]**现在,每次调用`communicate()`都会产生不同的行为,具体取决于此刻正在使用的策略**代码对象**。我们传递的是行为,而并不仅仅是数据。\[^3\] 在 Java 8 之前,我们能够通过**\[1\]**和**\[2\]**的方式传递功能。然而,这种语法的读写非常笨拙,并且我们别无选择。方法引用和 Lambda 表达式的出现让我们可以在需要时**传递功能**,而不是仅在必要时才这么做。