1. 特点:
- Scala是一门多范式编程语言,集成了面向对象编程和函数式编程等多种特性。
- Scala运行在虚拟机上,并兼容现有的Java程序。
- Scala源代码被编译成java字节码,所以运行在JVM上,并可以调用现有的Java类库。
- Scala和Java最大的区别是:Scala语句末尾的分号(;)是可选的!
- Scala编译运行:
先编译:scalac HelloScala.scala 将会生成两个文件:HelloScala$.class和HelloScala.class
再运行:scala HelloScala
输出结果:hello scala!!!
2. Scala基本语法
- 区分大小写
- 类名首字母大写驼峰形式(MyFirstScalaClass)
- 方法名称首字母小写驼峰形式(myMethodName())
- 程序文件名应该与对象名称完全匹配
- def main(args:Array[String]):scala程序从main方法开始处理,程序的入口。
- Scala注释:分为多行/**/和单行//
- 换行符:Scala是面向行的语言,语句可以用分号(;)结束或换行符(println())
- 定义包有两种方法:
1、package com.ahu
class HelloScala
2、package com.ahu{
class HelloScala
}
- 引用:import java.awt.Color
如果想要引入包中的几个成员,可以用selector(选取器):
import java.awt.{Color,Font}
// 重命名成员
import java.util.{HashMap => JavaHashMap}
// 隐藏成员 默认情况下,Scala 总会引入 java.lang._ 、 scala._ 和 Predef._,所以在使用时都是省去scala.的
import java.util.{HashMap => _, _} //引入了util包所有成员,但HashMap被隐藏了
3. 数据类型
Scala与Java有着相同的数据类型,下面列出一些Scala有的数据类型。
- Unit:表示无值,和其他语言的void一样。
- Null:null或空引用。
- Nothing:是Scala的类层级的最低端,是任何其他类型的子类型。
- Any:是所有其他类的超类。
- AnyRef:是Scala所有引用类的基类。
- 多行字符串的表示方法:
val foo ="""第一行
第二行
第三行"""
4. 变量
- 在Scala中,使用关键字“var”声明变量,使用关键字“val”声明常量。
var myVar1 : String = "foo"
var myVar2 : Int
val myVal = "Hello,Scala!"
- Scala多个变量声明:
val xmax, ymax = 100 // xmax,ymax都声明为100
5. 访问修饰符
Scala访问修饰符和Java基本一样,分别有private、protected、public。
默认情况下,Scala对象的访问级别是public。
- 私有成员:用private关键字修饰的成员仅在包含了成员定义的类或对象内部可见。
class Outer{
class Inner{
private def f(){println("f")}
class InnerMost{
f() // 正确
}
(new Inner).f() // 错误
}
}
- 保护成员:Scala比Java中更严格。只允许保护成员在定义了该成员的类的子类中被访问。
package p{
class Super{
protected def f() {println("f")}
}
class Sub extends Super{
f()
}
class Other{
(new Super).f() // 错误
}
}
- 公共成员:默认public,这样的成员在任何地方都可以被访问。
class Outer{
class Inner{
def f(){println("f")}
class InnerMost{
f() // 正确
}
}
(new Inner).f() // 正确
}
- 作用域保护:Scala中,访问修饰符可以通过使用限定词强调。
- private[x] 或者 protected[x]
- private[x]:这个成员除了对[...]中的类或[...]中的包中的类及他们的伴生对象可见外,对其他的类都是private。
5. 运算符
Scala运算符:和Java一样,这里就不再浪费时间一一介绍了。
算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符。
- Scala if...else语句:和Java一样
- Scala循环:和Java一样。while循环、do...while循环、for循环
6. Scala方法与函数
- Scala 有方法与函数,二者在语义上的区别很小。
- Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。
- Scala 中的方法跟 Java 的类似,方法是组成类的一部分。
- Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。
- Scala 中使用 val 语句可以定义函数,def 语句定义方法。
用一个例子来说明函数的定义和函数调用。
class Test{
def m(x: Int) = x + 3
val f = (x: Int) => x + 3
}
注意:有些翻译上函数(function)与方法(method)是没有区别的。
- 方法的声明
Scala 方法声明格式如下:
def functionName ([参数列表]) : [return type]
如果你不写等于号和方法主体,那么方法会被隐式声明为抽象(abstract),包含它的类型于是也是一个抽象类型。
- 方法的定义
方法定义由一个 def 关键字开始,紧接着是可选的参数列表,一个冒号 : 和方法的返回类型,一个等于号 = ,最后是方法的主体。
Scala 方法定义格式如下:
def functionName ([参数列表]) : [return type] = {
function body
return [expr]
}
以上代码中 return type 可以是任意合法的 Scala 数据类型。参数列表中的参数可以使用逗号分隔。
以下方法的功能是将两个传入的参数相加并求和:
object add{
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
如果方法没有返回值,可以返回为 Unit,这个类似于 Java 的 void, 实例如下:
object Hello{
def printMe( ) : Unit = {
println("Hello, Scala!")
}
}
- 方法调用
Scala 提供了多种不同的方法调用方式:
以下是调用方法的标准格式:
functionName( 参数列表 )
如果方法使用了实例的对象来调用,我们可以使用类似java的格式 (使用 . 号):
[instance.]functionName( 参数列表 )
以下实例演示了定义与调用方法的实例:
object Test {
def main(args: Array[String]) {
println( "Returned Value : " + addInt(5,7) );
}
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
7. Scala闭包:
闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
例子:
object Test{
def main(args: Array[String]){
println("muliplier(1) value = " + muliplier(1))
println("muliplier(2) value = " + muliplier(2))
}
var factor = 3 // 定义在函数外的自由变量
val muliplier = (i:Int) => i * factor // muliplier函数变量就是一个闭包
}
输出结果:
muliplier(1) value = 3
muliplier(2) value = 6
在 multiplier 中有两个变量:i 和 factor。其中的一个 i 是函数的形式参数,在 multiplier 函数被调用时,i 被赋予一个新的值。然而,factor不是形式参数,而是自由变量,
这里我们引入一个自由变量 factor,这个变量定义在函数外面。
这样定义的函数变量 multiplier 成为一个"闭包",因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。
8. Scala字符串
Scala中可以创建两中字符串:一种是不可修改的,一种是可以修改的。
- 创建不可修改的字符串
val greeting:String = "Hello World!";
- 创建可以修改的字符串
object Test{
def main(args: Array[String]){
val buf = new StringBuilder;
buf += 'a' // 添加一个字符
buf ++= "bcdef" // 添加一个字符串
println(buf.toString); // 输出:abcdef
}
}
- 字符串长度:xxx.length()
- 字符串连接:可以用concat()方法或者用加号
object Test {
def main(args: Array[String]) {
var str1 = "字符串1:";
var str2 = "字符串2";
var str3 = "字符串3:";
var str4 = "字符串4";
println( str1 + str2 ); // 字符串1:字符串2
println( str3.concat(str4) ); // 字符串3:字符串4
}
}
- 创建格式化字符串:
String类中可以使用printf()方法来格式化字符串并输出。
object Test{
def main(args:Array[String]){
var floatVar = 12.456
var intVar = 2000
var stringVar = "字符串变量"
var fs = printf("浮点型变量为 " +
"%f,整形变量为 %d, 字符串为 " +
"%s", floatVar, intVar, stringVar)
println(fs) // 浮点型变量为 12.456000, 整型变量为 2000, 字符串为 字符串变量
}
}
9. Scala数组
- 声明数组
//第一种
var z:Array[String] = new Array[String](3);
//第二种
var z = new Array[String](3);
//赋值
z(0)= "value1";
z(1) = "value2";
z(2) = "value3";
//第三种
var z = Array("value1","value2","value3");
- 处理数组
object Test {
def main(args: Array[String]): Unit = {
var myList = Array(1.1,2.2,3.3,4.4);
//输出所有元素
for(x <- myList){
println(x);
}
//计算数组所有元素的总和
var total = 0.0;
for(i <- 0 to (myList.length-1)){
total += myList(i);
}
println("total: "+total)
//查找数组中的最大值
var max = myList(0);
for(i <- 0 to (myList.length-1)){
if(myList(i) > max){
max = myList(i);
}
}
println("max: " + max)
}
}
- 多维数组
import Array._
object Test {
def main(args: Array[String]): Unit = {
//定义数组
val myMatrix = ofDim[Int](3,3);
//创建矩阵
for(i <- 0 to 2){
for(j <- 0 to 2){
myMatrix(i)(j) = j;
}
}
//打印矩阵
for(i <- 0 to 2){
for(j <- 0 to 2){
print(" " + myMatrix(i)(j));
}
println();
}
}
}
结果:- 合并数组
import Array._
object Test {
def main(args: Array[String]): Unit = {
var myList1 = Array(1.1, 2.2, 3.3, 4.4)
var myList2 = Array(5.5, 6.6, 7.7, 8.8)
// 使用concat()合并
var myList3 = concat(myList1, myList2)
// 输出所有数组元素
for (x <- myList3) {
println(x)
}
}
}
结果:- 创建区间数组:使用range(x,y,z)创建区间数组,数值范围大于等于x,小于y。z表示步长,默认为1。
import Array._
object Test {
def main(args: Array[String]): Unit = {
var myList1 = range(10,20,2);
var myList2 = range(10,20);
for (x <- myList1) {
print(" " + x)
}
println(); //输出:10 12 14 16 18
for(x <- myList2){
print(" " + x); //输出:10 11 12 13 14 15 16 17 18 19
}
}
}
10. Scala集合
Scala集合分为可变集合和不可变集合
可变集合:可以在适当的时候扩展或更新,也就是可以修改、添加、移除集合元素。
不可变集合:永远不可改变。但可以模拟添加、移除、更新操作,但是这些操作将在每一种情况下都返回一个新的集合, 同时使原来的集合不发生改变。
- Scala List:List的特征是其元素以线性方式存储,集合中可以存放重复对象。
- Scala Set:Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。
- Scala Map:Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。
- Scala 元组:元组是不同类型的值的集合
- Scala Option:Option[T] 表示有可能包含值的容器,也可能不包含值。
- Scala Iterator:迭代器不是一个容器,更确切的说是逐一访问容器内元素的方法。
object Test {
def main(args: Array[String]): Unit = {
//定义整型List
val list = List(1, 2, 3, 4);
//定义Set
val set = Set(1, 3, 5, 7);
//定义Map
val map = Map("one" -> 1, "two" -> 2, "three" -> 3);
//创建两个不同类型的元组
val x = (10, "tom");
//定义Option
val option: Option[Int] = Some(5);
//迭代器示例
val it = Iterator("one", "two", "three", "four")
while (it.hasNext) { // 检测集合中是否还有元素
println(it.next()) // 返回迭代器的下一个元素,并更新迭代器的状态
}
val ita = Iterator(1, 2, 3, 4, 5)
val itb = Iterator(11, 22, 33, 44, 55)
//println(ita.max) // 查找最大元素
// println(itb.min) // 查找最小元素
println(ita.size) // 获取迭代器的长度
println(itb.length) // 获取迭代器的长度
}
}
11. Scala类和对象
类是对象的抽象,而对象是类的具体实例。
类是抽象的,不占用内存,而对象是具体的,占用存储空间。
类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。
class Point(xc:Int, yc:Int) {
var x:Int = xc;
var y:Int = yc;
def move(dx:Int,dy:Int): Unit ={
x = x + dx;
y = y + dy;
println("x的坐标是:" + x);
println("y的坐标是:" + y);
}
}
object Test {
def main(args: Array[String]): Unit = {
val pt = new Point(10,20);
pt.move(10,20);
}
}
12. Scala继承
Scala继承一个基类跟Java很相似, 但我们需要注意以下几点:
1、重写一个非抽象方法必须使用override修饰符。
2、只有主构造函数才可以往基类的构造函数里写参数。
3、在子类中重写超类的抽象方法时,你不需要使用override关键字。
class Point(xc:Int, yc:Int) {
var x:Int = xc;
var y:Int = yc;
def move(dx:Int,dy:Int): Unit ={
x = x + dx;
y = y + dy;
println("x的坐标是:" + x);
println("y的坐标是:" + y);
}
var name = "";
override def toString: String = getClass.getName + "[name=" + name + "]";
}
class Location(val xc: Int, val yc: Int, val zc: Int)
extends Point(xc, yc) {
var z: Int = zc;
def move(dx: Int, dy: Int, dz: Int) = {
x = x + dx;
y = y + dy;
z = z + dz;
}
var salary = 0.0;
override def toString: String = super.toString + "[salary="+ salary+ "]";
}
object Test {
def main(args: Array[String]): Unit = {
val lo = new Location(10,20,30);
lo.move(10,10,5);
lo.name = "location";
lo.salary = 35000.0;
println(lo);
}
}
13. Scala单例对象
- 在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object。
- Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的区别是,object对象不能带参数。
- 当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。
- 类和它的伴生对象可以互相访问其私有成员
//私有构造方法
class Marker private(val color:String){
println("创建:" + this);
override def toString(): String = "颜色标记:"+ color //4:颜色标记:red
}
//伴生对象,能访问类的私有属性和方法
object Marker {
private val markers : Map[String, Marker] = Map(
"red" -> new Marker("red"), //1.创建颜色标记:red
"blue" -> new Marker("blue"), //2.创建颜色标记;blue
"green" -> new Marker("green") //3.创建颜色标记:green
)
def apply(color:String) = {
if(markers.contains(color)) markers(color) else null;
}
def getMarker(color:String) = {
if(markers.contains(color)) markers(color) else null; //5:颜色标记:blue
}
def main(args: Array[String]): Unit = {
println(Marker("red"));
//单例函数调用,省略了.(点)符号
println(Marker getMarker "blue");
}
}
运行结果:14. Scala Trait(特征)
Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。
与接口不同的是,它还可以定义属性和方法的实现。
一般情况下Scala的类只能够继承单一父类,但是如果是 Trait(特征) 的话就可以继承多个,从结果来看就是实现了多重继承。
- Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait,如下所示:
trait Equal {
def isEqual(x:Any) : Boolean;
def isNotEqual(x:Any) : Boolean = !isEqual(x);
}
以上Trait(特征)由两个方法组成:isEqual 和 isNotEqual。isEqual 方法没有定义方法的实现,isNotEqual定义了方法的实现。子类继承特征可以实现未被实现的方法。所以其实 Scala Trait(特征)更像 Java 的抽象类。
以下演示了特征的完整实例:
trait Equal {
def isEqual(x:Any) : Boolean;
def isNotEqual(x:Any) : Boolean = !isEqual(x);
}
class Point(xc:Int,yc:Int) extends Equal{
var x:Int = xc;
var y:Int = yc;
override def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == x
}
object Test{
def main(args: Array[String]): Unit = {
val p1 = new Point(2,3);
val p2 = new Point(2,4);
val p3 = new Point(3,3);
println(p1.isNotEqual(p2)) //false
println(p1.isNotEqual(p3)) //true
println(p1.isNotEqual(2)) //true
}
}
- 特征构造顺序
特征也可以有构造器,由字段的初始化和其他特征体中的语句构成。这些语句在任何混入该特征的对象在构造时都会被执行。
构造器的执行顺序:
- 调用超类的构造器;
- 特征构造器在超类构造器之后、类构造器之前执行;
- 特征由左到右被构造;
- 每个特征当中,父特征先被构造;
- 如果多个特征共有一个父特征,父特征不会被重复构造
*所有特征被构造完毕,子类被构造。
15. Scala模式匹配
Scala 提供了强大的模式匹配机制,应用也非常广泛。
一个模式匹配包含了一系列备选项,每个都开始于关键字 case。每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。
示例:
object Test{
def main(args: Array[String]): Unit = {
println(matchText(3)); //many
}
def matchText(x : Int) : String = x match {
case 1 => "one";
case 2 => "two";
case _ => "many";
}
}
match 对应 Java 里的 switch,但是写在选择器表达式之后。即: 选择器 match {备选项}。
match 表达式通过以代码编写的先后次序尝试每个模式来完成计算,只要发现有一个匹配的case,剩下的case不会继续匹配。
接下来我们来看一个不同数据类型的模式匹配:
object Test {
def main(args: Array[String]) {
println(matchTest("two"))
println(matchTest("test"))
println(matchTest(1))
println(matchTest(6))
}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
}
使用样例类
使用了case关键字的类定义就是就是样例类(case classes),样例类是种特殊的类,经过优化以用于模式匹配。
object Test {
def main(args: Array[String]) {
val alice = new Person("Alice", 25)
val bob = new Person("Bob", 32)
val charlie = new Person("Charlie", 32)
for (person <- List(alice, bob, charlie)) {
person match {
case Person("Alice", 25) => println("Hi Alice!")
case Person("Bob", 32) => println("Hi Bob!")
case Person(name, age) =>
println("Age: " + age + " year, name: " + name + "?")
}
}
}
// 样例类
case class Person(name: String, age: Int)
}
在声明样例类时,下面的过程自动发生了:
- 构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;
- 在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;
- 提供unapply方法使模式匹配可以工作;
- 生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义。
16. Scala正则表达式
Scala 的正则表达式继承了 Java 的语法规则
示例:
import scala.util.matching.Regex
object Test {
def main(args: Array[String]) {
val pattern = new Regex("(S|s)cala") // 首字母可以是大写 S 或小写 s
val str = "Scala is scalable and cool"
println((pattern findAllIn str).mkString(",")) // 使用逗号 , 连接返回结果
}
}
17. Scala异常处理
Scala 的异常处理和其它语言比如 Java 类似。
Scala 的方法可以通过抛出异常的方法的方式来终止相关代码的运行,不必通过返回值。
- 抛出异常
Scala 抛出异常的方法和 Java一样,使用 throw 方法,例如,抛出一个新的参数异常:
throw new IllegalArgumentException
- 捕获异常
异常捕捉的机制与其他语言中一样,如果有异常发生,catch字句是按次序捕捉的。因此,在catch字句中,越具体的异常越要靠前,越普遍的异常越靠后。 如果抛出的异常不在catch字句中,该异常则无法处理,会被升级到调用者处。
捕捉异常的catch子句,语法与其他语言中不太一样。在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列case字句,如下例所示:
import java.io.{FileNotFoundException, FileReader, IOException}
object Test{
def main(args: Array[String]): Unit = {
try{
val f = new FileReader("input.txt");
}catch{
case ex : FileNotFoundException =>{
println("Missing file exception")
}
case ex : IOException =>{
println("IO exception")
}
}
}
}
18. Scala 提取器(Extractor)
apply方法:无需new操作就可创建对象。
unapply方法:是apply方法的反向操作,接受一个对象,然后从对象中提取值,提取的值通常是用来构造对象的值。
以下实例演示了邮件地址的提取器对象:
object Test{
def main(args: Array[String]): Unit = {
println("Apply方法:" + apply("Zara","gmail.com"));//Apply 方法 : Zara@gmail.com
println("unapply方法:" + unapply("Zara@gmail.com"));//Unapply 方法 : Some((Zara,gmail.com))
println("unapply方法:" + unapply("Zara Ali"));//Unapply 方法 : None
}
//注入方法(可选)
def apply(user:String, domain:String) ={
user + "@" + domain
}
//提取方法(必选)
def unapply(str: String): Option[(String,String)] = {
val parts = str split("@")
if(parts.length == 2){
Some(parts(0),parts(1))
}else{
None
}
}
}
以上对象定义了两个方法: apply 和 unapply 方法。通过 apply 方法我们无需使用 new 操作就可以创建对象。所以你可以通过语句 Test("Zara", "gmail.com") 来构造一个字符串 "Zara@gmail.com"。
unapply方法算是apply方法的反向操作:unapply接受一个对象,然后从对象中提取值,提取的值通常是用来构造该对象的值。实例中我们使用 Unapply 方法从对象中提取用户名和邮件地址的后缀。
- 提取器使用模式匹配
在我们实例化一个类的时,可以带上0个或者多个的参数,编译器在实例化的时会调用 apply 方法。我们可以在类和对象中都定义 apply 方法。
就像我们之前提到过的,unapply 用于提取我们指定查找的值,它与 apply 的操作相反。 当我们在提取器对象中使用 match 语句是,unapply 将自动执行,如下所示:
object Test{
def main(args: Array[String]): Unit = {
val x = Test(5);//执行apply
println(x)
x match{
//执行unapply
case Test(num) => println(x + "是:" + num +"的两倍")
case _ => println("无法计算")
}
}
//注入方法(可选)
def apply(x:Int) = x*2;
//提取方法(必选)
def unapply(z: Int): Option[Int] = if(z%2 == 0) Some(z/2) else None
}
19. Scala文件I/O
- 文件写操作
Scala 进行文件写操作,直接用的都是 java中 的 I/O 类 (java.io.File)
import java.io._
object Test{
def main(args: Array[String]): Unit = {
val writer = new PrintWriter(new File("test.txt"))
writer.write("Scala教程");
writer.close();
}
}
- 从屏幕上读取用户操作
import scala.io.StdIn
object Test{
def main(args: Array[String]): Unit = {
print("请输入百度地址:")
val line = StdIn.readLine();
println("你输入的是: " + line)
}
}
- 从文件上读取内容
从文件读取内容非常简单。我们可以使用 Scala 的 Source 类及伴生对象来读取文件。以下实例演示了从 "test.txt"(之前已创建过) 文件中读取内容:
import scala.io.Source
object Test{
def main(args: Array[String]): Unit = {
println("文件内容是:")
Source.fromFile("test.txt").foreach{
print;
}
}
}
参考:https://www.cnblogs.com/ahu-lichang/p/7207847.html?utm_source=itdadao&utm_medium=referral