从原生的Java API
创建线程谈起,讲述Scala
对「控制结构」抽象的设计与实现.
创建线程
在Java8
之前,创建一个线程的典型方法如下。
Thread t = new Thread(new Runnable() {
@Override
public void run() {
...
}
});
t.start();
使用Java8
使用Java8
,可以除去一部分冗余的语法噪声,表达力得到了提升。
Thread t = new Thread(() -> {
...
});
t.start();
使用Scala
尝试使用Scala
,对Java
的接口进行包装处理,可以得到更加人性化的接口。首先定义runnable
的控制结构:
def runnable(callback: => Unit) = new Runnable {
override def run() = callback
}
然后,定义thread
的关键字,实现Thread
的创建。
def thread(callback: Unit) = new Thread(runnable(callback))
用户API
也变得更加简洁,其感觉形如if, while
等内置的控制结构,表达力非常强。
thread {
...
}
多样化
上例创建的是匿名的线程,如果想创建有名线程,并将其设置为Daemon
线程,可以如下设计。
daemon("daemon-service-1") {
...
}
可以如下实现:
def daemon(name: String)(callback: => Unit): Thread = {
val t = new Thread(runnable(callback), name)
t.setDaemon(true)
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler {
override def uncaughtException(t: Thread, e: Throwable) =
error(s"Uncaught exception in ${t.getName}:${e.toString}")
})
t
}
t.setUncaughtExceptionHandler
的入参有点复杂,可以通过「提取函数」改善表达力。
def daemon(name: String)(callback: => Unit): Thread = {
val t = new Thread(runnable(callback), name)
t.setDaemon(true)
t.setUncaughtExceptionHandler(handler)
t
}
private def handler = new Thread.UncaughtExceptionHandler {
override def uncaughtException(t: Thread, e: Throwable) =
error(s"Uncaught exception in ${thread.getName}:${e.toString}")
}
接下来,以此类推,可以提取「抽象结构」,改善程序的表现力。
private def handler = onException { (thread, except) =>
error(s"Uncaught exception in ${thread.getName}:${except.toString}")
}
private def onException(h: (Thread, Throwable) => Unit) =
new Thread.UncaughtExceptionHandler {
override def uncaughtException(t: Thread, e: Throwable): Unit = h(t, e)
}
也就是说,onException
和runnable, thread, daemon
一样,是对Java
接口的修饰或隐藏。
总结
Scala
是设计DSL
的利器。
借助于柯里化,及其漂亮的大括号语法,使得Scala
创建自定义的「控制结构」变得非常容易;同时可以有效地除去冗余的语法噪声,提升代码的可读性。
网友评论