scalable language,运行在jvm上,面向对象和面向函数式编程。
兼容java,可以访问庞大的java类库
执行流程
IDEA插件下载地址:http:/.plugins.jetbrains.com/plugin/1347-scala
版本必需和IDEA保持一致
下载插件后,IDEA使用从本地安装插件
cmd -> scala
(1)hello world
1. 输出语句
换行输出:println
不换行输出:print
输出多个值:println(value1, value2, value3...)
2. 分号
可以写,也可以不写
1. 分类
(1)字面常量:整型常量(如:2),浮点型常量(如:1.2),字符常量(如:'a'),字符串常量(如:"abc"),布尔常量(如:true, false),空常量(如:null)
(2)自定义常量
1. 语法格式
val/var 变量名:变量类型 = 初始值
其中:
val定义的是不可重新赋值的变量,也就是自定义常量
var定义的是可以重新赋值的变量
2. 示例
定义一个变量保存一个人的名字“tom”
val name:String = "tom"
3. 类型推断
val name = "tom"
三种定义方式:
(1)使用双引号
(2)使用插值表达式
(3)使用三引号
1. 使用双引号
var name = "hadoop"
println(name + name.length) //hadoop6
2. 使用插值表达式
如果涉及大量字符串的拼接,使用插值表达式
val/var 变量名 = s"${变量/表达式}字符串"
示例:定义变量保存“zhagnsan”, 23, "male",定义字符串打印输出:name=zhangsan, age=23, sex=male
val name = "zhangsan"
val age = 23
val sex = "male"
val info = s"name = ${name}, age = ${age}, sex = ${sex}"
println(info) //name = zhangsan, age = 23, sex = male
3. 使用三引号
如果涉及大段文本
val sql = """
select *
from stu
where name = 'zhangsan'
and age = 23
order by addr;
"""
println(sql)
4. 惰性赋值
lazy val/var 变量名 = 表达式
1. 变量或方法名:小驼峰命名法
2. 类或特质:大驼峰命名法
3. 包:全部小写,多级目录使用"."隔开
1. 类型继承图
(1)Any:所有类型的父类,相当于java中的Object类
(2)AnyVal:所有数值类型的父类
(3)AnyRef:所有引用类型的父类
(4)Unit:相当于java中的void
(5)Null:所有引用类型的子类,它的值只有null
(6)Nothing:所有数据类型的子类,它一般结合异常来进行使用
2. 判断是否有误
val b:Int = null //报错,Int是数值类型,null是引用类型
1. 强制类型转换
val/var 变量名:数据类型 = 具体的值.toXXX
例如:
var age = 3.14.toInt //3
2. 值类型数据转成字符串类型数据
val/var 变量名:String = 值类型数据 + ""
val/var 变量名:String = 值类型数据.toString
3. String类型转换成值类型数据
(1)转成Char的方法是“.toCharArray”
1. 使用步骤
(1)导包:import scala.io.StdIn
(2)通过StdIn.readxxx()来接收用户录入的数据:StdIn.readLine(), StdIn.readInt ()
1. 字符串与整数使用乘法计算,相当于字符串拷贝n份
2. 取模运算:a % b = a - a / b * b (10 % 3 = 1, -10 % 3 = -1, 10 % -3 = 1)
val s1 = "abc"
val s2 = "abc"
println(s1 == s2, s1.eq(s2)) //true, false
原码,反码和补码
计算机底层存储,操作和运算数据都是采用数据的二进制补码形式实现
正数:原码,反码和补码都一样,不需要计算
负数:
反码计算规则:原码的符号位不变,数值位按位取反
补码计算规则:反码 + 1
1. scala没有三元表达式
2. scala条件表达式有返回值(java不行)
val sex = "male"
val result = if(sex == "male") 1 else 0
println(result) //1
3. 块表达式
使用"{}"表示一个块表达式,它和条件表达式一样具有返回值,值为最后一个表达式
val a = {
var b = "aaa"
b + "11"
}
print(a) //aaa11
1. for循环
for(i <- 表达式/数组/集合) {
//逻辑代码
}
var num = 1 to 10
for(i <- num) {
println("num: " + i)
}
/**
num: 1
num: 2
num: 3
num: 4
num: 5
num: 6
num: 7
num: 8
num: 9
num: 10
*/
for(i <- 1 to 3; j <- 1 to 5) if(j == 5) println("*") else print("*")
/**
*****
*****
*****
*/
2. 守卫
for表达式中,可以添加if判断语句,这个if判断语句称为“守卫”,每一次遍历时都会经过if判断,如果为true,才会执行for大括号中的逻辑代码
for(i <- 表达式/数组/集合 if 表达式) {
//逻辑代码
}
for(i <- 1 to 10 if i % 3 == 0){
println(i)
}
//3 6 9
3. for推导式
在scala中,for循环是有返回值的,可以使用yield表达式构建处一个集合。使用yield的for表达式称为“推导式”。
val result = for(i <- 1 to 10) yield i *10
println(result) //(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
4. scala中没有break和continue
1. 语法格式
def 方法名(参数名:参数类型, 参数名:参数类型) : [return type] = {方法体}
(1)参数列表的参数类型不能省略
(2)返回值类型可以省略
(3)返回值可以不写return,默认就是{}块表达式的值
2. 示例
获取两个数字中的最大值
def getMax(a:Int, b:Int):Int = if(a > b) a else b
println(getMax(3, 13)) //13
3. 返回值类型推断
如果定义的是递归方法,那么不能省略返回值类型
4. 惰性方法
当记录方法返回值的变量被声明为lazy时,方法的执行将被推迟,直到首次使用该值时,方法才会被执行,这种方法叫惰性方法。
java中没有提供惰性技术,但是可以通过懒加载来实现;
lazy不能修饰var类型的变量。
使用场景:
打开数据库连接
提升某些特定模块的启动时间
确保对象中的某些字段能优先初始化
def getTotal(a:Int, b:Int) = a + b
lazy val total = getTotal(1, 2) //这里方法不会被执行
println(total) //3, 这里才回值还行方法
5. 方法参数
(1)默认参数:在定义方法时,可以给参数定义一个默认值
def getSum(a:Int = 10, b:Int = 20) = a + b
println(getSum()) //30
println(getSum(50)) //70
println(getSum(b=50)) //60
println(getSum(50, 10)) //60
(2)带名参数
在调用方法时,指定参数名称来进行调用
(3)变长参数
如果方法的参数是不固定的,可以将该方法的参数定义成变长参数
def 方法名(参数名:参数类型*):返回值类型={方法体}
1)在参数后面加一个*,表示该参数可以是0个或多个
2)一个方法有且只有一个变长参数,并且要位于参数列表的最后
def getSum(numbers:Int*)=numbers.sum //numbers底层为数组,scala的数组可以直接求和
println(getSum(1, 2, 3, 4, 5)) //15
6. 方法调用方式
(1)后缀调用法
和java一样,语法如下:
对象名.方法名(参数)
示例:
Math.abs(-1)
(2)中缀调用法
语法格式:
对象名 方法名 参数
示例:
Math abs -1 //等同Math.abs(-1)
Math min(1, 2) //等同Math.min(1, 2)
1 + 2 //等同 1.+(10)
1 to 10 //等同 1.to(10)
在scala中,操作符也是方法,例如+号是个方法名,是符号的方法
(3)花括号调用法(只能用于只有一个参数的方法)
语法格式:块表达式的返回值作为入参
Math.abs {
//表达式
}
示例:
Math.abs{
val a = -11
if(a > 0) a else -10
} //10
(4)无括号调用法
如果方法没有参数,可以省略方法名后面的括号
示例:
def sayHello() = println("hello world")
sayHello //hello world
***过程
在scala中,如果方法的返回值类型是Unit,这样的方法称为过程(procedure),过程的"="号可以省略不写,例如:
(1)示例1
def sayHello() {println("hello world")}
sayHello //hello world
(2)示例2
def getMax(a:Int, b:Int) {
val max = if(a >= b) a else b
println("max value is: " + max)
}
getMax(1, 2) //max value is: 2
1. 定义函数
val 函数变量名 = (参数名:参数类型, 参数名:参数类型...) => 函数体
1)在scala中,函数是一个对象
2)类似于方法,函数也有参数列表和返回值
3)函数定义不需要使用def
4)无需指定返回值类型
示例:
(1)示例1
val sum = (a:Int, b:Int) => a + b
sum(1, 2)
(2)示例2
val abs = (a:Int) => {
if(a > 0) a
else
-a
}
abs(-3)
(3)示例3
val hello = () => println("hello")
hello()
1. 区别
java中两者一致,但在scala中:
1)方式是隶属于类或者对象的,在运行时,它加载到JVM方法区中
2)可以将函数对象赋值给一个变量,在运行时,它加载到JVM堆内存中
3)函数是一个对象,继承自FunchtionN,函数对象有apply, curried, toString, tupled这些方法,而方法则没有
4)函数是对象,方法隶属于对象,所以可以理解为:方法归属于函数
2. 方法转换为函数
有时候需要将方法转换成函数,例如作为变量进行传递
格式:
val 变量名 = 方法名 _ //方法名 + 空格 + 下划线
示例:
def getSum(a:Int, b:Int) = a + b
def sum = getSum _
val a = sum(1, 2) //3
类,对象
object(单例对象)/class创建类,new创建对象
示例:
创建一个Person类,并创建它的对象,然后打印
object Demo01 {
class Person {
}
//main方法,所有程序测主入口,所有代码的执行都是从这里开始的
def main(args: Array[String]): Unit = {
val person = new Person()
println(person)
}
}
简写形式
1. 如果类是空的,没有任何成员,可以省略{}
2. 如果构造器的参数为空,可以省略()
object Demo01 {
class Person
def main(args: Array[String]): Unit = {
val person = new Person
println(person)
}
}
object FieldDemo {
class Person {
var name : String = ""
var age : Int = 23
}
def main(args: Array[String]): Unit = {
val person = new Person
person.name = "Tom"
person.age = 35
println(person.name + ": " + person.age) //Tom: 35
}
}
(1)用法:
在定义var类型的成员变量时,可以使用"_"来初始化成员变量
String => null
Int => 0
Bolean => false
Double => 0.0...
val变量必需手动初始化
object FieldDemo {
class Person {
//1.普通写法
// var name : String = ""
//2. 类型推断
// var name = ""
//3. 下划线初始化var类型变量, 必需指定类型
var name : String = _
var age : Int = _
}
def main(args: Array[String]): Unit = {
val person = new Person
person.name = "Tom"
person.age = 35
println(person.name + ": " + person.age)
}
}
(1)格式
def 方法名(参数1:数据类型1, 参数2:数据类型2):[return type] = {//方法体}
(2)示例
object CustomerDemo {
class Customer {
var name : String = _
var sex : String = _
def sayHello() = println(s"Hello ${name}, your are ${sex}")
}
def main(args: Array[String]): Unit = {
val customer = new Customer
customer.name = "Tom"
customer.sex = "male"
customer.sayHello()
}
}
在scala中,没有public关键字,没有被private或protected修饰的成员都是public的
也就是scala中只有:private,private[this],protected和默认4中权限修饰符
object PersonDemo {
class Person {
private var name : String = _
private var age : Int = _
def getName() : String = this.name
def getAge() : Int = this.age
def setName(name : String) : Unit = this.name = name
def setAge(age : Int) : Unit = this.age = age
def sayHello(msg : String) = println(s"hello ${this.name}, your are ${this.age} years old, ${msg}")
}
def main(args: Array[String]): Unit = {
val person = new Person
person.setAge(23)
person.setName("Jim")
person.sayHello("see you!")
}
}
主构造器默认帮我们定义好了成员变量
class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值...) {//代码块}
object ConstructorDemo {
class Person(name : String = "John", age : Int){
println("I am constructor function")
var addr : String = _
def sayHello(msg : String) = println(s"hello ${name}, your are ${age} years old, your addr is ${addr}, ${msg}")
}
def main(args: Array[String]): Unit = {
val p1 = new Person(age = 12)
p1.addr = "sh"
p1.sayHello("bye")
println("---------------")
val p2 = new Person("Tomas", 15)
p2.sayHello("byeBye")
println("---------------")
val p3 = new Person("Jimmy", 18)
p3.addr = "SZ"
p3.sayHello("goodBye")
}
}
def this(参数名:类型){
//调用主构造器或其他构造器
//构造器代码
}
示例:
object CustomerDemo2 {
class Customer(val name : String, val addr : String){
def this(args : Array[String]){
this(args(0), args(1))
}
}
def main(args: Array[String]): Unit = {
val c = new Customer(Array("Joy", "Beijing"))
println(c.name, c.addr)
}
}
scala中没有static关键字,要想定义static变量或者static方法,就要使用scala中的单例对象,也就是object
单例对象表示全局仅有一个对象,也就孤立对象
object 单例对象名{}
单例对象中定义的变量是静态变量,在内存中只有一个对象,可以使用“单例对象名.变量名”来访问
object ObjectDemo {
object Dog {
val legs = 4
}
def main(args: Array[String]): Unit = {
println("dog has " + Dog.legs + " legs")
}
}
object ObjectDemo {
object Dog {
val legs = 4
def printSpliter() = {println("-" * 15)}
}
def main(args: Array[String]): Unit = {
println("dog has " + Dog.legs + " legs")
Dog.printSpliter()
}
}
main方法必需定义在object中,因为scala没有静态方法
def main(args: Array[String]): Unit = { //代码块 }
创建一个object,继承App特质(Trait),然后将需要编写的代码写在object的构造方法体内
object AppTraitDemo extends App {
println("Hello main")
}
在java中,经常会有一些类,同时具有实例成员也有静态成员(没有实现静态内容和非静态内容的分离)。在scala中,要实现类似的效果,就需要使用伴生对象。
一个class和object具有相同的名字,这个object称为伴生对象,这个class称为伴生类
(1)伴生对象和伴生类具有相同的名字
(2)伴生对象和伴生类在同一个scala源文件中
(3)伴生对象和伴生类可以相互访问private属性
实例:
object ComponionDemo {
class Generals {
def toWar() = println(s"武士拿着${Generals.arms}上阵杀敌")
}
object Generals {
private val arms = "尚方宝剑"
}
def main(args: Array[String]): Unit = {
val g = new Generals
g.toWar() //武士拿着尚方宝剑上阵杀敌
}
}
如果某个成员权限设置为private[this],表示只能在当前类中访问,伴生对象也不可访问
scala支持创建对象时免new操作,要想实现免new,就要通过半生对象的apply方法来实现
格式:
object 伴生对象名 {
def apply(参数名:参数类型...) = new 类(...)
}
创建对象:
val 对象名 = 伴生对象名(参数1...)
示例:
object ApplyDemo {
class Person(var name : String, var age: Int){
println("I am structor")
}
object Person {
def apply(name : String, age: Int) = new Person(name, age);
}
def main(args: Array[String]): Unit = {
val p = Person("John", 23)
println(p.name + ", " + p.age)
}
}
(1)类继承
(2)单例对象继承类
object ObjectExtendsDemo {
class Person {
var name : String = _
var age : Int = _
def sayHello: Unit = println("hello " + name + ": your age is " + age)
}
object Student extends Person
def main(args: Array[String]): Unit = {
Student.name = "Tom"
Student.age = 12
Student.sayHello //hello Tom: your age is 12
}
}
单例对象不能继承单例对象,类也不能继承单例对象
(3)重写
重写方法和val变量
object OverrideDemo {
class Person {
val name = "Tom"
var age = 15
def sayHello: Unit = println(s"Hello ${name}, your age is ${age}")
}
class Student extends Person {
override val name: String = "Alicia"
age = 25
override def sayHello: Unit = {
super.sayHello
println(".......")
}
}
def main(args: Array[String]): Unit = {
val s = new Student
s.sayHello
}
}
isInstanceOf用于判断对象是否为指定类的对象
asInstanceOf用于将对象转换为指定类型
格式:
val flag : Boolean = 对象.isInstanceOf[类型]
var 变量 = 对象.asInstanceOf[类型]
object ClassOfDemo {
class Person
class Student extends Person
def main(args: Array[String]): Unit = {
val s : Person = new Student
println(s.isInstanceOf[Person]) //true
println(s.isInstanceOf[Student]) //true
println(s.getClass == classOf[Person]) //false
println(s.getClass == classOf[Student]) //true
}
}
如果类中有抽象字段或者抽象方法,那么就是抽象类
抽象字段:没有初始化值的变量
抽象方法:没有方法体的方法
object AbstractDemo {
abstract class Shape {
def area():Double
}
class Square(var length:Double) extends Shape {
override def area(): Double = length * length
}
class Rectangle(var length:Double, var width:Double) extends Shape {
override def area(): Double = length * width
}
class Circle(radius:Double) extends Shape {
override def area(): Double = Math.PI * radius * radius
}
def main(args: Array[String]): Unit = {
println(new Square(2).area()) //4.0
println(new Rectangle(3, 2).area()) //6.0
println(new Circle(2).area()) //12.566
}
}
object DogDemo {
abstract class Animel {
def getName : String
}
def main(args: Array[String]): Unit = {
val c = new Animel {
override def getName() = "dog"
}.getName()
println(c)
}
}
(1)瘦接口:只有抽象内容的特质
(3)富接口:既有抽象内容,又有具体内容的特质
定义特质:
trait 特质名称 {
//普通字段
//抽象字段
//普通方法
//抽象方法
}
继承特质:
class 类 extends 特质1 with 特质2 with 特质3...{
//重写抽象字段
//重写抽象方法
}
object TraitDemo {
trait Logger {
def log(msg : String)
}
trait Tag1 {
def addTag1(tag : String)
}
trait Tag2 {
def addTag2(tag : String)
}
class ConsoleLogger extends Logger with Tag1 with Tag2 {
override def log(msg: String): Unit = {
println(msg)
}
override def addTag1(tag: String): Unit = {
println("tag1 " + tag)
}
override def addTag2(tag: String): Unit = {
println("tag2 " + tag)
}
}
def main(args: Array[String]): Unit = {
val logger = new ConsoleLogger
logger.log("hello")
logger.addTag1("tag1")
logger.addTag2("tag2")
}
}
有时候,我们希望在不改变类继承体系的情况下,对对象的功能进行临时增强或者扩展,这个时候就可以考虑使用对象混入技术。对象混入值得是在scala中,类和特质之间无任何的继承关系,但是通过特定的关键字,却可以让对象具有指定特质中的成员。
语法:
val var 对象名 = new 类 with 特质
示例:
object TraitDemo2 {
trait Logger {
def log(msg : String) = println(msg)
}
class User
def main(args: Array[String]): Unit = {
val u = new User with Logger
u.log("hello")
}
}
(1)特质只有一个无参构造器
(2)一个类继承另一个类,以及多个trait,当创建该类的实例时,它的构造器执行顺序如下:
1)执行父类的构造器
2)安装从左到右的顺序执行trait的构造器
3)如果trait有父构造器,则先执行父trait构造器
4)如果多个trait有相同的父trait,则父trait只执行一次
5)执行子类构造器
object TraitDemo3 {
trait Logger {
println("Logger info 2")
}
trait LoggerChid1 extends Logger {
println("LoggerChid1 info 3")
}
trait LoggerChid2 extends Logger {
println("LoggerChid2 info 4")
}
class Person {
println("Person info 1")
}
class Student extends Person with LoggerChid1 with LoggerChid2 {
println("student 5")
}
def main(args: Array[String]): Unit = {
val s = new Student
}
}
类似java的POJO
case class 样例类名([val/var] 成员变量名1:类型1, 成员变量名2:类型2...){}
1)在普通class类前加case,就编程了样例类
2)变量名前的修饰符可以不写,默认是val,如果要指定是var,必需手写
当我们定义一个样例类后,编译器会自动生成一些方法,常用的如下:
1)apply()方法:创建类可以省略new
2)toString()方法:打印属性值而非地址
3)equals()方法:可以使用==类比较变量值
4)hashCode()方法:哈希值
5)copy()方法:可以用来快速创建一个属性值相同的对象,还可以使用带名参数来指定属性值
6)unapply()方法:一般用作提取器
case修饰的单例对象,它没有主构造器。主要用在:
1)枚举
2)作为没有任何参数的消息传递
object TraitDemo4 {
trait SEX
case object MALE extends SEX
case object FEMALE extends SEX
class Person(var name: String, var sex:SEX){
}
def main(args: Array[String]): Unit = {
val p = new Person("Tom", MALE)
println(p.name, p.sex)
}
}
定长数组,变长数组
格式:
val/var 变量名 = new Array[元素类型](数组长度)
val/var 变量名 = Array(元素1, 元素2...)
示例:
object ArrayDemo1 {
def main(args: Array[String]): Unit = {
val arr1 = new Array[Int](10)
arr1(0) = 2
println(arr1(0))
println("*" * 15)
val arr2 = Array("java", "scala", "python")
for(item <- arr2){
println(item)
}
}
}
2
***************
java
scala
python
import scala.collection.mutable.ArrayBuffer
val/var 变量名 = ArrayBuffer[类型]()
val/var 变量名 = ArrayBuffer(元素1, 元素2...)
(1)创建数组
object ArrayDemo2 {
def main(args: Array[String]): Unit = {
val arr1 = ArrayBuffer[Int]()
println(arr1)
println("-"*15)
val arr2 = ArrayBuffer("China", "US", "England")
println(arr2)
}
}
ArrayBuffer()
---------------
ArrayBuffer(China, US, England)
(2)变长数组元素的增删改
1)使用+=增加单个元素
2)使用-=删除单个元素
3)使用++=追加一个数组到变长数组中
4)使用--=移出变长数组中的指定多个元素
示例:
object ArrayDemo3 {
def main(args: Array[String]): Unit = {
val arr1 = ArrayBuffer("hadoop", "spark", "flink")
arr1 += "flume"
arr1 -= "hadoop"
arr1 ++= Array("hive", "sqoop")
arr1 --= Array("spark", "sqoop")
println(arr1)
}
}
object ArrayDemo4 {
def main(args: Array[String]): Unit = {
val arr1 = Array("a", "b", "c", "d", "e")
for (item <- 0 to arr1.length - 1) println(arr1(item))
println("-" * 15)
for (item <- 0 until arr1.length) println(arr1(item))
println("-" * 15)
for (item <- arr1.indices) println(arr1(item))
println("-" * 15)
for (item <- arr1) println(item)
}
}
sum(), max(), min(), sorted(), reverse()
元组一般用来存储多个不同类型的值,元组的长度和元素都是不可变的。例如,同时存储姓名,年龄,性别,出生年月这些数据,就要用到元组。
格式:
val/var 元组 = (元素1, 元素2...)
val/var 元组 = 元素1 -> 元素2 //适用于只有两个元素的元组
示例:
object TupleDemo {
def main(args: Array[String]): Unit = {
val tuple1 = ("Tom", 23, "2018-11-17")
val tuple2 = "Tom" -> "Jim"
println(tuple1)
println("--------------------------")
println(tuple2)
}
}
(Tom,23,2018-11-17)
--------------------------
(Tom,Jim)
元组访问:
方式1:
元组名._1 //访问第1个元素,序号从1开始
元组名._2 //访问第2个元素,序号从1开始
方式2:
for(item <- tuple1.productIterator){
println(item)
}
List
格式:
val/var 变量名 = List(元素1, 元素2...)
val/var 变量名 = Nil //空列表
val/var 变量名 = 元素1 :: 元素2 :: Nil //Nil表示结束
格式:
import scala.collection.mutable.ListBuffer
val/var 变量名 = ListBuffer[type]() //空的可变列表
val/var 变量名 = ListBuffer(ele1, ele2...)
可变列表操作:
isEmpty: 判断一个列表是否为空
distinct:去重
++:拼接两个列表,返回一个新的列表
head:获取列表首个元素
tail:获取除首个元素外的其他所有元素
reverse:反转,返回反转后的列表
take:获取前缀元素(具体个数可自定义,比如前3个元素)
drop:获取后缀元素(具体个数可自定义,比如除了前3个元素剩下的所有元素都算后缀元素)
flatten:扁平化操作,返回扁平化后的新列表(针对嵌套列表的操作)
zip:对列表进行拉链操作,将两个列表合并成一个元素为元组列表
unzip:对列表进行拉开操作,将一个包含元组的列表合拆成两个列表的元组
toString:将列表转成默认字符串形式
mkString:将列表转成指定字符串形式
union:获取两个列表的并集,并返回
intersect:获取两个列表的交集,并返回
diff:获取两个列表的差集,并返回
示例:
object ListDemo {
def main(args: Array[String]): Unit = {
val nameList = List("zhangsan", "lisi", "wangwu")
val ageList = List(12, 23, 45)
val tupleList = nameList.zip(ageList)
println(tupleList)
println("---------------------------")
val tuple = tupleList.unzip
println(tuple)
}
}
List((zhangsan,12), (lisi,23), (wangwu,45))
---------------------------
(List(zhangsan, lisi, wangwu),List(12, 23, 45))
不可变,可变
-,+,++,--
val/var map = Map(key1 -> val1, key2 -> val2...)
val/var map = Map((key1, val1), (key2, val2)...)
map(key): 获取对应的值,如果不存在,返回None
map.keys: 返回所有的键
map.values:返回所有的值
+:添加键值对
-:删除键值对
object MapDemo {
def main(args: Array[String]): Unit = {
val map = mutable.Map("zhangsan" -> 23)
map += "lisi" -> 27
println(map) //Map(lisi -> 27, zhangsan -> 23)
println(map.keys) //Set(lisi, zhangsan)
println(map.values) //HashMap(27, 23)
for((k, v) <- map) println("k : " + k + ", v : " + v)
//k : lisi, v : 27
//k : zhangsan, v : 23
}
}
是指方法的参数列表可以接收函数对象
例如:add(10, 20)不是函数式编程,add(函数对象)是函数式编程
以下函数都可以进行函数式编程:
def foreach(f:(A) => Unit):Unit
def foreach(函数)
示例:
object FunctionDemo {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
list.foreach(item => println(item))
}
}
1. 类型推断:函数的参数类型可以不写
2. 下划线简化:当函数参数只在函数中出现一次,且函数体没有嵌套调用,可以使用下划线简化函数定义
object FunctionDemo {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
// list.foreach(item => println(item))
list.foreach(println(_))
}
}
def map[B](f(A) => B) : TraversableOnce[B]
def map(函数对象)
先进行map操作,然后进行flatten操作
object FunctionDemo1 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
val list1 = list.flatMap(item => List(item, item * 2))
println(list1)
}
}
默认排序(sorted),指定字段排序(sortBy),自定义排序(sortWith)
(1)reduce
def main(args: Array[String]): Unit = {
val list = (1 to 10).toList
//x表示聚合的结果,y表示list中遍历的下一个值
val sum = list.reduce((x, y) => x + y)
val sum1 = list.reduce(_ + _)
val sum2 = list.reduceLeft(_ + _)
val sum3 = list.reduceRight(_ + _)
}
(2)fold
它是在reduce的基础上加了一个初始值
def main(args: Array[String]): Unit = {
val list = (1 to 10).toList
val fold = list.fold(100) (_ + _)
println(fold) //155
}
def main (args: Array[String] ): Unit = {
val stuList = List(("zhangsan", 35, 86, 97), ("lisi", 62, 79, 89), ("wangwu", 85, 79, 53), ("zhaoliu", 100, 100, 100))
println(stuList)
//语文及格
val yuwen = stuList.filter(_._2 >= 60)
println(yuwen)
//总成绩
val total = stuList.map(e => e._1 -> (e._2 + e._3 + e._4))
println(total)
//总成绩排名
val sortedTotal = total.sortWith((x, y) => x._2 > y._2)
println(sortedTotal)
}
List((zhangsan,35,86,97), (lisi,62,79,89), (wangwu,85,79,53), (zhaoliu,100,100,100))
List((lisi,62,79,89), (wangwu,85,79,53), (zhaoliu,100,100,100))
List((zhangsan,218), (lisi,230), (wangwu,217), (zhaoliu,300))
List((zhaoliu,300), (lisi,230), (zhangsan,218), (wangwu,217))
scala有强大的模式匹配机制,应用包括:
1)判断固定值;
2)类型查询
3)快速获取数据
格式:
变量 match {
case "val1" => expresstion1
case "val2" => expresstion2
case _ => expresstion1 //默认匹配
}
代码:
object MatchDemo {
def main(args: Array[String]): Unit = {
println("pls entry a String:")
val s = StdIn.readLine()
val res = s match {
case "hadoop" => "big data framework"
case "zk" => "zk framework"
case "spark" => "cal framework"
case _ => "not matck"
}
println(res)
}
}
pls entry a String:
spark
cal framework
格式:
变量 match {
case 变量名1:类型1 => expresstion1
case 变量名2:类型2 => expresstion2
case _:类型3 => expresstion3
case _ => expresstion1 //默认匹配
}
如果 case表达式中没有使用到匹配到的变量,那么可以使用下划线替代变量名
代码:
object MatchDemo1 {
def main(args: Array[String]): Unit = {
val a : Any = 1.2
a match {
case _:String => println("String type")
case x:Int => println(x + " is Int type")
case _:Double => println("Double type")
case _ => println("not match")
}
}
}
格式:
变量 match {
case 变量名1 if 条件1 => expresstion1
case 变量名2 if 条件2 => expresstion2
case _ if 条件3 => expresstion3
case _ => expresstion1 //默认匹配
}
代码:
object MatchDemo2 {
def main(args: Array[String]): Unit = {
println("pls enter a Int")
val s = StdIn.readInt()
s match {
case x if x > 0 && x < 10 => println( "0 < x < 10")
case x if x > 10 => println( "10 < x")
case _ => println("no match")
}
}
}
格式:
对象名 match {
case 样例类型1(f1, f2, fn) => expresstion1
case 样例类型2(f1, f2, fn) => expresstion2
case _ => expresstion1 //默认匹配
}
1)字段个数必需与样例类定义的字段个数一致
2)要匹配的对象必需声明为Any
代码:
object MatchDemo3 {
case class Person(name:String, age:Int)
case class Dog(age:Int)
def main(args: Array[String]): Unit = {
val c : Any = Person("zhangsan", 23)
c match {
case Person(a, b) => println(s"this is a Person class, name is ${a}, age is ${b}")
case Dog(a) => println(s"this is a Dog class, age is ${a}")
case _ => "not match"
}
}
}
代码:
object MatchDemo4 {
def main(args: Array[String]): Unit = {
val arr1 = Array(1, 2, 3)
var arr2 = Array(0)
var arr3 = Array(2, 3, 4, 5, 6)
arr1 match {
case Array(1, x, y) => println("匹配长度为3,0位置的值为1,其他位置的值任意的数组")
case Array(0) => println("匹配长度为1,0位置的值为0的数组")
case Array(2, _*) => println("匹配0位置的值为2,其他位置的值任意,数组长度任意的数组")
case _ => "not match"
}
}
}
List(0) //只保存0一个元素的列表
List(1, _*) //以0开头的列表,长度不限
List(1, x, y) //以1开头的列表,长度为3
代码:
def main(args: Array[String]): Unit = {
val arr1 = (0 to 10).toArray
//匹配数组的第1,2,3三个元素,并赋值给item1, item2, item3
val Array(_, item1, item2, item3, _*) = arr1
println(item1, item2, item3) //1, 2, 3
println("*********************")
val list = (0 to 10).toList
//获取list的第0,1个元素
val List(a, b, _*) = list
val a1 :: b1 :: tail = list
println(a, b, a1, b1)
}
def main(args: Array[String]): Unit = {
val map = Map("zhagnsan" -> 23, "zhaosi" -> 23, "wangwu" -> 27, "zhaoliu" -> 33)
for((k, v) <- map if v == 23) println(k + ":" + v)
for((k, 23) <- map) println(k + ":" + 23)
}
Option表示可选值,这种类型的数据有两种形式:
(1)Some(x)表示实际的值
(2)None表示没有值,可以使用getOrElse方法,当为None时,可以指定默认值
object OptionDemo {
def div(a : Int, b : Int): Option[Int] = {
if(b == 0) None
else Some(a / b)
}
def main(args: Array[String]): Unit = {
println(div(2, 0))
}
}
def main(args: Array[String]): Unit = {
val pf : PartialFunction[Int, String] = {
case 1 => "一"
case 2 => "二"
case 3 => "三"
case _ => "未匹配"
}
println(pf(1))
println(pf(2))
println(pf(3))
println(pf(4))
}
一
二
三
未匹配
def main(args: Array[String]): Unit = {
val list = (1 to 10).toList
val res = list.map{
case x if x >= 1 && x < 4 => "[1-4)"
case x if x >= 4 && x < 8 => "[4-8)"
case _ => "[8-*)"
}
println(res) //List([1-4), [1-4), [1-4), [4-8), [4-8), [4-8), [4-8), [8-*), [8-*), [8-*))
}
格式:
val regname = """reg expression""".r
(1)将类编程样例类,那么会自动生成unapply方法
(2)实现unapply方法
def unapply(stu : Student) : Option[(type1, type2, ...)] = {
if(stu != null) Some(f1, f2, ...)
else None
}
object ApplyDemo {
class Student(var name: String, var age:Int)
object Student {
def apply(name: String, age: Int): Student = new Student(name, age)
def unapply(s: Student): Option[(Any, Any)] = if(s == null) None else Some(s.name, s.age)
}
def main(args: Array[String]): Unit = {
val stu = Student("zhangsan", 23)
println(stu.name, stu.age)
println("--------------------------")
val res = Student.unapply(stu)
println(res)
println("--------------------------")
stu match {
case Student(name, age) => println(s"name = ${name}, age = ${age}")
case _ => "not match"
}
}
}
(zhangsan,23)
--------------------------
Some((zhangsan,23))
--------------------------
name = zhangsan, age = 23
val source : BufferedSource = Source.fromFile("path", "encoding")
val lines : Iterator[String] = source.getLines
val list:List[String] = lines.toList
source.close
代码:
object SourceDemo {
def main(args: Array[String]): Unit = {
val source = Source.fromFile("./read.txt" ,"UTF-8")
val list:List[String] = source.getLines.toList
println(list)
source.close
}
}
格式:
val source : BufferedSource = Source.fromFile("path", "encoding")
val iter : BufferedIterator[Char] = source.buffered
while(iter.hasNext) print(iter.next)
source.close
val source1 = Source.fromURL("https://www.baidu.com")
val source2 = Source.fromString("Hello")
println(source1.mkString)
println(source2.mkString)
java类库
java类库
如果一个函数的参数列表可以接收函数对象,那么这个函数就叫高阶函数(High-Order Function)
常用的高阶函数分为:
1)作为值的函数
2)匿名函数
3)柯里化
4)闭包
5)控制抽象
在scala中,函数就和数字、字符串一样,可以将函数传递给一个方法,例如,可以对算法进行封装,然后将具体的动作传递给方法。
案例:
将一个整数列表中的每个元素转换成对应个数的星号(*)
List(1, 2, 3) => *, **, ***
代码:
def main(args: Array[String]): Unit = {
val list1 = (1 to 10).toList
val func = (x:Int) => "*" * x
val list2 = list1.map(func)
println(list2)
}
def main(args: Array[String]): Unit = {
val list1 = (1 to 10).toList
// val func = (x:Int) => "*" * x
// val list2 = list1.map(func)
val list2 = list1.map("*" * _)
println(list2)
}
柯里化(Currying)是指将原来接收多个参数的方法转换为多个只有一个参数的参数列表的过程
执行过程:
案例:
定义一个方法,完成两个字符串的拼接
代码:
object FuncDemo1 {
//1. 普通字符串拼接,如果需求变动,例如要将x转换成大写,然后和y进行拼接,就需要修改方法体
def merge (x:String, y:String): String = x + y
//2. 柯里化
def merge1 (x:String, y:String)(f1:(String, String) => String): String = f1(x, y)
def main(args: Array[String]): Unit = {
println(merge("a", "b"))
println(merge1("a", "b")(_.toUpperCase + _))
闭包指的是可以访问不在当前作用域范围数据的一个函数
格式:
val y = 10
val add = (x:Int) => x + y
println(add(5)) //15
代码:
object FuncDemo2 {
def a = 10
def getSum(b : Int) = a + b
def main(args: Array[String]): Unit = {
println(getSum(3))
}
}
假设函数A的参数列表需要接收一个函数B,且函数B没有输入值也没有返回值,那么函数A就被称为控制抽象函数
格式:
val 函数A = (函数B: () => Unit) => {
//代码
函数B()
}
代码:
object FuncDemo3 {
def main(args: Array[String]): Unit = {
val myShop = (f1: () => Unit) => {
println("hello")
f1()
println("Bye")
}
myShop(() => println("shopping"))
}
}
1)隐式转换:使用implicit关键字声明的带有单个参数的方法,该方法是被自动调用的,用来实现自动将某种类型的数据转换为另一种类型的数据
2)隐式参数:使用implicit关键字修饰的变量。在scala的方法中,可以带有一个标记未implicit的参数列表,调用该方法时,此参数列表可以不用给初始化值,因为编译器会自动查找缺省值提供给该方法。
需求(手动导入):
让File对象具有read功能,将文件按字符串读取
object ImplicitDemo {
class RichFile(file: File) {
def read() = Source.fromFile(file).mkString
}
object ImplicitObject {
implicit def file2RichFile(file: File) = new RichFile(file)
}
def main(args: Array[String]): Unit = {
import ImplicitObject.file2RichFile
val file = new File("./read.txt")
println(file.read)
}
}
在当前作用域中有隐式转换方法,会自动导入隐式转换
object ImplicitDemo1 {
class RichFile(file: File) {
def read() = Source.fromFile(file).mkString
}
def main(args: Array[String]): Unit = {
implicit def file2RichFile(file: File) = new RichFile(file)
val file = new File("./read.txt")
println(file.read)
}
}
手动导入:
object ImplicitDemo2 {
def show(name:String)(implicit delimit:(String, String)) = delimit._1 + name + delimit._2
object ImplicitParam {
implicit val delimit_defaul = "<<<" -> ">>>"
}
def main(args: Array[String]): Unit = {
import ImplicitParam.delimit_defaul
println(show("zhangsan"))
}
}
自动导入:
object ImplicitDemo2 {
def show(name: String)(implicit delimit: (String, String)) = delimit._1 + name + delimit._2
def main(args: Array[String]): Unit = {
implicit val delimit_defaul = "<<<" -> ">>>"
println(show("zhangsan"))
}
}
scala中泛型使用[数据类型]来表示,一般结合数组或者集合使用,常用的方法还有:
1)泛型类
2)泛型特质
3)泛型方法
object TypeDemo {
//向上转类型耗性能
// def getMidEle(arr:Array[Any]) = arr(arr.length / 2)
//泛型优化
def getMidEle[T](arr:Array[T]) = arr(arr.length / 2)
def main(args: Array[String]): Unit = {
println(getMidEle(Array(1, 2, 3, 4, 5)))
println(getMidEle(Array("a", "b", "c")))
}
}
class 类[T] {val 变量名:T}
上界: [T <: 类型] //T只能是对应的类型,或者对应类型的子类型
下界: [T >: 类型] //T只能是对应的类型,或者对应类型的父类型
上下界:[T >: 类型2 <: 类型1]
协变:类A和类B是父子类关系,Pair[A]和Pair[B]之间也有父子类关系 class Pair[+T] {}
逆变:类A和类B是父子类关系,但Pair[A]和Pair[B]之间是子父类关系 class Pair[-T] {}
非变:类A和类B是父子类关系,但Pair[A]和Pair[B]之间没有关系 class Pair[T] {}