Java8实战-总结7

Java8实战-总结7

  • 通过行为参数化传递代码
    • 真实的例子
      • 用Runnable执行代码块
      • GUI事件处理
    • 小结
  • Lambda表达式
    • Lambda管中窥豹

通过行为参数化传递代码

真实的例子

用Runnable执行代码块

线程就像是轻量级的进程:它们自己执行一个代码块。但是,怎么才能告诉线程要执行哪块代码呢?多个线程可能会运行不同的代码。需要一种方式来代表稍候执行的一段代码。在Java里,可以使用Runnable接口表示一个要执行的代码块。请注意,代码不会返回任何结果(即void):

	// java.lang.Runnable
	public interface Runnable {
		public void run();
	}

可以像下面这样,使用这个接口创建执行不同行为的线程:

	Thread t = new Thread(new Runnable() {
		public void run() {
			System.out.println("Hello world");
		}
	});

Lambda表达式的话,看起来是这样:

	Thread t = new Thread(() -> System.out.println("Hello world"));

GUI事件处理

GUI编程的一个典型模式就是执行一个操作来响应特定事件,如鼠标单击或在文字上悬停。
例如,如果用户单击“发送”按钮,之后显示一个弹出式窗口,或把行为记录在一个文件中。还是需要一种方法来应对变化;需要能够作出任意形式的响应。在JavaFX中,可以使用EventHandler,把它传给setOnAction来表示对事件的响应:

	Button button = new Button("Send");
	button.setOnAction(new EventHandlercActionEvent>() {
		public void handle(ActionEvent event) {
			label.setText("Sent!!");
	});

这里,setOnAction方法的行为就用EventHandler参数化了。用Lambda表达式的话,看起来就是这样:

	button.setOnAction((ActionEvent event) -> label.setText("Sent!!"));

小结

以下是本章中的关键概念。

  • 行为参数化,就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成不同行为的能力。
  • 行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量。
  • 传递代码,就是将新行为作为参数传递给方法。但在Java 8之前这实现起来很啰嗦。为接口声明许多只用一次的实体类而造成的啰嗦代码,在Java 8之前可以用匿名类来减少。
  • Java API包含很多可以用不同行为进行参数化的方法,包括排序、线程和GUI处理。

Lambda表达式

利用行为参数化来传递代码有助于应对不断变化的需求。它允许你定义一个代码块来表示一个行为,然后传递它。你可以决定在某一事件发生时(例如单击一个按钮)或在算法中的某个特定时刻(例如筛选算法中类似于“重量超过150克的苹果”的谓词,或排序中的自定义比较操作)运行该代码块。一般来说,利用这个概念,就可以编写更为灵活且可重复使用的代码了。

但使用匿名类来表示不同的行为并不令人满意:代码十分啰嗦,这会影响程序员在实践中使用行为参数化的积极性。Java 8中提供了解决这个问题的新工具——Lambda表达式。它可以让你很简洁地表示一个行为或传递代码。现在可以把Lambda表达式看作匿名功能,它基本上就是没有声明名称的方法,但和匿名类一样,它也可以作为参数传递给一个方法。

如何构建Lambda,它的使用场合,以及如何利用它使代码更简洁。还有一些新的东西,如类型推断和Java 8 API中重要的新接口。最后,将介绍方法引用(method reference),这是一个常常和Lambda表达式联用的有用的新功能。

Lambda管中窥豹

可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。

  • 匿名——匿名,是因为它不像普通的方法那样有一个明确的名称:写得少而想得多!
  • 函数——说它是函数,是因为Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
  • 传递——Lambda表达式可以作为参数传递给方法或存储在变量中。
  • 简洁——无需像匿名类那样写很多模板代码。

Lambda这个词来自于学术界开发出来的一套用来描述计算的λ演算法。在Java中传递代码十分繁琐和冗长。Lambda解决了这个问题:它可以让你十分简明地传递代码。理论上来说,在Java 8之前做不了的事情,Lambda也做不了。但是,现在用不着再用匿名类写一堆笨重的代码,来体验行为参数化的好处了!Lambda表达式鼓励采用行为参数化风格。最终结果就是你的代码变得更清晰、更灵活。比如,利用Lambda表达式,可以更为简洁地自定义一个Comparator对象。

先前:

Comparator<Apple> byWeight = new Comparator<Apple>() {
	public int compare(Apple a1, Apple a2) {
		return a1.getWeight().compareTo(a2.getWeight());
	}
};

之后(用了Lambda表达式):

Comparator<Apple> byWeight = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

代码看起来更清晰了。现在,请注意,基本上只传递了比较两个苹果重量所真正需要的代码。看起来就像是只传递了compare方法的主体。甚至还可以进一步简化代码。

刚刚展示的Lambda表达式有三个部分,如下图所示:
Java8实战-总结7_第1张图片

  • 参数列表——这里它采用了Comparatorcompare方法的参数,两个Apple
  • 箭头——箭头 -> 把参数列表与Lambda主体分隔开。
  • Lambda主体——比较两个Apple的重量。表达式就是Lambda的返回值了。

为了进一步说明,下面给出了Java 8中五个有效的Lambda表达式的例子。

//第一个Lambda表达式具有一个string类型的参数并返回一个int。Lambda没有return语句,因为已经隐含了return
(String s) -> s.length()
//第二个Lambda表达式有一个Apple类型的参数并返回一个boolean(苹果的重量是否超过150克)
(Apple a) -> a.getWeight() > 150
//第三个Lambda表达式具有两个int类型的参一数而没有返回值(void返回)。注意Lambda表达式可以包含多行语句,这里是两行
(int x, int y) -> {
	System.out.println("Result:");
	System.out.println(x + y);
}
//第四个Lambda表达式没有参数,返回一个int
() -> 42
//第五个Lambda表达式具有两个apple类型的参数,返回一个int:比较两个Apple的重量
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight ())

Java语言设计者选择这样的语法,是因为C#Scala等语言中的类似功能广受欢迎。Lambda的基本语法是

(parameters) -> expression

或(请注意语句的花括号)

(parameters) -> { statements;}

可以看到,Lambda表达式的语法很简单。

Lambda语法测验
根据上述语法规则,以下哪个不是有效的Lambda表达式?
(1)() -> {}
(2)() -> "Raoul"
(3)() -> {return "Mario";}
(4)(Integer i) -> return "Alan"+ i;
(5)(String s) -> {"IronMan";}
答案:只有45是无效的Lambda(1)这个Lambda没有参数,并返回void。它类似于主体为空的方法:public void run() {}(2)这个Lambda没有参数,并返回String作为表达式。
(3)这个Lambda没有参数,并返回String(利用显式返回语句)(4) return是一个控制流语句。要使此Lambda有效,需要使花括号,如下所示:(Integer i) -> {return "Alan"+ i;}(5)IronMan”是一个表达式,不是一个语句。要使此Lambda有效,你可以去除花括号和分号,如下所示:(String s) -> "IronMan"。或者使用显式返回语句,如下所示:(String s) -> {return "IronMan";}

一些Lambda的例子和使用案例:
Java8实战-总结7_第2张图片

你可能感兴趣的:(java,开发语言)