scala与java的一些不同点

变量与常量

  • 变量:

    var i:Int = 10
    
  • 常量:

    val j:Int = 20
    

说明:

类型可以省略,类型确定后,就不能修改,变量声明时,必须要有初始值

字符串、变量一起使用

val s2 = s"name=$name"
var age: Int = 18
//格式化输出
printf("info=%s age=%d\n", s2, age)

//如果需要对变量进行运算,那么可以加${}
val s1 =
s"""
|select
|    name,
|    age
|from user
|where name="$name" and age=${age+2}
""".stripMargin
println(s1)

键盘输入

def main(args: Array[String]): Unit = {
    // 1 输入姓名
    println("input name:")
    var name = StdIn.readLine()

    // 2 输入年龄
    println("input age:")
    var age = StdIn.readShort()

    // 3 输入薪水
    println("input sal:")
    var sal = StdIn.readDouble()

    // 4 打印
    println("name=" + name)
    println("age=" + age)
    println("sal=" + sal)
}

数据类型

  1. scala中一切数据都是对象,都是Any的子类。
  2. scala中数据类型分为两大类:数值类型(AnyVal)、(AnyReg),不管是值类型还是引用类型都是对象。
  3. scala数据类型仍然遵守,低精度的值类型向高精度值类型,自动转换(隐式转换)
  4. scala中的StringOps是对Java中String的增强。
  5. Unit: 对应Java中void.用于方法返回值的位置,表示方法没有返回值。
    Unit是一个数据类型,只有一个对象就是()。Void不是数据类型,只是一个关键字
  6. Null是一个类型,只有一个对象就是null。它是所有引用类型(AnyRef)的子类。
  7. Nothing,是所有数据类型的子类,主要用在一个函数没有明确返回值时使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z5htjTfL-1652842108188)(O:%5CbmprProject%5CNew%20Mockup%201.png)]

for循环

  • 范围数据循环(To)
for(i <- 1 to 3){
    print(i + " ")
}
println()
  • 范围数据循环(Until) : i 是从 1 到 3 - 1
for(i <- 1 until 3) {
    print(i + " ")
}
println()
  • 循环守卫
for(i <- 1 to 3 if i != 2) {
    print(i + " ")
}
println()
  • 循环步长
for (i <- 1 to 10 by 2) {
    println("i=" + i)
}
  • 嵌套循环
for(i <- 1 to 3; j <- 1 to 3) {
    println(" i =" + i + " j = " + j)
}
  • 引入变量

    (1)for推导式一行中有多个表达式时,所以要加 ; 来隔断逻辑

    (2)for推导式有一个不成文的约定:当for推导式仅包含单一表达式时使用圆括号,当包含多个表达式时,一般每行一个表达式,并用花括号代替圆括号

for {
    i <- 1 to 3
	j = 4 - i
} {
    println("i=" + i + " j=" + j)
}
  • 循环返回值

需求:将原数据中所有值乘以2,并把数据返回到一个新的集合中。

var res = for(i <-1 to 10) yield {
    i * 2
}
println(res)

//输出结果:Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
  • 倒序打印
for(i <- 1 to 10 reverse){
    println(i)
}

循环中断

1)基本说明

Scala内置控制结构特地去掉了break和continue,是为了更好的适应函数式编程,推荐使用函数式的风格解决break和continue的功能,而不是一个关键字。Scala中使用breakable控制结构来实现break和continue功能。

2)案例实操

需求1:采用异常的方式退出循环

def main(args: Array[String]): Unit = {
  try {
    for (elem <- 1 to 10) {
      println(elem)
      if (elem == 5) throw new RuntimeException
    }
  }catch {
    case e =>
  }
  println("正常结束循环")
}

需求2:采用Scala自带的函数,退出循环

import scala.util.control.Breaks

def main(args: Array[String]): Unit = {

  Breaks.breakable(
    for (elem <- 1 to 10) {
      println(elem)
      if (elem == 5) Breaks.break()
    }
  )

  println("正常结束循环")
}

​ 需求3:对break进行省略

import scala.util.control.Breaks._

object TestBreak {

    def main(args: Array[String]): Unit = {
    
        breakable {
            for (elem <- 1 to 10) {
                println(elem)
                if (elem == 5) break
            }
        }
    
        println("正常结束循环")
    }
}

函数至简原则

函数至简原则:能省则省

(1)return可以省略,Scala会使用函数体的最后一行代码作为返回值

(2)如果函数体只有一行代码,可以省略花括号

(3)返回值类型如果能够推断出来,那么可以省略(: 和返回值类型一起省略)

(4)如果有return,则不能省略返回值类型,必须指定

(5)如果函数明确声明unit,那么即使函数体中使用return关键字也不起作用

(6)Scala如果期望是无返回值类型,可以省略等号

(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加

(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略

(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略

函数的高阶用法

  • 函数可以作为值进行传递
object TestFunction {
    def main(args: Array[String]): Unit = {
        
        //函数里嵌套函数
    	def foo():Int = {
            println("foo...")
          	1
        }
        
        //1. 调用foo函数,把返回值给变量f
        val f = foo
        println(f)
        
        //2. 在被调用函数foo后面加上 _,相当于把函数foo当成一个整体,传递给变量f1
        val f1 = foo _
        foo()
        f1()
        
		//3. 如果明确变量类型,那么不使用下划线也可以将函数作为整体传递给变量
		var f2:()=>Int = foo 
    
    }
}
  • 函数可以作为参数进行传递
def main(args: Array[String]): Unit = {
    
    // (1)定义一个函数,函数参数还是一个函数签名;f表示函数名称;(Int,Int)表示输入两个Int参数;Int表示函数返回值
    def f1(f: (Int, Int) => Int): Int = {
        f(2, 4)   //这个f1函数相当于提供了2个数值
    }
    
    // (2)定义一个函数,参数和返回值类型和f1的输入参数一致
    def add(a: Int, b: Int): Int = a + b
    
    // (3)将add函数作为参数传递给f1函数,如果能够推断出来不是调用,_可以省略
    println(f1(add))
    println(f1(add _))
    
}
  • 函数可以作为函数返回值返回
def main(args: Array[String]): Unit = {
    def f1() = {
        def f2() = {
        	1
    	}
        f2 _
    }

    val f = f1()
    // 因为f1函数的返回值依然为函数,所以可以变量f可以作为函数继续调用
     f()
    // 上面的代码可以简化为
   	 f1()()
}

匿名函数

例:(x:Int)=>{函数体} 注意与定义函数时,= 变成了 =>

def main(args: Array[String]): Unit = {

        // (1)定义一个函数:参数包含数据和逻辑函数
        def operation(arr: Array[Int], op: Int => Int) = {
            for (elem <- arr) yield op(elem)
        }

        // (2)定义逻辑函数
        def op(ele: Int): Int = {
            ele + 1
        }

        // (3)标准函数调用
        val arr = operation(Array(1, 2, 3, 4), op)
        println(arr.mkString(","))

        // (4)采用匿名函数
        val arr1 = operation(Array(1, 2, 3, 4), (ele: Int) => {
            ele + 1
        })
        println(arr1.mkString(","))

        // (4.1)参数的类型可以省略,会根据形参进行自动的推导;
        val arr2 = operation(Array(1, 2, 3, 4), (ele) => {
            ele + 1
        })
        println(arr2.mkString(","))

        // (4.2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过1的永远不能省略圆括号。
        val arr3 = operation(Array(1, 2, 3, 4), ele => {
            ele + 1
        })
        println(arr3.mkString(","))

        // (4.3) 匿名函数如果只有一行,则大括号也可以省略
        val arr4 = operation(Array(1, 2, 3, 4), ele => ele + 1)
        println(arr4.mkString(","))

        //(4.4)如果参数只出现一次,则参数省略且后面参数可以用_代替
        val arr5 = operation(Array(1, 2, 3, 4), _ + 1)
        println(arr5.mkString(","))
    }
}

需求2:定义一个计算器函数,传递的函数有两个参数

object TestFunction {

    def main(args: Array[String]): Unit = {

        //定义一个计算器函数,可以对 a,b做加减乘除等运算。运算:传递op函数
        def calculator(a: Int, b: Int, op: (Int, Int) => Int): Int = {
            op(a, b)
        }

        // (1)标准版
        println(calculator(2, 3, (x: Int, y: Int) =>  {x + y}))

        // (2)如果只有一行,则大括号也可以省略
        println(calculator(2, 3, (x: Int, y: Int) =>  x + y))

        // (3)参数的类型可以省略,会根据形参进行自动的推导;
        println(calculator(2, 3, (x , y) =>  x + y))

        // (4)如果参数只出现一次,则参数省略且后面参数可以用_代替
        println(calculator(2, 3,   _ + _))
    }
}

高阶函数案例(高阶用法与匿名函数一起使用)

需求:模拟Map映射、Filter过滤、Reduce聚合

object TestFunction {
    def main(args: Array[String]): Unit = {
        // (1)map映射
        def map(arr: Array[Int], op: Int => Int) = {
            for (elem <- arr) yield op(elem)
        }
        val arr = map(Array(1, 2, 3, 4), (x: Int) => {
            x * x
        })
        println(arr.mkString(","))

        // (2)filter过滤。有参数,且参数再后面只使用一次,则参数省略且后面参数用_表示
       def filter(arr:Array[Int],op:Int =>Boolean) ={
  			var arr1:ArrayBuffer[Int] = ArrayBuffer[Int]()
  			for(elem <- arr if op(elem)){
   			 arr1.append(elem)
  			}
  			arr1.toArray
  		}
      var arr1 = filter(Array(1, 2, 3, 4), _ % 2 == 1)
      println(arr1.mkString(","))

        // (3)reduce聚合。有多个参数,且每个参数再后面只使用一次,则参数省略且后面参数用_表示,第n个_代表第n个参数
        def reduce(arr: Array[Int], op: (Int, Int) => Int) = {
            var init: Int = arr(0)
            for (elem <- 1 until arr.length) {
                init = op(init, elem)
            }
            init
        }
        val arr2 = reduce(Array(1, 2, 3, 4), _ * _)
        println(arr2)
    }
}

函数柯里化&闭包

闭包:函数式编程的标配

1)说明

闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包

函数柯里化:把一个参数列表的多个参数,变成多个参数列表。例: f(1,2,3) -> f(1)(2)(3)

object TestFunction {

    def main(args: Array[String]): Unit = {
        def f1()={
			var a:Int = 10
            def f2(b:Int)={
                a + b
            }
            f2 _
        }

        // 在调用时,f1函数执行完毕后,局部变量a应该随着栈空间释放掉
        val f = f1()

        // 但是在此处,变量a其实并没有释放,而是包含在了f2函数的内部,形成了闭合的效果
        println(f(3))
        println(f1()(3))

        // 函数柯里化,其实就是将复杂的参数逻辑变得简单化,函数柯里化一定存在闭包
        def f3()(b:Int)={
             a + b
        }

        println(f3()(3))
    }
}

名调用:把代码传递过去

object TestControl {
    def main(args: Array[String]): Unit = {

        def f = ()=>{
            println("f...")
            10
        }

        foo(f())
    }

	//def foo(a: Int):Unit = {
    //名调用,把代码块传过去
    def foo(a: =>Int):Unit = {//注意这里变量a没有小括号了
        println(a)
        println(a)
    }
}

注意:Java只有值调用;Scala既有值调用,又有名调用。

惰性函数

1)说明

函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数。

def main(args: Array[String]): Unit = {

    lazy val res = sum(10, 30)
    println("----------------")
    println("res=" + res)
}

def sum(n1: Int, n2: Int): Int = {
    println("sum被执行。。。")
    return n1 + n2
}

输出结果:

----------------
sum被执行。。。
res=40
注意:lazy不能修饰var类型的变量

集合

1)Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质。

2)对于几乎所有的集合类,Scala都同时提供了可变不可变的版本,分别位于以下两个包

不可变集合:scala.collection.immutable

可变集合: scala.collection.mutable

3)Scala不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于java中的String对象

4)可变集合,就是这个集合可以直接对原对象进行修改,而不会返新的对象。类似于java中StringBuilder对象

建议:在操作集合的时候,不可变用符号,可变用方法

ef sum(n1: Int, n2: Int): Int = {
println(“sum被执行。。。”)
return n1 + n2
}


输出结果:


sum被执行。。。
res=40
注意:lazy不能修饰var类型的变量


### 集合

1)Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自**Iterable**特质。

2)对于几乎所有的集合类,Scala都同时提供了**可变**和**不可变**的版本,分别位于以下两个包

不可变集合:scala.collection.**immutable**

可变集合:  scala.collection.**mutable**

3)Scala不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于java中的String对象

4)可变集合,就是这个集合可以直接对原对象进行修改,而不会返新的对象。类似于java中StringBuilder对象

**建议:在操作集合的时候,不可变用符号,可变用方法**

你可能感兴趣的:(笔记,scala,java,开发语言)