Java知识点
一、java和Scala
1、scala中声明变量的方式有几种?
- 1)scala中的变量分为:不可变变量 val ( value) 和 可变变量 var( variable)
- val:定义的是不可重新赋值的变量(值不可修改),使用val声明变量,相当于java 中的final修饰,不能在指向其他的数据了
- var:定义的是可重新赋值的变量(值可以修改),后期可以被修改重新赋值
- 2)scala中声明变量是:变量名称 在前,变量类型 在后,跟java是正好相反
- 3)scala中定义变量可以不写类型,让scala编译器自动推断
2、scala与Java的区别
scala是运行在 JVM 上的多范式编程语言,同时支持面向对象和面向函数编程,scala最终被编译为.class文件,运行在JVM虚拟机中,其实本质上还是java, 所以在scala和java可以互调双方的api,兼容Java,可以访问庞大的Java类库。
-
Scala是函数式和面向对象编程的结合,而Java是面向对象编程语言。
-
用Scala编写的代码更短、更紧凑。在Java中,代码是长格式的。
-
(1)变量
- scala中声明变量,名称在前,类型在后,java正好相反;
- scala定义变量可不写类型,自动推断,语句最后不需要分号;
- scala中val声明不可变变量,相当于final,用var 声明可变变量;
- scala用关键字lazy来定义惰性变量,调用时,才实例化;
- scala所有类型,都使用大写字母开头,整形使用Int而不是Integer
-
(2)方法函数
- scala通过def 语句定义方法,通过val 语句定义函数。函数没有返回值用Unit,相当于java的void 。
- scala的return是可选的,方法调用会自动返回最后求值的表达式。如果scala使用了return则需要显示指定方法的返回值
-
(3)接口
- scala不支持接口interface,采用trait(类似于Java中的抽象类)。 java支持接口
- 类和方法修饰符的默认值 scala默认是public,java默认是protected.
-
(4)对字符串的支持 :scala采用三个双引号“”“支持换行字符串,Java需要采用“+”进行字符串的连接。
3、Scala方法函数
- 1、def 定义方法,参数列表的类型不可省,返回类型自动推断可省(递归方法除外), 返回值为最后一行可不写return ;
- 2、val定义函数,函数是一个对象(变量),不需返回类型
- 3、方法是类的一部分,隶属于类或者对象,运行时加载到 JVM 的方法区;
- 4、函数是一个完整对象,可赋值给一个变量,运行时加载到 JVM的堆内存中。函数对象有apply,curried,toString,tupled这些方法,而方法则没有。继承 Trait(Trait(特征) 相当于 Java 的接口。
- 5、方法转换为函数,val a = add _
方法 描述
- 遍历 foreach: 传入一个函数对象,函数输入为集合元素,返回为空。list.foreach(println)
- 映射 map:传入一个函数对象,函数输入为类型A,返回为类型B。list.map(_*10)
- 扁平化映射 flatmap :传入一个函数对象,函数的输入是集合的元素,返回一个集合 list.flatMap(_.split(" "))
- 过滤 filter: 传入一个函数对象,接收一个集合类型的参数,返回布尔类型
- 排序 sort :传入一个函数对象,接收一个集合类型的元素参数,返回排序后的列表
- 分组 groupBy: 传入一个函数对象,接收集合元素类型的参数,返回一个K类型的key,这个key会用来进行分组,相同的key放在一组中
- 聚合 reduce:传入函数对象,用来不断进行聚合操作,第一个A1类型参数为当前聚合后的变量,第二个A1类型参数为:当前要进行聚合的元素,列表最终聚合为一个元素
// 第一个下划线表示第一个参数,就是历史的聚合数据结果
// 第二个下划线表示第二个参数,就是当前要聚合的数据元素 scala> a.reduce(_ + _)
4、方法和函数的区别?
(1)定义方式:val 语句 定义函数;def 语句 定义方法。
(2)属性不同:
- 方法是类的一部分,隶属于类或者对象的。运行时加载到 JVM 的方法区。Scala 中的方法跟 Java 的类似,方法是组成类的一部分。
- 函数是一个完整的对象,可以赋值给一个变量。运行时加载到 JVM的堆内存中。函数对象有apply,curried,toString,tupled这些方法,而方法则没有。
- Scala 中的函数其实就是继承了 Trait(Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大的类的对象。
- 换句话来说,在类中定义的函数,即是方法。方法转换为函数:使用_即可将方法转换为函数,作为变量传递,就需要将方法转换为函数
1、定义方式:
//方法的定义
scala> def m1(x: Int) = x + 1
m1: (x: Int)Int
#方法是一个以def开头的带有参数列表(可以无参数列表)的一个逻辑操块,
#这正如object或者class中的成员方法一样。(上面有定义说明)
//函数的定义
scala> val f1 = (x : Int) => x + 1
f1: Int => Int = $$Lambda$1036/961708482@1573e8a5
#函数是一个赋值给一个变量(或者常量)的匿名方法(带或者不带参数列表),
#并且,通过 =>转换符号 跟上逻辑代码块的一个表达式。
# =>转换符号 后面的逻辑代码块的写法与method的body部分相同。
2、相互转换:
scala> def add(x:Int,y:Int)=x+y
add: (x: Int, y: Int)Int
scala> val a = add _
a: (Int, Int) => Int = <function2>
5、集合
·(1)元组,val a = (1, “张三”, 20, “北京市”) :可包含一组不同类型的值,_1表 示访问第一个元素
·(2)变长数组,scala.collection.mutable.ArrayBuffer:增+=、删-=、追加++=, array.sum/max/min/sorted
· (3)可变Map,scala.collection.mutable.Map: 增map+=(“w” ->35),删map -=“w”,改map(“li”)=50,查map(“zh”)
·(4)可变Set,scala.collection.mutable.Set:不重复 无顺序,增+=、删-=、追 加++=,
·(5)可变列表,scala.collection.mutable.ListBuffer,可重复 有顺序,增+=、删 -=、++=加list,
Scala元组将固定数量的项目组合在一起,以便它们可以作为一个整体传递。
元组可以容纳不同类型的对象( 与数组或列表不同),但它们也是不可变类型。
6、匿名函数:一个没有名称的函数
//定义一个数组
scala> val array=Array(1,2,3,4,5)
array: Array[Int] = Array(1, 2, 3, 4, 5)
//定义一个没有名称的函数----匿名函数
scala> array.map(x=>x*10)
res1: Array[Int] = Array(10, 20, 30, 40, 50)
7、柯里化
含义:方法可以定义多个参数列表,用较少的参数列表,调用较多参数列表的方法时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化。
柯里化(Currying)是一种,将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。
柯里化,是把接受多个参数的函数,变换成,接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
柯里化,是函数式编程的一个重要概念。它既能减少代码冗余,也能增加可读性。另外,附带着还能用来装逼。
curry化最大的意义在于, 把多个参数的function等价转化成, 多个单参数function的级联,这样所有的函数就都统一了,方便做lambda演算。
在scala里,curry化对类型推演也有帮助,scala的类型推演是局部的,在同一个参数列表中后面的参数不能借助前面的参数类型进行推演,curry化以后,放在两个参数列表里,后面一个参数列表里的参数可以借助前面一个参数列表里的参数类型进行推演。这就是为什么 foldLeft这种函数的定义都是curry的形式
# 定义2个整数相乘运算
def multiplie2par(x:Int,y:Int)=x*y
# 使用柯里化技术,
# 将上述2个整数的乘法函数,改修为接受一个参数的函数,
# 该函数 返回 是一个以原有第二个参数为参数的函数。
def multiplie1par(x:Int)=(y:Int)=>x*y
# 说明:
# multiplie1par(x:Int) 为接收一个参数的新等价函数,
# (y:Int)=>x*y 则是新等价函数的返回体,它本身就是一个函数(严格来说应该是一个匿名函数),
# 参数为 除等价新函数的参数外原函数剩余的参数。
进一步简化为:
def multiplie1par1(x:Int)(y:Int)=x*y
三个整数乘法的函数
def multiplie3par(x:Int,y:Int,z:Int)=x*y*z
def multiplie3par1(x:Int)=(y:Int,z:Int)=>x*y*z
def multiplie3par2(x:Int)(y:Int)(z:Int)=x*y*z
def multiplie3par3(x:Int)(y:Int)=(z:Int)=>x*y*z
# 编译执行的结果都是一样,调用不同形式参数过程略有不同,
# 直接参入三个参数的一步到位就可以得到运算结果,而
# 传入1或者2个参数的需要分步骤再传入第2/3或者第3个参数才能求出三个整数相乘的结果,
# 很好地体现了延迟执行或者固定易变因素等方面能力。
def getAddress(a:String):(String,String)=>String={
(b:String,c:String)=>a+"-"+b+"-"+c
}
scala> val f1=getAddress("china")
f1: (String, String) => String = <function2>
scala> f1("beijing","tiananmen")
res5: String = china-beijing-tiananmen
//这里就可以这样去定义方法
def getAddress(a:String)(b:String,c:String):String={
a+"-"+b+"-"+c
}
//调用
scala> getAddress("china")("beijing","tiananmen")
res0: String = china-beijing-tiananmen
//之前学习使用的下面这些操作就是使用到了柯里化
List(1,2,3,4).fold(0)(_+_)
List(1,2,3,4).foldLeft(0)(_+_)
List(1,2,3,4).foldRight(0)(_+_)
8、闭包
函数里面,引用外面类成员变量叫作闭包
var factor=10