大数据编程之Scala语言

Scala面试

Scala声明变量推荐使用val
  Scala是一种强类型语言,使用前变量的类型必须确定,编译器将语法补全,代码可以简化
  能推断出变量的类型,那么这个类型可以省略
 Java中变量的初始化可以在执行前完成,不需要必须在声明时完成
 Scala在声明变量的同时需要初始化变量
1. Scala开发环境搭建
2. 变量和数据类型
(1) 掌握var和val的区别
可变变量使用关键字var进行声明   值可以发生变化
object ScalaVariable {
    def main(args: Array[String]): Unit = {
        var username : String = "zhangsan"
        username = "lisi" // OK
        username = true // Error
    }
}
不可变变量使用关键字val进行声明,类似于Java语言中的final关键字,不可变化,不等同于常量,实际上还是变量
object ScalaVariable {
    def main(args: Array[String]): Unit = {
        val username : String = "zhangsan"
        username = "lisi" // Error
        username = true // Error
    }
}

补充: 常量也称为字面量,常量的计算在百年有意识就已经完成了
(2)掌握数据类型(Byte Short Int Long Float Double Char Boolean )之间的转换关系
Any
	AnyVal
		浮点型
			Double
				64位,双精度浮点数
			Float
				32位,单精度浮点数
		整型
			Long
				64Int
				32位,-21E~21E
			Short
				16位,-3W2~3W2
			Byte
				8位,-128127
		Boolean
		Char
		StringOps
		Unit
			表示无值,和其他语言中的void等同,只有一个实例()
	AnyRef
		Scala collections
		all java classes
		Other Scala classes
		备注:Null为所以引用对象的子类,只有一个实例null
	备注
		Nothing是所有类型的子类
类型转换:
	规则
		小转大,自动转
		大转小,需强转

	自动类型转换(implicit conversion)
		细节:
		多种类型混合运算时,自动将所有数据转为最大的
		(byte, short) 和 char之间不会相互自动转换
	强制类型转换
		用法
			.toXxx
scala是完全面向对象的语言,所有的类型都提供了toString方法,可以直接转换为字符串
	lon.toString
	val i = 10
	val s = "hello " + i

Scala数据类型

3. 流程控制
if-else
if(布尔表达式) {
   // 如果布尔表达式为 true 则执行该语句块
}
if(布尔表达式) {
   // 如果布尔表达式为 true 则执行该语句块
} else {
   // 如果布尔表达式为 false 则执行该语句块
}
object ScalaBranch {
    def main(args: Array[String]): Unit = {
        val age = 30
        val result = if ( age < 18 ) {
            "童年"
        } else if ( age <= 30 ) {
            "青年"
        } else if ( age <= 50 ) {
            "中年"
        } else {
            "老年"
        }
        println(result)
   }
}
for
for ( 循环变量 <- 数据集 ) {
	循环体
}
while
while( 循环条件表达式 ) {
    循环体
}
do {
    循环体
} while ( 循环条件表达式 )
break与continue
scala是完全面向对象的语言,所以无法使用break,continue关键字这样的方式来中断,或继续循环逻辑,而是采用了函数式编程的方式代替了循环语法中的break和continue
object ScalaLoop {
    def main(args: Array[String]): Unit = {
        scala.util.control.Breaks.breakable {
            for ( i <- 1 to 5 ) {
                if ( i == 3 ) {
                    scala.util.control.Breaks.break
                }
                println(i)
            }
        }
    }
}

补充: 九层妖塔练习
        *
       ***
      *****
     *******
    *********
   ***********
  *************
 ***************
for(i<-0 to 8){
	Print(“ ”*(8-i)+** (2*i+1))
}
4. 函数式编程
1. 面向对象(个体),将个体的特性抽取出来为类,静态的和对象无关,Object模拟静态语法,	为对象
Java可以用反射封装框架
	函数:function(功能),考虑的时封装,重复使用
		可以嵌套封装
		方法也是函数,但函数不是方法
		方法声明在类中,类中声明的函数就是方法
		函数可以声明在任何地方,函数的声明等同于方法的声明
		方法中可以声明函数,函数中不能声明方法
2. 基本语法:
	[修饰符] def 函数名 ( 参数列表 ) [:返回值类型] = {
    函数体
	}
	private def test( s : String ) : Unit = {
    	println(s)
	}

	在编译时,Scala采用的是私有静态方法来声明,函数是有作用域的,Scala会将函数的名称进行修改,方法名不修改,避免冲突
	Scala中的函数不能重载,在同一个作用域中,相同名称的函数只能有一个

3. 至简原则: 能省则省
	(1)省略return关键字
	def f2(name : String) : String = {
         "Name :" + name
	}
	//声明函数后,可以将函数体最后一行作为返回值,所以return关键字可以省略
	(2)省略花括号
	object ScalaFunction {
    	def main(args: Array[String]): Unit = {
        	def fun2(): String = "zhangsan"
    	}
	}
	//只有一行逻辑代码的情况下,可以省略花括号
	(3)省略返回值类型
	object ScalaFunction {
    	def main(args: Array[String]): Unit = {
        	def fun3() = "zhangsan"
    	}
	}
	//如果函数可以自动推断返回值类型,那么返回值类型可以省略
	object ScalaFunction {
    	def main(args: Array[String]): Unit = {
       		def fun5(): String = {
            	return "zhangsan"
        	}
            println(fun5())
        }
	}
	//如果函数体中有明确的return语句,那么返回值类型不能省略
	object ScalaFunction {
    	def main(args: Array[String]): Unit = {
        	def fun5(): Unit = {
            	return "zhangsan"
        	}
        	println(fun5())
    	}
	}
	//如果函数体返回值类型明确为Unit, 那么函数体中即使有return关键字也不起作用
	object ScalaFunction {
    	def main(args: Array[String]): Unit = {
        	def fun5() {
            	return "zhangsan"
        	}
        	println(fun5())
    	}
	}
	//如果函数体返回值类型声明为Unit, 但是又想省略,那么此时就必须连同等号一起省		略
	(4)省略参数列表
	object ScalaFunction {
    	def main(args: Array[String]): Unit = {
        	def fun4 = "zhangsan"
        	fun4// OK
        	fun4()//(ERROR)
    	}
	}
	//如果参数列表没有参数,那么参数列表的括号可以省略
	//如果函数的参数列表已声明,那么调用时可以使用小括号,也可以不使用
	//如果函数的参数列表未声明,那么调用时不能使用小括号
	(5)省略等号
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
            def fun5() {
                return "zhangsan"
            }
            println(fun5())
        }
    }
    //如果函数体返回值类型声明为Unit, 但是又想省略,那么此时就必须连同等号一起省		略
	(6)省略名称和关键字
	//如果只关心逻辑,而不关心方法名称,那么函数名称可以省略,def关键字也可省略
		()->{println("xxxxxxxx")}
	(7)匿名函数
	//匿名函数
	val f9 = (i : Int)=>{println("xxxxx")}
4. 高阶函数
	将函数当成一个类型来使用
(1)函数作为值
    object ScalaFunction {
       def text(): Unit ={
         //   println("aaa")
          }
        val f = text
        val f1 = text _   //将函数作为值
        val f2 :()=>Unit = text   //将函数作为值
    //    println(f)  //() 函数值
    //    println(f1)  //地址值  函数
    //    println(f2)  //地址值  函数
        }
    }
(2)将函数作为参数
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
            def fun2( i:Int ): Int = {
                i * 2
            }
            def fun22( f : Int => Int ): Int = {
                f(10)
            }
            println(fun22(fun2))
        }
    }
(3)函数作为返回值
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
          //3. 函数作为返回值
        def text3(): Unit ={
          println("zzz")
        }
    //    def fun1 () ={
    //      text3 _
    //    }
        def fun1(): ()=>Unit ={
            text3
        }
        //    val v = fun1()
        //    v()
              fun1()()
              //嵌套函数  给函数传2个参数,参数计算逻辑不清楚,
            def outer(x:Int) ={
              def middel(y:Int) ={
                def inner(f:(Int,Int)=>Int)={
                  f(x,y)
                }
                inner _  //使inner在外面使用
              }
              middel _  //使middel可以在外面调用
            }

            outer(10)(20)((x:Int,y:Int)=>{x+y})
            //简化
        println(outer(10)(20)(_ + _))
       outer(10)(20)((x: Int, y: Int) => {
          x * y
        })
        println(outer(10)(20)(_ * _))

        }
    }
(4)匿名函数
(5)将函数作为对象
    def text4(): Unit ={
      println("zzzz")
    }
    def fun2() ={
      text4 _
    }
    fun2()()
(6)控制抽象
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
            def fun7(op: => Unit) = {
                op
            }
            fun7{
                println("xx")
            }
        }
    }
    //参数是函数,函数参数没有输入值也没有返回值
(7)闭包
		如果函数中使用外部变量,为了防止变量数据丢失,将变量包含到函数的内部,形	成闭合的效果,形成闭包,改变变量的生命周期
	闭包就是一个函数和与其相关的引用环境(变量/值)组合的一个整体(实体)// 一个函数如果访问外部变量,需要将变量包含到函数的内部,改变这个变量的生命周期
    // 形成一个闭合的环境,这个闭合的环境称之为闭包.
    // TODO 闭包的产生
    //  1. 内部函数返回到外部使用
    //  2. 函数访问外部的变量,并改变其生命周期
    //  3. 将函数作为对象使用
    //  4. 所有的匿名函数都是闭包
    def outer1(x:Int)={
            def inner(y:Int) ={
              x+y
            }
            inner _
          }
        //outer1(10)(20)
        val r = outer1(10)
        println(r(20))
(8)函数柯里化
(9)递归函数
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
            def fun8(j:Int):Int = {
                if ( j <= 1 ) {
                    1
                } else {
                    j * fun8(j-1)
                }
            }
            println(fun8(5))
        }
    }
    //1.方法实现时调用自己.
    //2.存在跳出递归的逻辑
    //3.传递的参数之间应该存在规律
    //4.递归函数必须声明返回值类型
    //Scala中,递归函数不能省略返回值类型
(10)惰性函数
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
            def fun9(): String = {
                println("function...")
                "zhangsan"
            }
            lazy val a = fun9()
            println("----------")
            println(a)//要使用a前才执行
        }
    }
    //当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函		数才会执行。这种函数我们称之为惰性函数。lazy不可修饰var型变量
5. 匿名函数
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
            def fun4( f:Int => Int ): Int = {
                f(10)
            }
            println(fun4((x:Int)=>{x * 20}))
            println(fun4((x)=>{x * 20}))
            println(fun4((x)=>x * 20))
            println(fun4(x=>x * 20))
            println(fun4(_ * 20))
        }
    }

6. 函数柯里化
	柯里化指的是将原来接受多个参数的函数变成新的接受一个参数的函数的过程, 
​	新函数的参数接受原来的第二个参数为唯一参数
​	如果有n个参数, 就是把这个函数分解成n个新函数的过程 
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
            def fun6(i:Int)(j:Int) = {
                i * j
            }
        }
    }
    //可以将完整的参数列表进行拆分,参数之间是独立的		
7. 函数参数
    object ScalaFunction {
        def main(args: Array[String]): Unit = {
            def fun2( i:Int ): Int = {
                i * 2
            }
            def fun22( f : Int => Int ): Int = {
                f(10)
            }
            println(fun22(fun2))
        }
    }
5. 面向对象
(1)Scala与Java继承方面的区别
继承
	实例
		isInstanceOf    判断对象是否为指定类的对象
		asInstanceOf    将对象转换为指定类型
		classOf     精确的获取类
	子类与父类
		类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是间接调用)
		只有主构造器可以调用父类的构造器。辅助构造器不能直接调用父类的构造器。在Scala的构造器中,你不能调用super(params)
	动态绑定机制
		当调用对象方法的时候,该方法会和该对象的内存地址绑定
		当调用对象属性时,没有动态绑定机制,哪里声明,那里使用
	匿名子类
	通过包含带有定义或重写的代码块的方式创建一个匿名的子类
class Person {
}
class User extends Person {
}
//和Java一样,Scala中的继承也是单继承,且使用extends关键字。
//构造对象时需要考虑构造方法的执行顺序
(2)单例对象(伴生对象)
JAVA单例模式: 一个类对外只提供一个对象,不能让外界直接实例化该类对象.

	步骤: 1. 构造器私有化
		 2. 类的内部对外提供一个该类的对象  公共的静态常量或者方法

// TODO Scala 面向对象-- 对象 (堆内存)
   // TODO 获取对象的方法
   //  1.  new
   //  2. 反射
   //  3. 反序列化
   //  4. clone

// 面向对象--单例  -->object
//    	 scala中声明单例对象只需一个关键字即可:object
//      	当前使用的object声明的对象就是单例对象
//       	使用object声明类的时候,可以简单的理解为这个单例对象是伴随着类所产生的对象
//  所以将这个单例对象称为伴生对象,这个类称为伴生类.
//  伴生对象和伴生类如何区分
//  	println(Scala06_Object)伴生对象
//  	println(new Scala06_Object())伴生类对象
//scala没有静态的语法,采用object关键字声明伴生对象,模拟静态语法



伴生类需要通过构建对象来访问其中的属性和方法
而伴生对象可以直接访问其属性和方法,所以一般将静态方法放置在伴生对象中,将成员方法放置在伴生类中
伴生对象是可以直接访问伴生类中的私有内容
如果使用伴生对象来构建伴生类对象的场合,可以自动识别 一个方法 : apply

指定类的对象只能创建一个,而不能创建多个,
这样的对象可以由特殊的设计方式获得,也可以由语言本身设计得到,比如object伴生对象

Scala编译器可以通过伴生对象的apply方法创建伴生类对象。apply方法可以重载,并传递参数,且可由Scala编译器自动识别。所以在使用时,其实是可以省略的。

class User { // 伴生类
}
object User { // 伴生对象
    def apply() = new User() // 构造伴生类对象
}
...
val user1 = new User()// 通过构造方法创建对象
Val user2 = User.apply() // 通过伴生对象的apply方法构造伴生类对象 
val user3 = User() // scala编译器省略apply方法,自动完成调用
(3)特质的用法及功能
1) 基本语法

Scala中没有接口的概念. java 中所有的接口在scala中都当成特质来用

 接口只和当前实现类有关系,和父类,子类没有任何关系

而是采用特殊的关键字**trait**来声明特质

trait在编译时其实就是接口,但是一般会将特质理解为接口和抽象类的结合体

如果一个类符合某一个特征(特质),那么就可以将这个特征(特质)“混入”到类中。这种混入的操作可以在声明类时使用,也可以在创建类对象时动态使用。
//trait 特质名称
//class 类名 extends 父类(特质1) with 特质2 with特质3
trait Operator {

}
trait DB{

}
class MySQL extends Operator with DB{

}

2) 动态混入

如果一个类混入一个特质,那么使用extends关键字进行混入操作
如果一个类有父类,但是又混入特质,采用with关键字进行混入
如果有多个特质需要混入,也采用with
object ScalaTrait{
    def main(args: Array[String]): Unit = {
        val mysql = new MySQL with Operator
        mysql.insert()
    }
}
trait Operator {
    def insert(): Unit = {
        println("insert data...")
    }
}
class MySQL {
}

3) 初始化叠加
object Scala10_Interface_1 {
  def main(args: Array[String]): Unit = {
        // todo 初始化顺序
        //  1. 父类的初始化优先于子类和子类同级的特质初始化
        //  2. 父特质的初始化优先于子特质
        //  3. 同级的特质初始化优先于类
        //  4. 同级的特质和类,那么先混入的特质先初始化,依次类推
        new F()
  }
      trait A {
        println("aaaa")
      }
      trait B {
        println("bbbb")
      }
      trait E {
        println("eeee")
      }
      class C extends B {
        println("cccc")
      }
      class D extends C with E {
        println("dddd")
      }
      class F extends B with A with E {
        println("ffff")
  }
}
new F()		new D()
//bbbb		bbbb
//aaaa		cccc
//eeee		eeee
//ffff		dddd
4) 功能叠加
object Scala10_Interface_2 {
  def main(args: Array[String]): Unit = {
    //todo 特质的扩展功能
    // 扩展功能 - 初始化顺序 - 从左到右
    // 扩展功能 - 执行顺序   - 从右向左
      new MySQL().oper()

    }
    trait Operate {
      def oper(): Unit = {
        println("操作数据")
      }
    }
    trait DB extends Operate {
      override def oper(): Unit = {
        print("向数据库中")
        super[Operate].oper()
      }
    }
    trait Log extends Operate {
      override def oper(): Unit = {
        print("向日志文件中")
        super.oper()
      }
    }
    class MySQL extends Log with DB {
    }
  }

6. 集合
bject Scala01_Collection {
//TODO 集合
  /*java:
      1.list  ==>有序的,数据可重复
      2.set   ==>无序的,数据不可重复
      3.map   ==>KV键值对  (Entry  Node) 无序,key不可重复,value可重复
   */
  //TODO scala集合三大类 所有集合都扩展自 Iterable 特质,
  // 并提供可变和不可变版本,默认不可变集合
//   1. Seq=>序列 -->有序的
//   2. set=>集   -->无序的
//   3. map=>映射(转换) -->KV键值对
  //scala同时提供了可变和不可变两种版本,可变集合可以在适当地方扩展或更新,即修改添加移除集合中的元素
  //不可变集合仍然可以模拟添加,移除,更新元素. 但是会返回一个新的集合,原来的集合不会发生改变.
  //不可变指的是集合的内存地址不可变, 而不是集合本身.例如:string stringBuffer stringBuilder
  //可变和不可变根据集合所在包名进行区分
  //scala.collection.immutable  不可变集合

  //scala.collection.mutable    可变集合

}

(1)不可变数组
    object Scala02_Array {



      //TODO 集合--数组Array-- 不可变数组
    def main(args: Array[String]): Unit = {
      /*
          Object[] ss = new Object[3]
          ss[0] = "zhangsan"

         */

      // todo 构建集合 - 数组
      //  数组访问时,中括号需要改为小括号
      //  构建数组时,应该设定数组的长度,以及数组中容纳的元素的类型
      //  数组在编译时,会自动编译为java的数组
      // todo 数组定义
      val array = new Array[String](3)
      println(array.length)//  3
      // todo 数组赋值
      array(0) = "zhangsan"
      //println(array(0))
      array(1) = "lisi"
      array(2) = "wangwu"

      // todo 操作数据
      //todo 修改某个元素的值 -->update
      array.update(0, "zhaoliu")

      //println(array(0))

      // todo 遍历数据
       //todo 遍历1->普通遍历
      for ( i <- array ) {
          println(i)
      }

        // todo 遍历2-->查看数组
      println(array.mkString(","))

      // TODO 遍历3  foreach方法需要传递一个参数,这个参数的类型是一个函数类			型: String=>U
      // foreach方法可以将集合中的每一条数据进行处理,这个处理的逻辑是作为参数从		外部传递

      def foreachFuntion( s:String ): Unit = {
        println(s)
      }
      //        array.foreach(foreachFuntion)
      //        array.foreach(
      //            ( s:String ) => {
      //                println(s)
      //            }
      //        )
      //
      //        array.foreach(
      //            ( s:String ) => println(s)
      //        )
      //
      //        array.foreach(
      //            ( s ) => println(s)
      //        )
      //
      //        array.foreach(
      //            s => println(s)
      //        )
      array.foreach(println(_))
      array.foreach(println)
    }

    }
(2)可变数组
    object Scala02_Array_2 {
    //TODO 集合--可变数组Array
    def main(args: Array[String]): Unit = {
          //val buffer = new ArrayBuffer[String]()
          val buffer1 = ArrayBuffer(1,2,3,4)
          val buffer2 = ArrayBuffer(1,2,3,4)

          // 基本操作
    //   添加   添加集合
          buffer1.append(5, 6, 7, 8)
          buffer1.appendAll(buffer2)
    //  插入
          buffer1.insert(2, 9, 0)
    //  修改
          buffer1.update(0, 8)
          buffer1(0) = 8
    //  删除
          buffer1.remove(2)
          buffer1.remove(1,2)


          // 遍历数据

          println(buffer1)

      }
    }
(3)可变和不可变数组之间的转换
    import scala.collection.mutable
    import scala.collection.mutable.ArrayBuffer
    object Scala02_Array_3 {
      //TODO 集合--可变数组Array
      def main(args: Array[String]): Unit = {
        // TODO 集合 - 可变数组和不可变数组的转换
        val array = Array(1, 2, 3, 4)
        val buffer = ArrayBuffer(5, 6, 7, 8)
        // 不可变数组 => 可变数组
        val buffer1: mutable.Buffer[Int] = array.toBuffer
        // 可变数组 => 不可变数组
        val array1: Array[Int] = buffer.toArray
      }
    }
7. 模式匹配

8. 异常

9. 隐式转换

10. 泛型

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值