Java-Web-开发学习手册-六-

118 阅读11分钟

Java Web 开发学习手册(六)

原文:Learn Java for Web Development

协议:CC BY-NC-SA 4.0

十一、附录 C:Scala 简介

Scala 无缝集成了面向对象和函数式编程。Scala 是一种静态类型语言,由 Martin Odersky 于 2001 年提出,他也是 Java 参考编译器的作者和 Java 泛型的合著者。Scala 为 Java 虚拟机(JVM)编译成字节码,使其与平台无关。这也意味着从 Scala 程序中你可以使用现有的 Java 库,反之亦然。

Scala 入门

你可以从 www.scala-lang.org/download/下载 Scala。这个 Scala 软件发行版可以安装在任何类似 Unix 或 Windows 的系统上。它需要 Java 运行时版本 1.6 或更高版本。

>scala  -version
Scala code runner version 2.10.3 -- Copyright 2002-2013, LAMP/EPFL

有三种方法可以执行 Scala 代码。

  • 使用交互式解释器
  • 将 Scala 代码作为脚本执行
  • 编译 Scala 代码

使用交互式解释器

Scala 解释器(称为读取-评估-打印循环,或 REPL )是执行一行 Scala 代码最简单的方法。您可以使用 scala 命令行工具 Scala 启动交互式解释器,该工具位于 Scala 安装文件夹的 bin 文件夹中。

从命令行输入以下内容,打开交互式解释器,如图 C-1 所示。

>scala

9781430259831_AppC-01.jpg

图 C-1 。Scala 交互式解释器

使用交互式解释器,您可以通过使用 println 方法运行您的第一个“Hello world”程序。

scala> println("Hello world");
Hello world

要退出解释器,请键入 exit。

scala> exit

将 Scala 代码作为脚本执行

另一种执行 scala 代码的方式是将其输入到一个文本文件中,并用扩展名. Scala 保存。然后,您可以通过键入 filename .scala 来执行该代码。例如,您可以创建一个名为 hello.scala 的文件,其中包含“Hello world”。

println("Hello world")

要执行它,需要将文件名指定为 Scala 命令行工具的参数。

>scala  hello.scala

编译 Scala 代码

您也可以通过首先使用 scalac 命令行工具编译 Scala 代码来执行它。然后代码将需要在应用的上下文中执行,因此您将需要添加一个带有 main()方法的对象(参见清单 C-1 )。

列表 C-1 。“你好,世界”节目

1.    object HelloWorld {
2.    def main(args: Array[String]) {
3.    println("Hello, world")
4.       }
5.    }

注意语句末尾的分号通常是可选的。

  • 第 1 行:main()方法是在对象中定义的,而不是在类中。Scala 有一个对象构造,你可以用它来声明一个单例对象。在本附录的后面,您将了解更多关于单例的内容。
  • 第二行 : Scala 程序处理从 main()方法开始,这是每一个 Scala 程序必不可少的一部分。main()方法未标记为 static。在 Scala 中,一切都是对象。main()方法是自动实例化的 singleton 对象上的实例方法。
  • 第 2 行:没有返回类型。其实是有 Unit 的,和 void 差不多,不过是编译器推断出来的。您可以通过在参数后加上冒号和类型来显式指定返回类型。
def main(args: Array[String]) : Unit = {
                       }
  • 第 2 行:Scala 中没有访问级修饰符。在这个上下文中,Java 中有一个 public 修饰符,但是 Scala 没有指定 public 修饰符,因为默认的访问级别是 public。
  • 第 2 行 : Scala 使用 def 关键字告诉编译器这是一个方法。

将清单 C-1 中的代码保存在名为 HelloWorld.scala 的文件中,并使用以下命令编译代码:

>scalac HelloWorld.scala

现在使用以下命令运行程序:

>scala HelloWorld
Hello, World!

注意 Java 要求你把一个公共类放在一个以该类命名的文件中。例如,您应该将类 HelloWorld 放在 HelloWorld.java 文件中。在 Scala 中,你可以命名。scala 可以保存你想要的任何东西,不管你在里面放了什么 Scala 类或者代码。但是,建议您像在 Java 中一样,根据文件包含的类来命名文件,以便根据文件名轻松定位类。

变量

Scala 允许你在声明一个变量时决定它是否是不可变的(只读的)。不可变变量是用关键字 val 声明的。这意味着它是一个不可改变的变量。清单 C-2 展示了创建一个不可变的变量,而图 C-2 展示了当你试图改变它时会发生什么。

列表 C-2 。不可变变量

val immutableVar : String = "Hello"
immutableVar = "Hi"

9781430259831_AppC-02.jpg

图 C-2 。尝试更改 val 时出错

清单 C-3 展示了创建一个可变变量,而图 C-3 展示了它被成功改变。

列表 C-3 。可变变量

var mutableVar = "Hello"
mutableVar = "Hi"

9781430259831_AppC-03.jpg

图 C-3 。var 更改成功

当你给一个变量赋一个初始值时,Scala 编译器可以根据赋给它的值推断出变量的类型。这被称为类型推理,如清单 C-4 所示。

清单 C-4 。类型推理

var  var1= 10
var var2 = "Hello world"

在清单 C-4 中,Scala 将推断 var1 为 Int 类型,var2 为 String 类型变量。

收集

Scala 集合区分可变和不可变集合。可变集合可以就地更新或扩展。这意味着你可以更改、添加或删除收藏的元素。相比之下,不可变集合永远不会改变。您仍然有模拟添加、删除或更新的操作,但是这些操作在每种情况下都将返回一个新集合,而旧集合保持不变。Scala 有一个丰富的集合库。最常用的集合是列表、集合和映射,这些将在下面的章节中介绍。你可以在docs . Scala-lang . org/overviews/collections/introduction . html找到关于 Scala 收藏库的详细信息。

列表

列表是不可变的,这意味着列表的元素不能通过赋值来改变。包含 T 类型元素的列表类型被写成 List[T],如下所示:

val numberList: List[Integer] = List(1, 2, 3)

清单 C-5 展示了如何创建和使用一个不可变列表。

清单 C-5 。创建不可变列表

val list = List(1, 2, 3, 2, 3)
println (list.head)
println(list.tail)
println(list.length)
println(list.max)
println(list.min)
println(list.sum)
println(list.sorted)
println(list.reverse)
head   --- 1

tail   --- List(2, 3, 2, 3)

length --- 5

max    --- 3

min    --- 1

sum    --- 11

sorted --- List(1, 2, 2, 3, 3)

reverse--- List(3, 2, 3, 2, 1)

Scala 只定义了一个不可变的列表。但是,它也定义了一些可变的列表类型,比如 ArrayBuffer。清单 C-6 展示了如何创建一个可变列表。

清单 C-6 。创建可变列表

import collection.mutable
val list = mutable.ArrayBuffer(1, 2, 3, 2, 3)
assert (list.length  == 5)

设置

集合是不包含重复元素的集合。有两种集合,不可变的和可变的。清单 C-7 展示了如何创建一个不可变的集合。

清单 C-7 。创建不可变集合

val set = Set(1, 2, 3, 2, 3)
println ("head -- "+set.head)
println("tail -- "+set.tail)
println("size -- "+set.size)
println("sum  -- "+set.sum)
head -- 1

tail -- Set(2, 3)

size -- 3

sum  -- 6

默认情况下,Scala 使用不可变集合。如果你想使用可变集合,你必须导入 scala.collection.mutable.Set。

清单 C-8 。创建可变集合

import collection.mutable
val set = mutable.HashSet(1, 2, 3, 2, 3)
assert (set.size == 3)

地图

Scala map 是键值对的集合。默认情况下,Scala 使用不可变的 map。如果想使用可变映射,就必须显式导入 scala.collection.mutable.Map 类。清单 C-9 展示了如何创建和使用一个不可变的地图。

清单 C-9 。创建不可变的地图

val map = Map("1" -> 1, "2" -> 2, "3" -> 3, "2" -> 2, "3" -> 3)

println ("head  -- "+map.head)
println("tail  -- "+map.tail)
println("size  -- "+map.size)
head  -- (1,1)

tail  -- Map(2 -> 2, 3 -> 3)

size  -- 3

类别

Scala 中的类的声明非常像 Java 类。一个区别是 Scala 类可以有参数,如清单 C-10 中的所示。

列出 C-10 。带参数的 Scala 类

class Vehicle (speed : Int){
val mph :Int = speed
    def race() = println("Racing")
}

车辆类接受一个参数,即车辆的速度。创建 Vehicle 类的实例时,必须传递该参数,如下所示:new Vehicle(100)。该类包含一个名为 race()的方法。

扩展一个类

在 Scala 中覆盖从超类继承的方法是可能的,如清单 C-11 中的所示。

列出 C-11 。扩展一个 Scala 类

1.    class Car (speed : Int) extends Vehicle(speed) {
2.    override val mph: Int= speed
3.    override  def race() = println("Racing Car")
4.    }
  • 第 1 行:Car 类使用关键字 extends 扩展了 Vehicle 类。
  • 第 2 行到第 3 行:字段 mph 和方法 race()需要使用关键字 override 来覆盖。

清单 C-12 展示了另一个叫做 Bike 的类,它扩展了 Vehicle。

清单 C-12 。扩展一个 Scala 类

class Vehicle (speed : Int){
val mph :Int = speed
    def race() = println("Racing")
}
class Car (speed : Int) extends Vehicle(speed) {
override val mph: Int= speed
override  def race() = println("Racing Car")

}
class Bike(speed : Int) extends Vehicle(speed) {
override val mph: Int = speed
override  def race() = println("Racing Bike")

}

将清单 C-12 保存在 vehicle.scala 文件中,并使用以下代码进行编译:

>scalac vehicle.scala

现在您可以使用 scala 命令进入 REPL 并创建 vehicle 对象,如下所示:

scala> val vehicle1 = new Car(200)

使用这个命令,Scala 创建了 vehicle1 对象,如下所示:

vehicle1: Car = Car@19a8942

现在,您可以使用 Scala 创建的 vehicle1 对象来访问汽车的速度。

scala> vehicle1.mph

斯卡拉 REPL 发出汽车的速度,如下所示:

res1: Int = 200

以类似的方式,您可以执行 vehicle1 的 race()方法,如下所示:

scala>vehicle1.race()

Scala 解释器发出输出,如下所示:

Racing Car

现在您可以创建 Bike 对象并访问它的属性和方法,如下所示:

scala> val vehicle2 = new Bike(100)
vehicle2: Bike = Bike@b7ad3
scala>vehicle2.mph
res4: Int = 100
scala> vehicle2.race()
Racing Bike

特征

假设您想在车辆层次结构中添加另一个类。这一次你要添加一个蝙蝠战车。蝙蝠战车可以赛跑、滑行和飞行。但是你不能在 Vehicle 类中添加 glide 和 fly 方法,因为在一个非冲突的世界中,汽车和自行车不能滑行或飞行。至少现在还没有。所以,如果你想把蝙蝠战车添加到你的车辆等级中,你可以使用一个特征。特性就像 Java 中的接口,也可以包含代码。在 Scala 中,当一个类从 trait 继承时,它实现了 trait 的接口,并继承了 trait 中包含的所有代码。清单 C-13 展示飞行和滑翔特性。

清单 C-13 。Scala 特征

trait flying {
    def fly() = println("flying")
}

trait gliding {
def gliding() = println("gliding")
}

现在你可以创建蝙蝠战车类来扩展飞行器类以及飞行和滑翔特性,如清单 C-14 中的所示。

清单 C-14 。使用特征

1.    Batmobile(speed : Int) extends Vehicle(speed)  with flying with gliding{
2.    override val mph: Int = speed
3.    override  def race() = println("Racing Batmobile")
4.    override def fly() = println("Flying Batmobile")
5.    override def glide() = println("Gliding Batmobile")
6.
7.    }

现在,您可以在 REPL 创建一辆蝙蝠战车,如下图所示:

scala> val vehicle3 = new Batmobile(300)
vehicle3: Batmobile = Batmobile@374ed5

现在您可以访问 Batmobile 的 fly()方法,如下所示:

scala> vehicle3.fly()
Flying Batmobile

创建一个车辆列表,然后可以使用 Scala collections 库提供的 maxBy()方法来查找列表中最快的车辆。

scala> val vehicleList = List(vehicle1, vehicle2, vehicle3)
vehicleList: List[Vehicle] = List(Car@562791, Bike@e80317, Batmobile@374ed5)
scala> val fastestVehicle = vehicleList.maxBy(_.mph)
fastestVehicle: Vehicle = Batmobile@374ed5

单一对象

Scala 没有静态成员。相反,Scala 有单例对象。单例对象定义看起来像一个类定义,除了你使用关键字对象代替关键字类。singleton 是一个只能有一个实例的类。清单 C-15 展示了如何在应用中使用单例对象。

清单 C-15 。在应用中使用单例对象

1.    class Vehicle (speed : Int){
2.    val mph :Int = speed
3.    def race() = println("Racing")
4.    }
5.    class Car (speed : Int) extends Vehicle(speed) {
6.    override val mph: Int= speed
7.    override  def race() = println("Racing Car")
8.
9.    }
10.    class Bike(speed : Int) extends Vehicle(speed) {
11.    override val mph: Int = speed
12.    override  def race() = println("Racing Bike")
13.
14.    }
15.    trait flying {
16.    def fly() = println("flying")
17.    }
18.
19.    trait gliding {
20.    def glide() = println("gliding")
21.    }
22.
23.    class Batmobile(speed : Int) extends Vehicle(speed)  with flying with gliding{
24.    override val mph: Int = speed
25.    override  def race() = println("Racing Batmobile")
26.    override def fly() = println("Flying Batmobile")
27.    override def glide() = println("Gliding Batmobile")
28.
29.    }
30.    object Vehicle {
31.    def main(args: Array[String]) {
32.    val vehicle1 = new Car(200)
33.    val vehicle2 = new Bike(100)
34.    val vehicle3 = new Batmobile(300)
35.
36.    val vehicleList = List(vehicle1, vehicle2, vehicle3)
37.    val fastestVehicle = vehicleList.maxBy(_.mph)
38.
39.    printVehicle
40.
41.    def printVehicle{
42.    println ("speed of Bike : " + vehicle1.mph);
43.    println ("speed of Car : " + vehicle2.mph);
44.    println ("speed of Batmobile : " + vehicle3.mph);
45.    println ("Fastest Vehicle : " + fastestVehicle.mph + " mph");
46.
47.         }
48.      }
49.    }

当编译并执行前面的代码时,它会产生以下结果:

>scalac vehicle.scala
>scala Vehicle
speed of Bike : 200 mph

speed of Car : 100 mph

speed of Batmobile : 300 mph

Fastest Vehicle : 300 mph

摘要

本附录向您介绍了 Scala 的基础知识。您学习了三种交互执行 Scala 代码的方式,一种是作为脚本执行,另一种是作为编译程序执行。然后您学习了如何使用 Scala collections 库。最后,您学习了如何使用 traits 以及如何在应用中使用 singleton 对象。