Scala和Java的区别
Scala与java不同之处
1. 变量和常量
1.1 定义形式
-
java
变量类型 名称 = 初始值;
final 类型 名称 = 初始值:
-
scala
var 名称 [: 类型] = 初始值 [ ;]
val 名称 [: 类型] = 初始值 [ ; ]
scala中var表示变量,val表示常量。引用类型的常量本身不能改变,带上引用对象的值可以改变。变量的类型可以省略不写,scala能自动推导类型,句尾的l;可选。
1.2 标识符的命名
除java原有规范外增加如下区别:
- 以操作符开头,且只包含操作符(+ - * / # !等)
- 使用反引号(``)包含的任意字符串,包括scala关键字。
2. 字符串输出
-
字符串拼接,使用+。
-
使用C语言类似格式化输出:printf(),%d整数,%f浮点数,%s字符串。
-
字符串模板(插值字符串):通过$获取变量值,println(s"字符串内容");
scala中多行字符串的表示:“”“ 字符串
| 字符串
“”“.stripMargin
3. 键盘输入
java
Scanner in = new Scanner(System.in);
a=in.nextInt(); //输入整形数
b=in.nextInt();
c=in.nextLine(); //字符串
scala
val name = StdIn.readLine() //字符串
val age = StdIn.readInt() //整数
4. 数据类型
scala取消了java的基本数据类型。其他类似java的包装类,Any为所有类的父类,Nothing为所有类的子类。
Unit 表示无值,类似于void,有有实例,写成()。Null 只有一个实例null,Null 可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)。
Byte | 8位有符号补码整数。数值区间为 -128 到 127 |
---|---|
Short | 16位有符号补码整数。数值区间为 -32768 到 32767 |
Int | 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 |
Long | 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 |
Float | 32 位, IEEE 754 标准的单精度浮点数 |
Double | 64 位 IEEE 754 标准的双精度浮点数 |
Char | 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF |
String | 字符序列 |
Boolean | true或false |
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null 或空引用 |
Nothing | Nothing类型在Scala的类层级的最底端;它是任何其他类型的子类型。 |
Any | Any是所有其他类的超类 |
AnyRef | AnyRef类是Scala里所有引用类(reference class)的基类 |
先贴一张官网的类型图
类型之间的转换
-
低精度转高精度自动转,在有混合运算时。
-
高精度转低精度需要强转。
int a = (int)1.2 //java var num:Int = 1.2.toInt //scala
5. 运算符
- equals比较的是值是否相等
- eq比较的是 地址是否相等
- ,如果比较的对象是null,调用的是eq方法,如果比较的对象不是null,==调用的是equals方法
- Scala 中没有++、--操作符,可以通过+=、-=来实现同样的效果;
6.分支 循环
6.1 分支
if、if...else...、if...else if ...else与java完全类似。
另:Scala中的if else表达式其实是有返回值的,返回值取决于满足条件的最后一行代码,取所有分支共同的类祖先,该特性可以实现java的三元表达式,Scala本身没有三元表达式。
val res:String = if (age < 18) "童年" else "成年"
java中的switch-case在scala中通过模式匹配实现
val x: Int = 5
val y: String = x match {
case 1 => "one"
case 2 => "two"
case 3 => "three"
case _ => "other"
}
一目了然,最后的case_相当于java的default
6.2 循环
Scala中while、do...while 、for循环与java类似。
范围数据循环
- to,前后均闭合。to是一个方法,scala是省略点,当只有一个参数时()也可省略
for(i <- 1 to 10 [by 2] ){ // by 步长
println(i)
}
等价于
for(i <- 1.to(10).by(2)){
print(i+" ");
}
- until,前闭后开。
for(i <- 1 until 10) {
println(i)
}
循环守卫
for(i <- 1 to 10 if i != 5) //排查特殊情况,满足守卫条件时执行循环。
循环嵌套
for (i <- 1 to 10;j <- 1 to i){
print(i+"*"+j+"="+i*j)
}
循环中断
Scala 内置控制结构特地去掉了 break 和 continue,是为了更好的适应函数式编程,推
荐使用函数式的风格解决break和continue的功能。
1、循环守卫可以实现continue的功能。
for (i <- 0 to 10 if i%2==0){
println(i+" ")
}
2、抛出异常实现continue的功能,在循环体内捕获异常使后面的代码不再执行。
for(j <- 0 to 10 ){
try{
if(j%2 != 0){
throw new RuntimeException;
}
println(j+" ")
}catch {
case ex: Exception =>
}
}
3、使用抛出异常的方式实现break的功能,在捕获异常后不做任何处理。
try{
for(i <- 0 to 5){
if(i == 3){
throw new RuntimeException
}
println(i);
}
}catch {
case e:Exception=>{}
}
println("这是循环外的内容");
4、抛出异常使用try-catch太麻烦,可以使用Scala中的Breaks类的break方法,对可中断的代码块使用Breaks.breakable包含。
Breaks.breakable(
for(i <- 0 to 5){
if(i == 3){
Breaks.break();
}
println(i);
}
)
5、Scala是一门一切从简的编程语言,怎么结束个循环还要专门麻烦,当然可以简写
对引入Breaks类的时候引入Breaks下所有属性、方法,类似java的*
import scala.util.control.Breaks._
breakable(
for(i <- 0 to 5){
if(i == 3){
break();
}
println(i);
}
)
println("这是循环外的内容");
7 函数式编程
7.1 函数的基本语法
def funName(x:Int,y:String):String={
return s"${x}${y}";
}
说明:
- def 是定义函数的标识
- funName是函数名称
- x,y是参数名
- x,y后的Int,String是x,y的类型
- 括号后的String是函数返回类型,没有返回类型使用Unit,类似void,如果返回值为Unit,函数体内写了return也不起作用
- {}内是函数体,有返回值是如果不写return会把最后一句表达式作为返回值。
7.2 函数中参数的特殊用法
7.2.1 可变参数
def f1(str:String*):Unit={
println(str);
}
f1("小明","小红");
如果有多个参数,可变参数放在最后
7.2.2参数默认值
def f2(name:String="小明"):Unit={
println(s"hello ${name}");
}
f2("小红");
f2();
7.2.3 带名参数
def f3(age:Int,name:String):Unit = {
println(s"${name}今年${age}岁了");
}
f3(20,"小明");
f3(name = "小红",age = 25);
带命参数在部分参数有默认值值是显得尤为重要。
def f3(age:Int=20,name:String):Unit = {
println(s"${name}今年${age}岁了");
}
f3(20,"小明");
f3(name = "小红");
7.3 简化函数
下面懒人的福利来了,scala专门为懒人设计了能省就省的原则。
7.3.1retuen可以省略,函数体的最后一行代码会作为返回值。
def f1(name:String):String = {
name;
}
println(f1("Jeck"))
7.3.2 如果函数体只有一行,{}可以省略
def f2(name:String):String = name;
println(f2("Jeck"))
7.3.3 如果返回类型可以推导出来,返回值类型可以省略
def f3(name:String) = name;
println(f3("Jeck"))
如果函数体有return,返回值类型不能省略。
7.3.4 如果函数没有返回值,等号可以省略。
def f4(name:String){
println(name)
}
f4("Jeck4");
7.3.5 如果函数没有参数,调用时()可以省略
def f5(): Unit ={
println("Hello")
}
f5;
f5();
7.3.5 如果函数没有参数,声明时()可以省略
def f6 {
println("Hello")
}
f6;
声明时省略的(),调用时就不能有();
7.4 匿名函数(lambda表达式)
定义形式
(name:String)=>{println(name);}
7.4.1 lambda表达式的调用方式
-
直接使用变量接收。
var fun = (name:String) =>{println(name)} fun("小红");
-
作为参数
def f2(func:String => Unit ):Unit={ func("小红"); } f2((name: String) => {println(name)})
7.4.2 匿名函数的简化
-
参数类型可以省略
def f2(func:String => Unit ):Unit={ func("小红"); } f2((name) => {println(name)})
-
如果只有一个参数,()可以省略
def f2(func:String => Unit ):Unit={ func("小红"); } f2(name => {println(name)})
-
函数体只有一行时,{}可以省略
def f2(func:String => Unit ):Unit={ func("小红"); } f2(name => println(name))
-
如果参数只出现异常,参数可以省略,且在使用的地方使用_代替。
def f2(func:String => Unit ):Unit={ func("小红"); } f2( println(_))
-
如果可以推断出当前传入的是一个函数体,可以直接省略下划线
def f2(func:String => Unit ):Unit={ func("小红"); } f2(println)
7.5. 函数的高阶用法
7.5.1 函数作为值进行传递
def f1(name:String):Unit={
println(s"hello ${name}")
}
var f = f1 _; // 对函数名称加空格加下划线
var f2:String=>Unit=f1; //作用等同上一句
f2("小明");
7.5.2 函数作为参数传递
def arrayOperation(array:Array[Int],op:Int=>Int):Array[Int]={
for(element <- array) yield op(element)
}
var arr:Array[Int] = Array(15,25,35);
def addOne(elem:Int):Int={
elem+1;
}
val array:Array[Int] = arrayOperation(arr,addOne)
println(array.mkString(","));
8 面向对象
8.1 类的定义及创建
Scala中不需要像java一样类名和文件名相同,且必须是public修饰,Scala甚至一个文件下可以有多个类。
-
创建类和java使用相同的关键字class,Scala中没有public关键字,默认所有属性都是public的。
-
声明属性时可以指定访问权限,默认public,可以指定protected,private,protected不能在同包下访问。
-
一般可以直接使用对象.属性进行访问或赋值,如果一定要set,get方法可以在属性上添加@BeanProperty,会自动创建set,get
-
在定义时不需要指定属性具体值时,使用_,相当于占位符,会根据属性类型赋初始值。
// 定义一个类 class Student { // 定义属性 private var name: String = "alice" @BeanProperty protected var age: Int = _ var sex: String = _ }
-
创建对象
val student: Student = new Student() println(student.sex) println(student.age)//不能直接访问private的属性,protected的属性只在本身和子类中可以访问
-
特殊访问权限
private[test] var age: Int = 18 // 可以指定在test包下可以访问属性
8.2 构造方法
8.2.1 主构造方法
-
定义类时在class后面增加参数及为构造函数,没有参数则为无参构造。
-
声明类时的参数使用var,或val定义,则会默认参数未类的属性,类体重无须重复定义。
class Student(name: String, age: Int){ def printInfo(){ println(s"name = ${name}, age = $age") } }
val student = new Student("小红", 20) student.printInfo()
8.2.2 辅助构造器
辅助构造器需要直接或间接调用主构造器。
1、定义方式,辅助构造器的方法名必须为this。
def this(name: String, age: Int, school: String){ this(name, age) this.school = school }
2、创建
val student1 = new Student("小红", 25, "清华大学")
-
持续学习中.......