Scala
1、Scala简介
1.1Scala的介绍
- scala是一门多范式的编程语言
- Scala是把函数式编程思想和面向对象编程思想结合的一种编程语言
- 大数据计算引擎spark是由Scala编写的
1.2Scala的特性
1.2.1多范式
1.2.1.1面向对象特性
Scala 是一种高度表达性的编程语言,它结合了面向对象编程和函数式编程的最佳特性
- 类和对象:Scala支持类和对象,可以定义属性和方法。
- 继承和多态:支持类的继承和多态,可以创建层次结构和重用代码。
- 抽象类:可以定义抽象类,用于定义接口和实现部分行为
- 封装:支持访问控制修饰符(public,protected,private),实现数据的封装
1.2.1.2函数式编程
- 高阶函数:函数可以作为参数传递给另一个函数,或者从另一个函数返回。
- 不可变性:默认使用不可变数据结构,提高代码的并发安全性。
- 模式匹配:提供强大的模式匹配功能,可以解构复杂数据结构,进行条件判断。
1.2.2兼容JAVA
- 类库调用
- 互操作
1.2.3语法简洁
- 代码行短
- 类型推断
- 抽象控制
1.2.4静态类型化
- 可检验、安全重构
1.2.5支持并发控制
- 强计算能力、自定义其他控制结构
1.3面向函数式编程和面向对象编程的区别
- 在面向对象编程中,我们把对象传来传去,那在函数式编程中,我们要做的是把函数传来传去,而这个,说成术语,我们把他叫做高阶函数。
- 在函数式编程中,函数是基本单位,,他几乎被用作一切,包括最简单的计算,甚至连变量都被计算所取代。在函数式编程中,变量只是一个名称,而不是一个存储单元,这是函数式编程与传统的命令式编程最典型的不同之处。
1.4Scala和Java的编译过程
- 以Scala结尾的文件和以Java结尾的文件都会通过编译之后生成 .class文件,
- 并且由于Scala是基于Java的,因此两者编译之后产生的 .class文件是一样的
- 然后相应的 .class文件会在JVM上运行,产生最终的结果
2、Scala的相关基础用法
注意事项
-
1、如果需要是可运行文件就必须将class改成object
-
2、如果是class仅仅代表的是一个类,如果是object就代表的是一个单例对象
-
3、在Scala中,编写完一句代码结尾不需要加上";"
-
4、Scala文件中可以任意的使用Java的类和方法
Scala的第一个代码,hello world
object demo01HelloWord {def main(args: Array[String]): Unit = {println("hello world")}
}
2.1变量与常量
2.1.1变量
变量: 在程序运行过程中其值可能发生改变的量叫做变量。
object Demo02base {def main(args: Array[String]): Unit = {/*** 定义变量* 注意:* 1、变量一旦定义类型就确定了,可以不用手动指定变量的类型,Scala会根据赋予的值自动推断出其类型* 2、也可以手动的指定变量的数据类型,如:var 变量名:数据类型=值** Scala中的数据类型和Java数据类型的对应关系* Java: scala:* byte Byte* short Short* int Int* long Long* float Float* double Double* boolean Boolean* char Char*/var a1=100println(a1)//获取a1的数据类型println(a1.getClass)//类型不一致无法直接转换a1的值
// a1="hello"
// println(a1)//类型一致可以直接改变变量的值a1=200println(a1)//定义一个整数类型的完整写法var a2:Int=100println(a2)println(a2.getClass)// * 其实是一个函数,底层是通过StringBuilder链接字符的//简化写法将.和()省略println("="*50)println("=".*(50))}
}
2.1.2常量
在程序运行过程中其值不会发生变化的量叫做常量
object Demo03base {def main(args: Array[String]): Unit = { /*** 定义常量:在Scala中定义一个常量,需要使用关键字:val*/val a3:Int=50println(a3)//常量的值一旦定义就无法改变
// a3=20}
}
2.2字符串
scala中的字符串String类和Java中的String类是共同的一个字符串类
Java中字符串的功能在Scala中正常使用
object Demo04base {def main(args: Array[String]): Unit = {var s3:String="hello,world,java,shujia,scala"val arr1: Array[String] = s3.split(",")//直接打印使用逗号切分的数组,打印的是该数组的地址值println(arr1)//Scala中的数组和Java的数组一致,具有索引且从0开始println(arr1(0))println(arr1(1))println(arr1(2))println(arr1(3))println(arr1(4))/*** scala中的字符串拼接方式:* 1、直接使用+号,这种拼接方式比较消耗性能* 2、使用String Builder的append方法* 3、使用Scala特有的函数mkString,该方法的前提是有一组序列* 4、使用Scala特有的字符串传递方法 s"${变量}" 该方法的底层是使用String Builder方式拼接的*/var q1:String="hello"var q2:String="world"var q3:String="java"//方式1val res1: String = q1 + "|" + q2 + "|" + q3print(res1)//方式2val sb: StringBuilder = new StringBuilder()sb.append(q1).append("-").append(q2).append("-").append(q3)println(sb)//方法3:指定字符串的分隔符val res2: String = arr1.mkString("|")println(res2)//方法4val res3: String = s"${q1.toUpperCase()}#${q2}#${q3}"println(res3)}}
2.3scala的运算符
import java.util.Scanner
import scala.util.control.Breaks._object Demo03 {def main(args: Array[String]): Unit = {/*** scala中的运算符*/var x:Int=3var y:Int=4//这些运算符在Scala中其实都是函数println(x+y)println(x-y)println(x*y)println(x/y)println(x%y)//x乘以1.0之后其数据类型就上升为了double,故结果就会是double类型println(x*1.0/y)println("hello"+4)}
}
2.4条件语句
条件语句分为:
1、选择语句:if
2、循环语句:while,break
- if语句
//条件语句if
val sc: Scanner = new Scanner(System.in)
println("请输入年龄:")
val age: Int = sc.nextInt()
if(age>18){println("old")
}else{println("young")
}
- while循环
注意:
1、在Scala语言中,没有++或者--的语法,只有i+=1 或者i-=1
2、在Scala语言中,不存在和Java一样的普通for循环
3、Scala中的for循环写法不一样
//Scala中值存在下面的for循环写法
for(e<-arr1){println(e)
}/*** while循环*/
var i:Int=0
while (i<arr1.length){println(arr1(i))i+=1
}/*** 需求:在控制台中输出10行hello world*/
var j:Int=1
while(j<=10){println("hello world")j+=1
}//使用for循环
for(e<-1 to 10){println(e)
}for(e<-1 until 10){println(e)
}
- 流程控制语句
注意:在scala中没有break或者continue关键字,但是存在breakable
breakable{for(e<-1 to 10){if(e==5){// 底层实现是一个函数,抛出一个异常,终止程序运行break}println(e)}
}
println("hello")
2.5 Scala中的IO流
注意:对于Scala来说,不存在写文件的方式,有读取文件的方式
-
采用Java中写文件的方式写入,如果文件不存在,则会自动进行创建
-
但是对于读文件,如果文件不存在时会报错
package com.shujia.jichuimport java.io.{BufferedReader, BufferedWriter, FileReader, FileWriter}
import scala.io.{BufferedSource, Source}
object Demo03base3 {def main(args: Array[String]): Unit = {/*** scala中的读取文件的方式* Source.fromFil 底层是使用了字节输入流读取数据FileInputStream*/val bs: BufferedSource = Source.fromFile("scala/data/words.txt")val iterator: Iterator[String] = bs.getLines()while (iterator.hasNext){val str: String = iterator.next()println(str)}//使用for循环的方法for(e<-bs.getLines()){println(e)}val bw: BufferedWriter = new BufferedWriter(new FileWriter("scala/data/words3.txt"))bw.write("hello shujia")bw.newLine()bw.write("java")//刷写进入文件bw.flush()}
}
2.6异常处理
- Scala中的异常处理和Java中的类似
object Demo04Exception {def main(args: Array[String]): Unit = {try{println(0/0)//如果上面的错误没有被抛出,使用catch的方式处理,那么下面的语句不会执行val arr1: Array[Int] = Array(1, 2, 3, 4)println(arr1(4))}catch{//相当于sql语句中的case whencase e:ArithmeticException=>println("除0异常")e.printStackTrace()case e:ArrayIndexOutOfBoundsException=>println("数组越界")e.printStackTrace()case _ =>println("出现异常")}finally {//今后finally中的处理大部分情况下都与释放资源有关println("finally")}}
}//上面是对异常进行捕获的方式,也可以对异常进行抛出
val sc: Scanner = new Scanner(System.in)
println("输入除数:")
val css: Int = sc.nextInt()
if (css != 0) {println(10 / css)
} else {throw new ArithmeticException("除数为0")
}
2.7函数
/*** def: 定义函数或者方法的关键字* main: 是函数或者方法的名字,符合标识符的命名规则* args: 函数形参的名字* Array[String]: 参数的数据类型是一个元素为字符串的数组* =: 后面跟着函数体* Unit: 等同于java中的void 表示无返回值的意思*** def main(args: Array[String]): Unit = {** }** 在不同的地方定义,称呼不一样* 函数:在object中定义的叫做函数* 方法:在class中定义的叫做方法*/
object Demo05Function {def main(args: Array[String]): Unit = {//函数def add(a1:Int,b1:Int):Int={return a1+b1}val res3: Int = Demo05Function.add1(100, 200)def fun1(s1:String):Int={return s1.toInt}val res1: Int = add(3, 4)println(res1)def add2(a1:Int,b1:Int):Int={return a1+b1}val d1: Demo01 = new Demo01()val res2: Int = d1.add2(11, 22)println(res2)//object中的函数调用方式一:可以直接通过类名进行调用,类似于静态方法一样val result1: Int = Demo05Function.add1(3, 4)println(result1)//调用方法二:可以省略类名,直接调用val result2: Int = add1(100, 200)println(result2)//方法三:如果方法调用的函数只有一个参数的时候,可以将.和小括号用空格代替调用val result3: Int = Demo05Function fun2 "1000"println(result3)add5}def add1(a1: Int, b1: Int): Int = {return a1 + b1}def fun2(s1: String): Int = {return s1.toInt}/*** 函数的定义格式* 1、函数有返回值,并且最后一句话作为函数的返回值的时候,return关键字可以不写* 2、函数体只有一句话实现时,大括号可以不写* 3、如果函数没有参数时,小括号可以省略不写*///方法一def add3(a1:Int,b1:Int):Int={a1+b1}//方法二def add4(a1:Int,b1:Int):Int=a1+b1//方法三def add5=println("hello")}
class Demo01{def add2(a1: Int, b1: Int): Int = {return a1 + b1}
}
2.8Scala中的函数递归
递归:方法定义时,调用自身的现象
条件:必须存在函数出口
def main(args: Array[String]): Unit = {val res1: Int = jiecheng(5)println(res1)println(s"5的阶乘是${Demo06Function jiecheng (5)}")
}//求数的阶乘
def jiecheng(num:Int):Int={if(num==1){1}else{num*jiecheng(num-1)}
}
2.9Scala中定义类
定义类的三大要素:构造方法,成员方法,成员变量
构造方法:
-
1、在scala中构造方法的编写和在java中不太一样,类所拥有的大括号中都是构造代码块的内容 2、默认情况下,每一个类都应该提供一个无参的构造方法 3、构造方法可以有许多
object Demo07class {def main(args: Array[String]): Unit = {val stu1: student = new student("zhangsan",19)println(stu1)val stu2: student = new student("zhangsan", 18, "nv")println(stu2)//如果调用的是一个函数的无参构造方法,那么小括号可以不用写val stu3: Student2 = new Student2stu3.fun1()//也可以使用多态的方式创建对象//多态:父类引用,指向子类对象val stu4: Object = new student("lisi", 19, "nan")println(stu4.toString)}
}class student(name:String,age:Int){//相当于构造代码块中的内容
// println("hello world")/*** 定义成员变量*/val _name:String=nameval _age:Int=age//下划线表示将来会给其赋予默认值var _gender:String= _/*** 构造方法可以写多个*/def this(name:String,age:Int,gender:String){this(name:String,age:Int)_gender=gender}/*** 也可以重写其方法*/// override def toString:String=super.toStringoverride def toString: String = {"姓名:" + _name + ", 年龄:" + _age + ", 性别:" + _gender}
}class Student2{def fun1()=println("shujia666")
}
2.10样例类
- Scala中非常重要的功能:样例类
- 其最重要的特性是:
- 减少创建类时编写的代码两,只需要定义成员变量即可,
- 样例类会自动扩充成员变量,构造方法,并且自动重写了toString等方法
object Demo08caseClass {def main(args: Array[String]): Unit = {val t1: Teacher = new Teacher("zhangsan", 20, "shuijiao")println(t1.toString)println(t1.name)println(t1.age)println(t1.like)// t1.name="lisi"t1.like="eat"println(t1.like)}}
/*** 样例类中的成员变量,编译后默认是被jvm添加了final关键字,用户是改变不了的* 对于scala来说,默认是被val修饰的* 如果将来想要被改变,定义的时候需要使用var进行修饰*/
case class Teacher(name:String,age:Int,var like:String)
2.11 伴生对象
-
在一个Scala文件中
-
如果一个object对象的名字和定义的class类名一样的话,那么称这个object是该class类的伴生对象 直接在main函数中调用object的名字就相当于调用该object中的apply方法 而一般在这个apply方法中会new创建一个上述的类的对象,便于直接调用
-
object Demo09apply {def main(args: Array[String]): Unit = {//普通使用的方法val book: Book = Book.apply("shujia", 666)println(book)//使用伴生对象的方式,调用object的名字就相当于调用该object中的apply方法val book1: Book = Book("shujia", 666)println(book1)}}object Book{def apply(name:String,price:Int): Book = {new Book(name,price)}
}class Book(name:String,price:Int){val _name:String=nameval _price:Int=priceoverride def toString: String = "书名:" + _name + ", 价格:" + _price
}