Scala 基础篇之一

一、关于Scala

专门为计算而生的语言。
Scala将(Java后者C++)面向对象设计和函数式编程结合在一起的简洁的高级编程语言。
编译的代码可以直接运行在JVM之上,能和java、Spark无缝的对接,继而简化大数据集的处理难度,简化开发步骤。

函数式编程:强调的是通过传递算子(代码|函数)实现大规模数据集的本地计算。

二、环境配置

下载对应的scala版本:https://www.scala-lang.org/download/2.11.12.html
Windows版本安装:
	- 点击 scala-2.11.12.msi双击msi文件安装
	- 配置Scala的环境变量SCALA_HOME变量,同时在PATH变量中追加xxx;%SCALA_HOME%\bin
	- 打开控制台输入scala
		C:\Users\Administrator>java -version
			java version "1.8.0_161"
			Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
			Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
			
			C:\Users\Administrator>scala
			Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
			Type in expressions for evaluation. Or try :help.

CentOS安装:
	- 下载 scala-2.11.12.rpm
	- 安装配置Scala
	
		[root@CentOSA ~]# rpm -ivh scala-2.11.12.rpm
		Preparing...                ########################################### [100%]
		   1:scala                  ########################################### [100%]
		[root@CentOSA ~]# scala
		Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_191).
		Type in expressions for evaluation. Or try :help.
		
		scala>

三、变量

在这里插入图片描述

3.1 值类型和引用类型

Scala将值类型和引用类型分离。
	所有的数值变量类型都是 AnyVal的子类,这些变量的值都有字面值。
	对象类型的变量都是AnyRef的子类。对于 AnyRef类下的变量(除String类型),一般不允
许直接赋值字面量,都需要借助 new关键创建。

3.2 变量声明

Scala 可以做变量类型自动推断。编译器在编译的时候推断出最终类型。根据字面量的值自动识别类型。
因此Scala中声明一个变量主需要告知编译器该变量的值是常量还是变量。
程序一旦编译后,类型固定,不可以更改。
	声明一个变量使用      var
	声明的是一个常量使用  val
语法:var|val 变量名[:类型] = 变量值[:类型]  类型可省略
	var i=1 (默认Int类型)

由于编译器是可以自动推断出AnyVal类型的变量,因此用户在声明AnyVal类型的变量的时候,无需指定变量类型。

3.3 数值转换

用户可以使用asInstanceOf[类型]这种方式在数值间转换。该方式只适合类型兼容的时候使用。
	scala> var i=1
	i: Int = 1
	scala> var b:Byte=i.asInstanceOf[Byte]
	b: Byte = 1
	scala> var b:Byte=i.toByte
	b: Byte = 1

如果类型不兼容可以使用toInt、toChar 方法等可以将常规参数自动转换为数值类型
	scala> var sex="true"
	sex: String = true
	scala> sex.toBoolean
	res2: Boolean = true	
	scala> sex.asInstanceOf[Boolean]
	java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
	  at scala.runtime.BoxesRunTime.unboxToBoolean(BoxesRunTime.java:85)
	  ... 32 elided

3.4 数组

Scala提供了简便的声明和使用方式,例如声明一个Int类型的数组,
	scala> val array:Array[Int] = Array(1,2,3)
	scala> array(0)
	res10: Int = 1

可以通过length和size方法获取数组长度。

3.5 元组

元组是在Scala编程语言中的一种特殊变量。该变量可以组合任意几种类型的变量。构建一个只读的变量类型。
元组中的元素只读,其本身可以修改。
访问元组的成员可以使用_元素下标访问。
	scala> var t:(String,Int)=("zs",18)
	t: (String, Int) = (zs,18)
	scala> t._1
	res10: String = zs
	scala> t._2
	res11: Int = 18

注意:一个元组最大允许有22个元素。

四、分支循环

4.1 条件分支-if

使用if可以作为条件分支控制语句,这一点类似与Java
	 var i:Int=100
		if(i<10){
    
    
		    println("i小于10:"+i)
		}else if(i<20){
    
    
		    println("i小于20:"+i)
		}else{
    
    
		    print(s"i大于:$i") //小s上下文取值,隐式转化。
		}

if修饰的代码分支可以赋值给一个变量,这里的代码块中不允许使用return。
	var i:Int=new Random().nextInt(30)
	var result=  if(i<10){
    
    
	    "小"
	}else if(i<20){
    
    
	    true
	}else{
    
    
	    ("zhangsan",1)//元组
	}

4.2 while/do-while

	var i=5
	while (i != 0){
    
    
	  i -= 1
	  println(i)
	}

	var i=5
	do{
    
    
	  i -= 1
	  println(i)
	}while(i!=0)

4.3 Break

Scala 语言中默认是没有 break 语句,但是在 Scala 2.8 版本后可以使用另外一种方式来实现 break 语句。
当在循环中使用 break 语句,在执行到该语句时,就会中断循环并执行循环体之后的代码块。Scala 中 break 的语法有点不大一样,格式如下:

	var loop=new Breaks
	loop.breakable({
    
    
	  do{
    
    
	    i -= 1
	    print(i+"\t")
	    if(i==1) {
    
    
	      loop.break()
	    }
	  }while(i!=0)
	})

4.4 for循环

数组遍历:
	var array=Array(1,2,3,4)
	for(item <- array){
    
    
	  print(item+"\t")
	}
	
	var array=Array("a","b","c")
	for( index <- 0 to array.length-1){
    
    
	  print(array(index))
	}

	var array=Array("a","b","c")
	for( index <- 0 until array.length){
    
    
	  print(array(index)+"\t")
	}

for循环可以使用多个循环因子:
	for(i<-1 to 9;j <- 1 to i){
    
    
	    print(s"$i*$j="+(i*j)+"\t")
	    if(i==j) println()
	}
	
for循环可以嵌套if判断:
	for(i<-1 to 9;if(i%2==0 || i%3==0) ){
    
    
	    print(s"$i\t")
	}

数组计算:
	var array=0 to 9
	val results = for(i <- array;if(i%2==0)) yield i*i
	for(i <- results){
    
    
	    println(i)
	}

模式匹配:
	模式匹配是检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分。
	它是Java中的switch语句的升级版,同样可以用于替代一系列的 if/else 语句。
数值匹配:
	val x: Int = Random.nextInt(10)
	var result= x match {
    
    
	   case 0 => "zero"
	   case 1 => "one"
	   case 2 => "two"
	   case 3 => "three"
	   case 4 => "four"
	   case _ => "other"
	 }
	 println(result)

类型匹配:
	var array=Array("zs",true,new Date(),1000.0)
	var x=array(new Random().nextInt(array.length))
	println("x:"+x)
	 var result= x match {
    
    
	   case v:String => "name"
	   case v:Boolean => "sex"
	   case x:Date => "birth"
	   case x:Double => "salary"
	   case _ => "未知"
	  }
	println(result)
	

五、函数

5.1 函数声明

def functionName ([参数列表]) : [return type] = {
    
    
 }
 
def sum(x:Int,y:Int):Int={
    
    
  return x+y
}
//可以尝试省略返回值类型
def multi(x:Int,y:Int)={
    
    
  x*y
}
def sayHi(name:String):Unit={
    
    
  println("hi~ "+name)
}

5.2 可变长参数

	def sum(args:Int*):Int={
    
    
	    var sum:Int=0
	    for(agr <- args){
    
    
	        sum += agr
	    }
	    return sum
	}

5.3 参数默认值

	def sayHello(msg:String="a",name:String="b"):Unit={
    
    
	    println(msg+"  "+name)
	}
	
	sayHello()

命名参数:
sayHello(name="zhangsan",msg="你好!")
def sayHello(msg:String="hello",name:String="zhangsan"):Unit={
    
    
    println(msg+"  "+name)
}

5.4 内嵌函数

	 def factorial(x:Int)={
    
    
	    def mulit(i:Int):Int={
    
    
	      if(i > 0){
    
    
	        i*mulit(i-1)
	      }else{
    
    
	        1
	      }
	    }
	    mulit(x)
	  }
等价
	def factorial(x:Int):Int={
    
    
	   if(x>0){
    
    
	      x*factorial(x-1)
	   }else{
    
    
	      1
	   }
	 }


5.5 柯里化(Currying)

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数的函数,
并且返回接受余下的参数的新函数的这种技术。(改写的_必须为最后一个参数)
	def sum1(x:Int)(y:Int)(z:Int):Int={
    
    
	    x+y+z
	}
	scala> sum1(1)(2)(_)
	res19: Int => Int = <function1>
	scala> res19(3)
	res20: Int = 6
	

5.6 匿名函数

Scala 中定义匿名函数的语法.
	箭头左边是参数列表,右边是函数体。
		scala> (x:Int,y:Int) => {
    
    x+y}
		res21: (Int, Int) => Int = <function2>
		
		scala> res21(1,2)
		res22: Int = 3

注意:任意一个函数本质,就是一个变量。
	 var f:(Int,Int)=>Int = (x:Int,y:Int)=>{
    
    x+y}
	 var f:(Int,Int)=>Int = (x,y)=>{
    
    x+y}

在这里插入图片描述

六、Class & object

6.1 单例类

由于Scala没有静态方法和静态类,所有通过object去定义静态方法或者静态对象。- 单例对象(类似java中的工具类 )

object User {
    
    
    def sayHello:(String)=>String = (name)=> "Hello ~"+name

    def sayHello1(name:String):String={
    
    
      "Hello ~"+name
    }
}

var u1=User
var u2=User
println(u1 == u2) // true

6.2 伴生对象

当object和Class放在一个文件中时候,且名字保持一致称该object为当前Class的伴生对象。
	class Animal {
    
    }
	object Animal{
    
    }

6.3 类

必须要求在构造方法的第一行显式调用this(),其中_表示参数赋值为
默认值,因为Scala中class默认构造器是在类上声明的

class User {
    
    
   var id:Int = _
   var name:String= _
   var birth:Date = _

  def this(id:Int,name:String,birth:Date){
    
    
    this()
    this.id=id
    this.name=name
    this.birth=birth
  }
  override def toString: String = {
    
    
    s"$id\t$name\t$birth"
  }
}

var u=new User() //right
var u2=new User(1,"zs",new Date())


def this(参数)构造器重载:
使用该种方式声明构造类似于Java编程,但是要求在构造的第一行必须显示调用默认构造方法。

class User(var age:Int,var name:String) {
    
     //默认构造器
  var birth:Date = _
  def this(age:Int,name:String,birth:Date){
    
    
    this(age,name)
    this.birth=birth
  }
  override def toString: String = {
    
    
    s"$age\t$name\t$birth"
  }
}

var u1=new User() //error
var u2=new User(1,"zs") 
var u3=new User(1,"zs",new Date())

6.4 伴生对象创建类

apply关键字:
使用伴生对象可以方便的创建对象,只需要覆盖对应的apply方法,如下:
	class User(var age:Int,var name:String) {
    
    
	  var birth:Date = _
	  def this(age:Int,name:String,birth:Date){
    
    
	    this(age,name)
	    this.birth=birth
	  }
	  override def toString: String = {
    
    
	    s"$age\t$name\t$birth"
	  }
	}
	object User{
    
    
	  def apply(age: Int, name: String): User = new User(age, name)
	  def apply(age: Int, name: String,birth:Date): User = new User(age, name,birth)
	}

	var u3=User(1,"zs",new Date())
	var u4=User(1,"zs",new Date())

注意:
	声明数组就是使用半生对象方式创建的。
		scala> var a=new Array[Int](3)
		a: Array[Int] = Array(0, 0, 0)
		
		scala> var b=Array(1,2,3)
		b: Array[Int] = Array(1, 2, 3)

unapply关键字:用于将一个实体对象的属性解码出来。
	class User(var age:Int,var name:String) {
    
    
	  var birth:Date = _
	  def this(age:Int,name:String,birth:Date){
    
    
	    this(age,name)
	    this.birth=birth
	  }
	  override def toString: String = {
    
    
	    s"$age\t$name\t$birth"
	  }
	}
	object User{
    
    
	  def apply(age: Int, name: String): User = new User(age, name)
	  def apply(age: Int, name: String,birth:Date): User = new User(age, name,birth)
	
	  def unapply(u: User): Option[(Int, String,Date)] ={
    
    
	    Some(u.age,u.name,u.birth)
	  }
	}

		val u = new User(1,"zs",new Date())
		u.name="zhangsan"
		var User(age,name,birth)=u
		println(s"$age\t$name\t$birth")


6.5 抽象类

	abstract class Animal(name:String) {
    
    
	  def eat():Unit={
    
    
	    println("animal can eat...")
	  } //抽象类型可以定义方法的实现
	  def  sleep():String
	}

6.6 Trait/特质(接口)

	trait Speakable {
    
    
	  def speek():Unit
	}
	trait Flyable {
    
    
	  def fly():Unit
	}


6.7 继承&实现

class Bird(name:String) extends Animal(name:String) with Flyable with Speakable {
    
    
  override def sleep(): String = {
    
    
    s"$name 睡觉"
  }
  override def fly(): Unit = {
    
    
    println(s"$name 会飞!")
  }
  override def speek(): Unit = {
    
    
    println(s"$name 唧唧咋咋!")
  }
}

class Dog(name:String) extends Animal(name:String) with Speakable {
    
    
  override def sleep(): String = {
    
    
    s"$name 睡觉!"
  }

  override def speek(): Unit = {
    
    
    println(s"$name 旺旺叫!")
  }
}

var d:Animal=new Dog("小黑")
var b:Animal=new Bird("小麻雀")

var d2:Dog=d.asInstanceOf[Dog]
d2.speek()

6.8 动态植入

	class SmallBird(var name:String) extends Animal (name:String) with Speakable {
    
    
	  override def sleep(): String = {
    
    
	    s"$name 会睡觉!"
	  }
	
	  override def speek(): Unit = {
    
    
	    println(s"$name 咿咿呀呀!")
	  }
	  override def eat(): Unit = {
    
    
	    println(s"$name 吃鱼!")
	  }
	}
	
①在覆盖有实现的方法必须添加overwrite;
②一个类只能继承一个类(抽象)with多个trait例如:
class A extends B with C with D{
    
    }
 // B既可以是Trait也可以是Class,但是C/D必须是Trait

	var sb=new SmallBird("丑小鸭") with Flyable{
    
    
	  override def fly(): Unit = {
    
    
	    println(s"$name 会飞!")
	  }
	}
	sb.fly()

6.9 self

等价于this关键字,在this出现混淆的时候使用self给this关键字起别名。

class User(var name:String) {
    
    
  self =>
  def setName(name:String):Unit={
    
    
    self.name=name
  }
  def getName():String={
    
    
    self.name
  }
}

6.10 Case class样列类

case class就像常规类,case class适用于对不可变数据进行建模。
与普通的class不同的是,CaseClass创建的对象 == 比较的是对象的内容。
通常用于只读数据的建模。可以简单的使用copy来实现两个对象间的值得传递

当一个类被定义成为case类后,Scala会自动帮你创建一个伴生对象并帮你实现了apply, unapply,setter, getter 和toString,equals,copy和hashCode等方法

	case class User(name:String,age:Int)
		var u1= User("zs",19)
		var u2= User("zs",19)
		println(u1==u2) //true
		
		var u1= new User("zs",19)
		var u2= new User("zs",19)
		println(u1==u2) //true

		var u1= User("zs",19)
		var u2= u1.copy(u1.name,20)
		println(u2)
		

6.11、final的用法。

	 修饰类 ,表示最终类,该类无法被继承
	 修饰方法,表示方法不允许被覆盖
	 修饰属性,表示改属性不允许被子类遮盖
	 

七、可见性

注意:可见性使用

	class 或 trait 关键字之前,
    val   或 var 关键字之前  ,
    def   关键字之前。如果不指定默认都是public

7.1 public

Scala 中的默认可见性为 public ,默认可见性为 public.
这是逻辑上的,实际上 Scala 中并没有 public 这个关键字,如果你用 public 来声明一个类或成员,编译器会报错
	public class User {
    
     //编译器不通过
	  var id=1
	  var name="zhanngsan"
	  var age=18
	  var birthDay = new Date ()
	}
	 

7.2 Private

1.修饰类:
	只能被同包下的子类继承(同包可见),并且同包继承的类也必须是private修饰。
	不同包类不可见。因为这样才不会改变原始父类的可见性。
	被private修饰的类只能在同包下可用
		package com.sxxd.demo08
		import java.util.Date
		private class User {
    
    //父类
		  var id=1
		  var name="zhanngsan"
		  var age=18
		  var birthDay = new Date ()
		}
	
		package com.sxxd.demo08
		private class SmallUser extends User {
    
    //子类继承,同包可见
		}

2.修饰属性|方法:
   表示该属性/方法只能被本类|伴生对象可见,其他均不可见
	package com.sxxd.demo08
	import java.util.Date
	private class User {
    
    
	  private var id=1
	  var name="zhanngsan"
	  var age=18
	  var birthDay = new Date ()
	
	  private def eat():Unit={
    
    
	    println("吃!")
	  }
	}
	object User{
    
    
	  def main(args: Array[String]): Unit = {
    
    
	    val user = new User()
	    user.eat()
	    user.id=2
	  }
	}



7.3 Protected

1、修饰类:类可以被同包下的其他类访问。或者是同包子类使用。
		package com.sxxd.demo09
		protected class User {
    
    }

		package com.sxxd.demo09
		class SmallUser extends User{
    
    }
		
2、修饰属性和方法
	只能在本类或者本类的子类以及半生对象中访问
		package com.sxxd.demo09
		protected class User {
    
    
		  protected var name:String= _
		  protected def eat():Unit={
    
    
		    println("eat")
		  }
		}

		package com.sxxd.demo09
		class SmallUser extends User{
    
    
		}
		object SmallUser{
    
    
		  def main(args: Array[String]): Unit = {
    
    
		    val sm = new SmallUser()
		    sm.eat()
		  }
		}
		

7.4 this限定

可以去除伴生对象的可见性:
	class Student(name:String) {
    
    
	   var id=1
	   protected|private[this] var sex=true
	   
	   def sayHello():Unit={
    
    
	     println(this.name)
	   }
	}
	object Student{
    
    
	  def apply(name: String): Student = new Student(name)
	}

7.5 package限定

表示当前的类、属性、方法可以在指定的包下可见
	class Student(name:String) {
    
    
	   var id=1
	   private [demo01] var sex=true  //01包可见
	   def sayHello():Unit={
    
    
	     println(this.name)
	   }
	}
	object Student{
    
    
	  def apply(name: String): Student = new Student(name)
	}


7.6 sealed(密封)

Trait和classcase class可以标记为 sealed,
	这意味着必须在同一文件中声明所有子类,这样就确保了所有的子类型都是已知的。(被定义好,不允许修改)
 
	sealed case class Message(msg:String,code:Int)
	class InfoMessage(msg:String,code:Int) extends Message(msg:String,code:Int) 
	class ErrorMessage(msg:String,code:Int) extends Message(msg:String,code:Int) 
	class WarnMessage(msg:String,code:Int) extends Message(msg:String,code:Int) 
	

八 函数对象

函数对象-java函数式接口

函数式接口定义:
	在Java1.8中提出,如果一个接口里面只能有一个抽象方法,那么我们将该接口称为函数式接口
	Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查。加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错
	
	@FunctionalInterface
	public interface GreetingService {
    
    
	    void sayMessage(String message);
	}

//        函数式 接口的使用 与lambda 表达式的转换
      GreetingService gs= new GreetingService() {
    
    
          @Override
          public void sayMessage(String message) {
    
    
              System.out.println(message);
          }
      };
      gs.sayMessage("java hello");

      GreetingService gs1= (GreetingService)(message)-> System.out.println(message);
      gs1.sayMessage("函数式调用");//注意强转


8.1 部分应用函数

部分应用函数:只给你一部分参数的函数
在Scala中同样对所有的函数都可以理解为是一个接口函数。在Scala中可以尝试将一个函数转变成一个对象类型
	scala> def sum(v1:Int,v2:Int):Int={
    
    
	     |       v1+v2
	     |    }
	sum: (v1: Int, v2: Int)Int
	scala> var sumFunction=sum _
	sumFuction: (Int, Int) => Int = <function2>	
	
这里的sumFunction,sumForOne都是是sum函数的部分应用函数
	scala> var sumForOne=sum(_:Int,2)
	sumForOne: Int => Int = <function1>

可以看出sumFunction是一个变量,该变量的类型是(Int, Int) => Int其中<function2>是该对象的字面值。在Scala中所有的函数都可以更改成为Function1~22对象的实例。例如
	scala> sumFuction.isInstanceOf[Function2[Int,Int,Int]]
	res28: Boolean = true

可以看出sumFuction实际上Function2的一个实例而已,因此可以将以上函数定义为一个变量
	scala> var sumFunction=new Function2[Int,Int,Int] {
    
    
	     |     override def apply(v1: Int, v2: Int): Int = v1+v2
	     |   }
	sumFunction: (Int, Int) => Int = <function2>
	scala> sumFunction(1,2)
	res31: Int = 3
	
也就意味着(T1,T2)=>R表示Function2类型进一步证实了(Int, Int) => Int就是Function2[Int,Int,Int]一种变体形式。
因此可以得到这么个结论
	scala> def sum(x:Int,y:Int):Int={
    
    
	     |     x+y
	     |   }
等价:
	scala> class SumFunction extends  Function2[Int,Int,Int] {
    
    //第三个参数为返回值
	     |   override def apply(v1: Int, v2: Int): Int = {
    
    
	     |     v1+v2
	     |   }
	     | }
等价:
scala> class SumFunction extends  ((Int,Int)=>Int) {
    
    
     |   override def apply(v1: Int, v2: Int): Int = {
    
    
     |     v1+v2
     |   }
     | }
defined class SumFunction

等价:
scala> var sumFunction:(Int,Int)=>Int = (x:Int,y:Int)=> x+y
sumFunction: (Int, Int) => Int = <function2>

即:
   var f1:Function2[Int,Int,Int]= (x,y)=>x +y
   var f2:(Int,Int)=>Int = (x,y)=>x +y

8.2 偏函数 PartitalFunction

	偏函数:处理指定类型的数据,多用于集合处理中。
	定义一个函数,而让它只接受和处理其参数定义域范围内的子集,对于这个参数范围外的参数则抛出异常,这样的函数就是偏函数(顾名思异就是这个函数只处理传入来的部分参数)。
	
	偏函数是个特质其的类型为PartialFunction[A,B],其中接收一个类型为A的参数,返回一个类型为B的结果。
	
	class MyPartialFunction extends PartialFunction[Any, Int]{
    
    
	  override def isDefinedAt(x: Any): Boolean = {
    
    
	     x.isInstanceOf[Int]
	  }
	
	  override def apply(v1: Any): Int = {
    
    
	    v1.asInstanceOf[Int] * 2
	  }
	}

	object MyPartialFunction{
    
    
	  def main(args: Array[String]): Unit = {
    
    
		    var pf=new MyPartialFunction
		    println( pf1("111"))//报错

			    var pf2:PartialFunction[Any,Int]={
    
    
		      case x:Int => x*2
		    }
		   println( pf2("111"))
	  }
	}

偏函数等价写法:(只处理指定类型的数据)
		var a=Array(1,2,3,"a","b")
		a.collect(
		{
    
    case x:Int => x*2}
		)
		for(item <- a;if(item.isInstanceOf[Int])){
    
    
		 yield item.asInstanceOf[Int]*2
		 }

九、异常处理

 Java异常处理:
 	如果有异常发生,catch子句是按次序捕捉的。因此,在catch字句中,越具体的异常越要靠前,越普遍的异常越靠后。
    如果抛出的异常不在catch子句中,该异常则无法处理,会被升级到调用者处。
    
Scala异常处理:
	借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列case子句
	在Scala中并不会检查捕获异常的顺序,Scala并不区分运行异常和以检查异常。
	finally 语句用于执行不管是正常处理还是有异常发生时都需要执行的步骤
	 	try {
    
    
	    //var i: Int = 10 / 0
	    throw new java.io.IOException()
	} catch {
    
    
	    case  e: ArithmeticException => {
    
    
	        println("e1:"+e.getMessage)
	    }//捕捉异常顺序没有限制
	    case  e: Exception => {
    
    
	        println("e2:"+e.getMessage)
	    }
	}finally {
    
    
    println("finally")
}
	
	//不区分运行异常和以检查异常
  	throw new java.io.IOException()



十、Scala导包

导入具体的一个包:
	import java.util.Date
导入特定的一个包下的几个类:
	import java.util.{
    
    Date, HashMap}
导入一个包下所有的类:
	import java.util._
当一个类中存在命名冲突,可以起别名:Scala中的hashMap与java中的Map
	import scala.collection.mutable.HashMap
	import java.util.{
    
    HashMap=>JHashMap}
		val jmap = new JHashMap[String,Int]()
		jmap.put("aa",1)
		println(jmap.get("aa"))
		
		val map = HashMap(("aa",1))
		println(map.get("aa").getOrElse(0))

十一、隐式传值\隐式转换

3.1 隐式值获取

使用implicitly[类型],必须保证当前上下文有且仅有一个隐式值类型,一般这种隐式值变量的声明写在object单例类或者伴生对象中。
	object MyImplicits {
    
    
		implicit val i:Int=2 //用作隐式值注入
		implicit val s:String="Hello" //用作隐式值注入
	}
主函数中使用:
	object testImplicits {
    
    
	  def main(args: Array[String]): Unit = {
    
    
		import com.sxxd.demo12.MyImplicits._
		val b=implicitly[Int] //当前类文件中,只能有一个隐式值类型
		val ss=implicitly[String] //当前类文件中,只能有一个隐式值类型
		
		println("b:"+b+"\tss:"+ss)
		}
	}


3.2 隐式注入值

	要求隐式注入的值一般都会写成柯理化形式并且保证需要隐式注入的值写在最后。
		
object Myimplicit {
    
    
  implicit val s: String = "Hello" //用作隐式值注入
}

	object testImplicit2 {
    
    
	  def main(args: Array[String]): Unit = {
    
    
	  import com.sxxd.demo15_Exception.Myimplicit._
	    sayholle("zhangsan")
	    sayholle("zhangsan")("不好")
	
	    sayholle2("buhao","lisi")
	    sayholle2(implicitly[String],"zhansgan")
	  }
	  //柯里化写法
	  def sayholle(name:String)(implicit msg:String): Unit ={
    
    
	    println(name +"&"+msg)
	  }
	  //当implicit放置在参数上时候,只能放在第一参数上。
	  def sayholle2(implicit msg:String,name:String): Unit ={
    
    
	    println(name +"&"+msg)
	  }
	}
consol:
	zhangsan&Hello
	zhangsan&不好
	lisi&buhao
	zhansgan&Hello

3.3 隐式参数转换

	该方式是通过隐式转换将参数不满足的类型转为所需类型,Scala在编译代码的时候,先尝试正常编译
如果发现编译类型不匹配,会尝试加载当前上下文中是否存在该类型和目标类型的一种隐式
转换(这种转换严格意义上应该必须唯一,否则编译器会提示错误警告,并不影响执行),如果存在则编译通过.
	
object MyImplicits {
    
    
  implicit def str2Date(s:String):Date={
    
    
    val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    sdf.parse(s)
  }
}
object testImplicit2 {
    
    
  def main(args: Array[String]): Unit = {
    
    
    import com.sxxd.demo15_Exception.Myimplicit._
    def tellTime(date: Date): Unit = {
    
    
      println(date.toLocaleString)
    }
    
    tellTime(new Date())
    tellTime("2019-06-26 10:43:00")
  }
}


3.4 隐式方法增强

	该方式是通过隐式转换将类的方法进行增强处理,当对目标对象调用不存在的方式时候,Scala会尝试加载当前上下文中是否存在该类的隐式
增强类(这种转换严格意义上应该必须唯一,否则编译器会提示错误警告,并不影响执行),如果存在则编译通过。

/**
  * (1)、声明一个类 pig --拥有方法 吃、睡 --不会飞
  *
  */
class Pig(var name: String) {
    
    
  def eat(): Unit = {
    
    
    println(s"$name eat")
  }

  def sleep(): Unit = {
    
    
    println(s"$name sleep")
  }
}
//增强一个发方法
object Myimplicit {
    
    
  //  给pig 隐式增强方法--声明一个隐士类 (限定泛型)
  implicit class PigImplicits(pig: Pig) {
    
    
    def fly(): Unit = {
    
    
      println(pig.name  + " 会飞!")
    }
  }
}
//使用 隐式方法增强 猪会飞的方法。
object testImplicit2 {
    
    
  def main(args: Array[String]): Unit = {
    
    
    import com.sxxd.demo15_Exception.Myimplicit._
    // 测试猪会飞 隐式方法增强
    val pig = new Pig("佩奇")
    pig.eat()
    pig.sleep()
    pig.fly()
  }
}

十二、Scala 泛型

12.1 <: 设置上边界

//表示只可以传递Dog或者Dog的子类
class Keeper[U <: Dog] {
    
    
  def keep(u:U):Unit={
    
    
    println(u)
  }
}

12.2 >: 设置下边界

//表示设置下边界, 泛型只允许设置Dog或者是Dog的父类
class Keeper[U >: Dog] {
    
    
  def keep(u:U):Unit={
    
    
    println(u)
  }
}

12.3 <%视图限定

	视图限定将会在后续版本移除,主要意思是指必须保证上下文中有能够提供一个隐式转换T <% U能够将T隐式转为U类型,如下所示要求上下文中能够尝试将一个String类型隐式转换为Date类型。
/**
  * 隐式传值\隐式转换
  */
object MyPredefs {
    
    
  implicit def str2Date(s:String):Date={
    
    
    var sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    sdf.parse(s)
  }
}
//将String看成一个Date,从而调用Date的方法。--视图限定
object TestFanXing {
    
    
  def main(args: Array[String]): Unit = {
    
    
	import com.sxxd.demo13.MyPredefs._
	sayTime("2019-06-26 14:51:00")
	}
def sayTime[String <% Date](date:String):Unit={
    
    
    println(date.getTime)
}
}

12.4 T:A上下文绑定

表示上下文中必须存在这种隐式值A[T]隐式值,否则程序编译出错.
这样可以在上下文中还没有隐式值得时候确保方法能编译成功。
	class User[T] {
    
    
		  def sayHello(t:T): Unit ={
    
    
		    println(t)
		  }	
	}

	object MyPrrdefs {
    
    
	  implicit val u1 = new User[Int]()
	}

	object TestFanxing {
    
    
	  def main(args: Array[String]): Unit = {
    
    
	    import com.baizhi.demo17.MyPrrdefs._
	    sayInfomation(21)
	  }
	  def sayInfomation[T:User](msg:T)(implicit u:User[T]):Unit={
    
    
	    u.sayHello(msg)
	  }
   }	


12.5 +A协变

class Covariant[+T](t:T) {
    
    
}//小给大

val c1 = new Covariant[Dog](new Dog("小狗"))
val c2 = new Covariant[SmallDog](new SmallDog("小狗",true))
var c3:Covariant[Animal]= c1  //狗赋值给Animal
var c4:Covariant[Animal]= c2

12.6 -A逆变

class Covariant[-T](t:T) {
    
        
}//大的赋值给小的

val c1 = new Covariant[Dog](new Dog("小狗"))
val c2 = new Covariant[SmallDog](new SmallDog("小狗",true))
var c3:Covariant[SmallDog]= c1
var c4:Covariant[Dog]= c2 //error

12.7 A不变

	class Covariant[T](t:T) {
    
    
	}  //强制

	val c1 = new Covariant[Dog](new Dog("小狗"))
	val c2 = new Covariant[SmallDog](new SmallDog("小狗",true))
	var c3:Covariant[SmallDog]= c1//error
	var c4:Covariant[Dog]= c2     //error
	var c5:Covariant[Dog]= c1
	var c6:Covariant[SmallDog]= c2
	

猜你喜欢

转载自blog.csdn.net/weixin_44809337/article/details/110097795