Scala基础知识与语法

1.Scala基础知识与语法

1.1. scala语言的特点

可拓展
  面向对象
  函数式编程

兼容JAVA
  类库调用
  互操作

语法简洁
  代码行短
  类型推断
  抽象控制

静态类型化
  可检验
  安全重构

支持并发控制
  强计算能力
  自定义其他控制结构

1.2. scala与java的关系

  1. 都是基于JVM虚拟机运行的
    Scala编译之后的文件也是.class,都要转换为字节码,然后运行在JVM虚拟机之上。

  2. Scala和Java相互调用
    在Scala中可以直接调用Java的代码,同时在Java中也可以直接调用Scala的代码

  3. Java 8 VS Scala
    1)Java 8(lambda)没有出来之前,Java只是面向对象的一门语言,但是Java 8出来以后,Java就是一个面向对象和面向函数的混合语言了。

    2)首先我们要对Scala进行精确定位,从某种程度上讲,Scala并不是一个纯粹的面向函数的编程语言,有人认为 Scala是一个带有闭包的静态面向对象语言),更准确地说,Scala是面向函数与面向对象的混合。

    3)Scala设计的初衷是面向函数FP,而Java起家是面向对象OO,现在两者都是OO和FP的混合语言,是否可以这么认为:Scala = FP + OO,而Java = OO+ FP?

    由于面向对象OO和面向函数FP两种范式是类似横坐标和纵坐标的两者不同坐标方向的思考方式,类似数据库和对象之间的不匹配阻抗关系,两者如果结合得不好恐怕就不会产生1+1>2的效果。
    面向对象是最接近人类思维的方式,而面向函数是最接近计算机的思维方式。如果你想让计算机为人的业务建模服务,那么以OO为主;如果你希望让计算机能自己通过算法从大数据中自动建模,那么以FP为主。所以,Java可能还会在企业工程类软件中占主要市场,而Scala则会在科学计算大数据分析等领域抢占Java市场,比如Scala的Spark大有替代Java的Hadoop之趋势。

1.3. Scala解释器

  1. Scala解释器读到一个表达式,对它进行求值,将它打印出来,接着再继续读下一个表达式。这个过程被称做读取read–求值eval–打印print–循环loop,即:REPL

    从技术上讲,scala程序并不是一个解释器。实际发生的是,你输入的内容被快速地编译成字节码,然后这段字节码交由Java虚拟机执行。正因为如此,大多数scala程序员更倾向于将它称做“REPL”

在这里插入图片描述

1.4. scala变量的定义

​ scala的变量定义分为两种方式,分别需要使用关键字val和var。

  • val

    val a = 3

  • var

    var a = 3

    ​ val和var都可以用来定义变量,唯一的区别就在于,val定义的变量是不可变,而var定义的变量是可变的。不可变的量确实类似常量(被final修饰的变量),但不叫常量,只能叫不可变量的量。

    ​ 在今后的开发过程中,能使用val就使用val,var尽量不用,因为scala编程的特点,是在创建变量的时候可以省略数据类型,val有助于进行类型的推断。var在操作过程中不利于变量的类型。

    scala> val c = 4
    c: Int = 4
    
    scala> c = 5
    <console>:12: error: reassignment to val
           c = 5
    

    一个完整的变量的定义如下:

    val a:Int = 3

    其中val为变量修饰符,a为变量名,Int为a的数据类型,其中需要将变量名和数据类型使用:连接,=右侧为变量的值。

1.5. scala的数据类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4uhLgJM4-1633661209770)(assets/1572493461288.png)]

说明:scala拥有和java一样的数据类型,和java的数据类型的内存布局完全一致,精度也完全一致。需要说明一点的是Any和AnyRef,其中Any是对象的超类,AnyRef是类的超类,实例/对象是类的具体化。

4.6. scala操作符说明

  1. 在scala调用一些方法或者函数的时候,如果方法或者函数是空参的,可以省略掉().

  2. 在scala中一行表示的结尾不像java需要使用";",scala可以省略

2. scala的流程控制结构

2.1. if表达式

​ scala中的if表达式,基本和java中的if表达式一模一样,唯一的区别就是scala中的if、if-else、if-elseif-else有返回值!

scala> val ret = if(x < 4) 1 else -1
ret: Int = -1

scala> val ret = if(x < 4) 1 else "afff"
ret: Any = afff

​ 记住:scala中任意的表达式,都有返回值。

如果else丢失了
if(x>0) 1
那么有可能if语句没有输出值,但是在Scala中,每个表达式都有值,这个问题的解决方案是引入一个Unit类,写作(),不带else语句的if语句等同于if(x>0) 1 else ()

​ 表达式的最后一句话,最为表达式的返回值返回。

var f = 3
var n = 10
var m = 1
val d = if(n < 18){f = f + n ; m = m +n ; f+m}

==>d = 24

2.2. 循环

2.2.1. while

/*
	while --->
	1 + .... + 10
	java: 
		int sum = 0;
		int n = 1;
		while(n <= 10) {
			sum += n;
			n++;
		}
		sop();
*/
object _1WhileDemo {
	def main(args:Array[String]): Unit = {
		var sum = 0
		var n = 1
		while(n <= 10) {
			sum += n
			n += 1
		}
		println("sum= " + sum)
	}
}

注意:error: value ++/-- is not a member of Int

​ scala中不能直接对一个变量执行自增/减,++/–是scala集合的一个函数。

2.2.2 do while

object _2DoWhileDemo {
	def main(args:Array[String]): Unit = {
		var sum = 0
		var n = 1
		do {
			sum += n
			n += 1
		}while(n <= 10)
		println("sum= " + sum)
	}
}

2.2.3. 循环练习

​ 登录用户名密码的游戏:三次机会,从控制台输入输入用户名密码,如果成功登录,返回登录成功,失败,则反馈错误信息!

object _3DoWhileTest {
	def main(args:Array[String]): Unit = {
		val dbUserName = "pgone"
		val dbPassword = "lxl"
		var count = 3
		do {
			var inputUser = readLine("请输入您的姓名:")
			var inputPwd = readLine("请输入您的密码:")
			if(dbUserName == inputUser && dbPassword == inputPwd) {
				//println("欢迎光临:" + inputUser)
				println(s"欢迎光临:${inputUser}")
				count = -1
			} else {
				println(s"用户名密码有误,还有${count}次机会,请重输入:")
				count -= 1
			}
		} while(count >= 0)		
	}
}

2.3. 循环的终止

​ 在java中终止循环有关键字,continue,break,return,但是在scala中没有前两者continue和break。该如何终止循环呢?

​ 有三种方式来结束循环:

  1. 使用一个boolean变量来控制循环的结束

  2. 使用循环结束的条件来进行控制,比如上例中的count >= 0

  3. 还可以使用breakable函数体来进行控制

    import scala.util.control.Breaks._
    object _4BreakableDemo {
    	def main(args:Array[String]): Unit = {
    		var sum = 0
    		var n = 1
    		breakable {
    			do {
    				sum += n
    				n += 1
    				if(n > 6)
    					break
    			}while(n <= 10)
    		}
    		println("sum= " + sum)
    	}
    }
    

2.4. for循环

2.4.1. for循环

​ 在java中有2中写法,普通的for循环for(变量;条件;自增或自减){循环体} or for(类型 变量 : 集合) {}。

​ scala中的for循环该如何定义呢?

​ scala中并没有像java中普通for循环的语法结构,更像是高级for循环。

for (变量 <- 集合) {
    
}

​ 将上述的while循环使用for循环改写

object _5ForDemo {
	def main(args:Array[String]): Unit = {
		var sum = 0
		for(n <- 1 to 10 reverse) {
			println(n)
		}
		//println("sum= " + sum)
	}
}

说明:添加reverse主要就是向进行循环的反转

2.4.2. 循环的嵌套

object _6ForDemo {
	def main(args:Array[String]): Unit = {
		
		for(y <- 1 until 5) {
			for(x <- 1 to 5) {
				print("*")
			}
			println
		}
		println("-----------^~^----------")
		for(y <- 1 until 5; x <- 1 to 5) {
			print("*")
			if(x == 5)
				println
		}
		/*
			*
			**
			***
			****
		*/
		println("-----------^~^----------")
		for(x <- 1 to 5; y <- 1 to 5) {
			if(y <= x)
				print("*")
			if(x == y)
				println
		}
		println("-----------^_^----------")
		for(x <- 1 to 5; y <- 1 to 5 if y <= x) {
			print("*")
			if(x == y)
				println
		}
	}
}

练习题:9*9乘法口诀表。

for(x <- 1 to 9; y <- 1 to 9 if y <= x) {
	print(y+"*"+x+"="+(x*y)+"\t")
	if(x == y)
		println
}

2.5. 异常控制

​ scala的异常体系,在很大程度上沿用java的异常体系的,只不过在书写结构上略有差异。

val i = 1 / 0
println("i= " + i)

​ 上述代码,在执行过程中出现异常:

java.lang.ArithmeticException: / by zero

​ 在java中学习了两种异常的处理方式:throws和try-catch。throws和java中的一模一样,将异常转交给调用者进行处理。try-catch则意味着自己要进行处理,但是编写的方式和java不一样。

import scala.io._
object _7ExceptionDemo {
	def main(args:Array[String]): Unit = {
		
		try {
			lazy val line = Source.fromFile("E:/data/hello1.txt").mkString
			println(line)
			val ii = Integer.valueOf("abc")
			val i = 1 / 0
			println("i= " + i)
		} catch {// 模式匹配
			case e: ArithmeticException => {
				println("ArithmeticException==>" + e.getMessage)
			}
			case e: NumberFormatException => {
				println("NumberFormatException===>" + e.getMessage)
			}
			case e:RuntimeException => {
				println("RuntimeException===>" + e.getMessage)
			}
			case _ => {
				println("通用的处理~")
			}			
		}
	}
}	

说明:上面的案例中,更进一步的学习了一个关键字lazy(懒加载),被lazy所修饰的变量,只有当第一次被使用的时候才会进行初始化,没有使用之前只是记录了存在,检查语法结构是否正确。可以节省一定的资源空间。

3. scala的函数

3.1. 函数的定义

​ Scala除了方法外还支持函数。方法对对象进行操作,函数不是。要定义函数,你需要给出函数的名称、参数和函数体,就像这样:

在这里插入图片描述

1、你必须给出所有参数的类型。不过,只要函数不是递归的,你就不需要指定返回类型。Scala编译器可以通过=符号右侧的表达式的类型推断出返回类型。
2、“=”并不只是用来分割函数签名和函数体的,它的另一个作用是告诉编译器是否对函数的返回值进行类型推断!如果省去=,则认为函数是没有返回值的!

3、在scala中一个函数的最后一句话就是该函数的返回值,不需要使用return,当然加上也行。

3.2. 函数定义练习

object _8FunctionDemo {
	def main(args:Array[String]): Unit = {
		val ret = add(3, 4)
		println("ret: " + ret)
	}
	
	def add(first:Int, second:Int) = {
		first + second
	}
}	

说明:函数可以不使用return语句,但是如果加上return,那返回值类型,必须要加上,否则:

_8FunctionDemo.scala:9: error: method add has return statement; needs result type
return first + second
^
one error found

def add(first:Int, second:Int):Int = {
	return first + second
}

3.3. 特殊函数

  • 单行函数

    所谓单行函数,指的是函数体只有一行的函数。

    def method = 5 or def method = println(“abcdefg”)

  • 无参函数

    函数的参数列表为空。
    
    object _9FunctionDemo {
    	def main(args:Array[String]): Unit = {
    		//show()
    		show
    	}
    	
    	def show {
    		println("Today is a well day")
    	}
    }	
    

    注意:定义空参函数的时候,如果函数加了(),在调用的时候,()可以省略;但是如果在定义的时候没有加(),在调用的时候,也只能省略,不能加()。

  • 递归函数

    ​ 在特定条件下,函数调用本身。

    阶乘求解:5!

    object _10FunctionDemo {
    	def main(args:Array[String]): Unit = {
    		val ret = factorial(5)
    		println("5!= " + ret)
    	}
    	/*
    		5! = 5 * 4 * 3 * 2 * 1
    		5! = 5 * 4!
    		4! = 4 * 3!
    		3! = 3 * 2!
    		2! = 2 * 1!
    		1! = 1
    	*/
    	def factorial(n:Int):Int = {
    	    if(n == 1)
    		  1
    	    else
    			n * factorial(n - 1)
    	}
    }	
    

3.4. 函数参数的特点

3.4.1. 默认参数和带名参数

object _11FunctionDemo {
	def main(args:Array[String]): Unit = {
		address("常军磊", "河南", 13919191119L)
		address("old李", telphone = 13838383338L)
		address("田月梅", telphone = 1888888888L, province = "湖北")
		address(telphone = 1888888888L, name = "田月梅", province = "湖北")
	}
	
	def address(name:String, province:String = "bj", telphone:Long) {
		println(s"name:${name},\tprovince:${province},\ttelphone:${telphone}")
	}
}	

scala的函数参数列表,在定义的时候,可以使用有默认值的参数,在做函数调用的时候可以使用带名的参数,所以有时我们是无法通过参数的参数来推断出具体的参数列表顺序。

3.4.2. 可变参数

object _12FunctionDemo {
	def main(args:Array[String]): Unit = {
		var ret = add(1, 2)
		println("ret = " + ret)
		val arr = Array(3, 4, 5)
		ret = add(arr: _*)
		println("ret = " + ret)
	}
	/*
	def add(a:Int, b:Int) = {
		a + b
	}
	
	def add(a:Int, b:Int, c:Int) = {
		a + b + c
	}
	
	def add(arr:Array[Int]):Int = {
		/*var sum = 0
		for(a <- arr) {
			sum += a
		}
		sum*/
		arr.sum
	}
	*/
	//可变参数
	def add(arr: Int*):Int = {
		var sum = 0
		for(a <- arr) {
			sum += a
		}
		sum
	}
}	

说明:

  1. scala中的可变参数和java有一点不同,上例中第三个函数和第四个函数,在java中实际上是同一个函数,而在scala中是两个不同的函数。

  2. 在对第四个函数add(arr:Int*)就不能向java一样,直接传递一个数组,否则报错,类型不匹配。要想给一个可变参数传递数组,就需要将数组中的元素提取出来,再传递,操作方式如下:

    val arr = Array(3, 4, 5)
    ret = add(arr: _*)

4. scala数组和集合

​ scala的集合分为了两类,一类是可变的集合(集合可以执行增删改查操作),另一类是不可变集合(集合元素在初始化的时候确定,后续只能进行查,有的可以进行修改,有的不可以)。二者可能名称一样,但是在不同的包下面,对应的包为:scala.collection.mutable和scala.collection.immutable。

​ scala默认使用的集合,或者默认导入的包是immutable。

4.1. Scala数组

4.1.1. 不可变数组Array

​ Array可以理解为java中的数组。

  1. 数组的定义

    //创建数组
    //int[] a = new int[5];
    val arr = new Array[Boolean](3)
    for(a <- arr) {
        println(a)
    }
    println("-------------------")
    //叫做数组类Array的伴生对象的创建方式
    val arr1 = Array[Int](1, 2, 3, 4, 5) // int[] a = {1 , 2, 3, 4, 5}
    for(a <- arr1) {
        println(a)
    }
    
  2. 获取数组中的元素

    println("----------获取数组中的元素--------------")
    println("获取arr1中index为3的元素:" + arr1(3))
    arr1(3) = -3
    println("获取arr1中index为3的元素:" + arr1(3))
    
  3. 元素的遍历

    println("--普通的for--")
    for(a <- arr1) {
        println(a)
    }
    println("--foreach--")
    arr1.foreach(a => println(a))
    
  4. 数组的长度

    println("length: " + arr1.length)
    
      /** The length of the array */
      def length: Int = throw new Error()
    

4.1.2. 可变数组ArrayBuffer

​ ArrayBuffer就可以理解为java中的ArrayList。

  1. 定义

    //两种创建方式
    //普通的创建方式,创建一个初始化长度为3的Int类型的ArrayBuffer
    var ab = new ArrayBuffer[Int](3)
    //使用ArrayBuffer的伴生对象创建类型为Int的ArrayBuffer
    ab = ArrayBuffer[Int]()
    
  2. crud

    //追加元素---(尾部追加元素)append
    ab.append(1, 2, 3)
    println("ab: " + ab)
    //insert(index, 元素*)在指定的位置插入元素
    ab.insert(1, -2, -1)
    println("ab: " + ab)
    //修改
    ab(2) = 0
    println("ab: " + ab)
    //删除
    ab.remove(2)//删除下标对应的元素
    println("ab: " + ab)
    ab.remove(1, 2)
    println("ab: " + ab)
    ab.insert(1, -2, -1, 0, 1, 2)
    println("ab: " + ab)
    ab = ab.drop(2)//从首部开始删除N个元素,并返回一个新集合,原集合不变
    println("ab: " + ab)
    ab = ab.dropRight(2)//从尾部开始删除N个元素,并返回一个新集合,原集合不变
    println("ab: " + ab)
    
  3. 遍历和长度

    遍历和Array方式一样。

    长度可以使用length,也可以使用size。

4.1.3. Array和ArrayBuffer的一些基本通用操作

  1. 包含

    ab.contains(3)
    
  2. 数组求和

    ab.sum
    
  3. 数组的最大值最小值

    ab.max
    ab.min
    
  4. Array和ArrayBuffer之间的互相转换

    Array--->ArrayBuffer
    	array.toBuffer
    ArrayBuffer--->Array
    	ab.toArray
    
  5. 数组内容的显示

    //mkString的方法 将数组元素使用分隔符串成一个字符串
    println(ab.mkString(","))//分割符为,
    println(ab.mkString("[", ", ", "]"))//分割符为,起始结束符号分别为[, ]
    

4.2. Scala集合

4.2.1 Map映射

​ Map是一个对偶,映射的k-v键值对的集合,在一个map中可以包含若干组k-v映射关系,前提条件是k不能重复。同样map也有可变和不可变之分。

4.2.1.1 不可变Map

​ import scala.collection.immutable.Map

  1. 定义

    因为Map是一个类似java中的接口,无法直接创建对象,所以需要使用它的伴生对象创建。

    val map = Map[K, V]()
    
  2. 初始化

    val map = Map[String, Integer](
                ("pgp" -> 27),
                "jdr" -> 18,
                "jdr" -> 19,
                "lhj" -> 38
            )
    
  3. crud

    /*
              * 通过get(k)获得的结果为Option(可选的)
              * 可以将option理解为java中的一个抽象类或者接口
              * option有两个仅有的子类:
              *     Some    --->代表有值
              *     None    --->没有值
              * 获取Some对应的值,可以通过some.get获取,对None调用get会报错
              *     NoSuchElementException
              * 所以为了避免这个错误,我们可以调用option的另一个方法规避:getOrElse
              */
    var gAge = map.get("pgp")
    println(gAge.get)
    gAge = map.get("zxn")
    println(gAge.getOrElse(-1))
    println("----获取的另外一种方式-----")
    println(map("pgp"))
    //判断key是否包含
    if(map.contains("pga")) {
        println(map("pga"))
    }
    
4.2.1.2. 可变Map
  1. 定义并初始化

    //创建并初始化
    val map = mutable.Map[String, Integer](
        "zgj" -> 13
    )
    
  2. crud

    //增加元素
    map.put("lsl", 18)
    println(map)
    map("csl") = 23
    println(map)
    map.+(("xy", 15))//添加一对kv,并返回一个新的map,原map不变
    println(map)
    map += ("lk" -> 17)
    println(map)
    //获取元素--get,和不可变map一模一样
    //修改
    map("csl") = 33
    println(map)
    //删除
    //remove返回值为被删除的key对应的value,类型Option
    println(map.remove("lk"))
    
4.2.1.3. map的通用操作
  1. 集合大小

    map.size
    
  2. map的遍历

    println("-------遍历--------")
    for(aaa <- map) {
        println(aaa)
    }
    println("-----(k, v)------")
    for((k, v) <- map) {
        println(s"k=${k}, v=${v}")
    }
    println("-----foreach------")
    map.foreach(kv => {
        println(kv._1 + "--->" + kv._2)
    })
    

4.2.2 Tuple元组

  1. 定义

​ 元组,其实就是一组对偶,也可以理解为是java中List。映射是键/值对偶的集合。对偶足元组( tuple)的最简单形态,元组是不同类型的值的聚集。元组的值是通过将单个的值包含在圆括号中构成的。例如:(1, 3.14, “Fred”)是一个元组,类型为:Tuple3 [Int, Double, java.lang.String]

  1. 创建并初始化

    说明:元组Tuple是List,但是其长度是有范围的,最长可以容纳22个元素,也即Tuple22,其中Tuple1可以简写为Tuple。

    val t = new Tuple2[String, Int]("陈腾", 18)
    or
    val tt = ("陈腾", 18)
    
  2. 操作

    val t = new Tuple2[String, Int]("陈腾", 18)
    val tt = ("陈腾", 18)
    //获取tuple中的某一个元素
    println("name: " + tt._1)
    println("age: " + tt._2)
    val weekdays = ("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN")
    for (a <- weekdays.productIterator) {
        println(a)
    }
    println("----------------------")
    val season = ("春", "夏", "秋", "冬")
    val (spring, summer, autumn, winter) = ("春", "夏", "秋", "冬")
    println("spring: " + spring)
    println("summer: " + summer)
    println("autumn: " + autumn)
    println("winter: " + winter)
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

(YSY_YSY)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值