Scala语言
引言:其实代码没有你想象那么难,但是如果你想不到哪里去,就会很难.
学习一个技术或知识点的流程:
大数据技术生态体系
学习Scala的原因:
1)Spara新一代内存级大数据框架,是大数据的重要内容。
2)Spark就是使用Scala编写的,因此为了更好的学习Spark,需要掌握Scala这门语言。
3)Scala是Scalable Language的简写,是一门多范式的编程语言。
4)Spark的兴起,带动了Scala语言的发展。
官网:Scala-lang.org
Scala和Java以及jvm的关系分析图
Scala语言的特点:
Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言。
1)Scala是一门多范式(multi-paradigm)的语言,Scala支持**面向对象和函数式编程(是一个值) ** 表达能力强,代码精简 最优雅
2)Scala源代码(Scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝对接
3)Scala但作为一门语言来说,非常的简洁高效(三元运算符,++,–)
快速有效的掌握Scala的建议:
1】学习Scala语法特有的特性
2】搞清楚Scala和Java的区别
3】如何让规范使用Scala
写第一个Scala语言
//说明
//1.object表示以一个伴生对象,这里我们可以简单的理解就是一个对象
//2.Hello Scala就是对象的名字,他的底层真正对应的类名是Hello Scala$,
// 对象是Hello Scala$ 类型的一个静态对象MODULE$
//3.
object HelloScala{//名字
//前:形参名字 后:形参类型 泛型表示:[String] Unit:相当于Java的void
def main(args:Array[String]):Unit={//主方法
println("hello,scala!~~") //输出:println()
}
}
在IDEA上面开发
第一步创建一个Maven工程等等
在IDEA上创建基于maven工程的Scala项目(创建项目的方式有很多,自己要掌握几套熟练的)
在maven工程里面下载mysql的依赖包jar
//注意版本要配套
//去官网查找maven里的mysql依赖包版本。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
纵览项目结构
查看项目的默认路径
高阶函数要熟练掌握
scala> def xxx(x:Array[String])={
| val fids = x(1).split(" ")
| val odn = x(2).split(" ")
| for(j <- 0 until fids.length){
|
scala> xx.
!= compareTo genericBuilder matches runWith toBuffer
## compareToIgnoreCase getBytes max sameElements toByte
* compose getChars maxBy scan toCharArray
+ concat getClass min scanLeft toDouble
++ contains groupBy minBy scanRight toFloat
++: containsSlice grouped mkString segmentLength toIndexedSeq
+: contentEquals hasDefiniteSize ne self toInt
-> copyToArray hashCode nonEmpty seq toIterable
/: copyToBuffer head notify size toIterator
:+ corresponds headOption notifyAll slice toList
:\ count indexOf offsetByCodePoints sliding toLong
< diff indexOfSlice orElse sortBy toLowerCase
<= distinct indexWhere padTo sortWith toMap
== drop indices par sorted toSeq
> dropRight init partition span toSet
>= dropWhile inits patch split toShort
addString endsWith intern permutations splitAt toStream
aggregate ensuring intersect prefixLength startsWith toString
andThen eq isDefinedAt product stringPrefix toTraversable
apply equals isEmpty r stripLineEnd toUpperCase
applyOrElse equalsIgnoreCase isInstanceOf reduce stripMargin toVector
asInstanceOf exists isTraversableAgain reduceLeft stripPrefix transpose
canEqual filter iterator reduceLeftOption stripSuffix trim
capitalize filterNot last reduceOption subSequence union
charAt find lastIndexOf reduceRight substring unzip
chars flatMap lastIndexOfSlice reduceRightOption sum unzip3
codePointAt flatten lastIndexWhere regionMatches synchronized updated
codePointBefore fold lastOption replace tail view
codePointCount foldLeft length replaceAll tails wait
codePoints foldRight lengthCompare replaceAllLiterally take withFilter
collect forall lift replaceFirst takeRight zip
collectFirst foreach lines repr takeWhile zipAll
combinations format linesIterator reverse to zipWithIndex
companion formatLocal linesWithSeparators reverseIterator toArray →
compare formatted map reverseMap toBoolean
scala> xx.
//只要以后看到有object TestScala ,你应该有这样一个认识
//1.object TestScala对应的是一个Test Scala$的一个静态对象 MODULE$
//2.在我们的程序中,是一个单例模式
object TestScala {
def main(args: Array[String]): Unit = {
println("hello,sca;a,idea...")
var num1:Int = 10
var num2:Int = 20
println(num1+num2)
println("名字\t年龄\t邮件\t性别")
}
}
Scala执行流程分析
Scala程序开发注意事项(重点)
1)Scala源文件以“.Scala”为扩展名
2)Scala程序的执行入口时main()函数
3)Scala语言严格区分大小写、
4)Scala方法由一条一条语句构成,每一个语句后不需要分号(Scala语言会在每行后自动加分号),这也体现了Scala的简洁性。
5)如果在同一行有多条语句,除了最后一条不需要分号,其他语句都需要加分号。
Scala语言转义字符
Scala语言输出的三种方式
1)字符串通过+号连接(类似java)
2)printf用法(类似C语言)字符串通过%传值
3)字符串通过$引用(类似PHP)
代码如下
//案例
object printDemo {
def main(args: Array[String]): Unit = {
var str1:String = "hello"
var str2:String = "world"
//连接起来输出
println(str1 + str2)
var name:String = "tom"
var age:Int = 10
var sal:Float = 10.67f
var height:Double = 180.15
//格式化输出
//保留小数点后面两位三位%.2f $%.3f 输出的值要一一对应
println("名字=%s 年龄是%d 薪水%.2f 身高%.3f",name,age,sal,height)
//Scala支持使用$输出内容,编译器会去解析$对应变量
println(s"个人信息如下:\n 名字$name \n年龄$age \n薪水$sal")
//如果在字符串中出现了类似${age + 10}则表示{}是一个表达式
println(s"个人信息如下:\n 名字${name} \n年龄${age + 10} \n薪水${sal*100}")
}
}
Scala源码的查看的关联
使用Scala过程中,为了搞清楚底层代码的机制,需要查看源码,
1)查看源码,选择要查看的方法或者类,输入CTRL+b
2)关联源码,步骤 1:将我们的源码包拷贝到 scala/lib 文件夹下. scala-sources-2.12.4
步骤 2: 关联即可,选中这个文件夹,进行关联, 最后,可 以看到源码
注释(comment)
注释提高了代码的阅读性,注释是一个程序员必须具有的良好的编程习惯
注释类型:单行注释 多行注释 文档注释
正确的代码风格
正确的缩进和空白
-
使用一次 tab 操作,实现缩进,默认整体向右边移动,时候用 shift+tab 整体向左移
-
或者使用 ctrl + alt + L 来进行格式化 [演示]
-
运算符两边习惯性各加一个空格。比如:2 + 4 * 5。
-
一行最长不超过 80 个字符,超过的请使用换行展示,尽量保持格式优雅
编程最难的两点:(1)业务逻辑(2)性能优化(实现那些性能)
Scala变量的基本使用
object VarDemo01 {
def main(args: Array[String]): Unit = {
var age: Int = 10
var sal: Double = 10.9
var name:String = "tom"
var isPass:Boolean = true
//在Scala中,小数默认为Double,整数默认为Int
var score:Float = 70.9f
println(s"${age} ${isPass}")
}
}
Scala变量声明基本语法
变量声明的基本语法
var|val 变量名 [: 变量类型] = 变量值
var 是可以改变值的 val是不可以改变值(常量值)的,没有线程安全问题,效率高(推荐使用) 两者有一定的区别
Var修饰的对象可以改变,val修饰的则不可以改便,但是对象的状态(值)却是可以改变的(比如L自定义对象,数组,集合等等)
变量声明时,需要初始值。
Scala数据类型介绍
Scala与Java有着相同的数据类型,在Scala中数据的类型都是对象,也就是说Scala没有Java中的原生类型。
Scala数据类型分为两大类AnyRef(值类型)和AnyRef(引用类型),注意,不管是AnyVal还是AnyRef都是对象。
Option下面还有两个子类(1)None (1)Some
Some代表有没有值Some((1,2,3,4))其中Some((1,2,3,4))代表元组
<- 可以理解为 :
to 与 nutil 前面是包括到哪里,后面是不包括到哪里
右面是集合,
步长:默认为1; ifi%==0;i>5
List如果是空的,像相当于List没有new,
流程控制
fou(变量名:数据类型 <- 可遍历对象){
}其中可便利对象:i to j 生成一个[i,j]
i until j 生成一个[i,j)
循环守卫(添加 if 条件表达式,过滤数据)
yield 在 for循环中搜集数据,返回集合
Yield 表示后面的值到了之后就往前送一下。
对上面图的小结整理
1)在Scala中有一个根类型Any,他是所有类的父类,是最顶级的超类,
2)Scala数据类型分为两大类AnyRef(值类型)和AnyRef(引用类型),注 意,不管是AnyVal还是AnyRef都是对象。
3)Null类型是Scala的特别类型,他只有一个值null,他是bottom calss,是所有 AnyRef类型的句子类
4)Nothing类型也是bottom class,他是所有类的子类,在开发中通常可以将Nothing类型的值返回给任意变量或者函数,这里抛出异常很多。
在Scala中仍然遵守,低精度向高精度自动转换(implicit conversion)隐式转换
Scala数据类型列表
变量
数据类型
基本数据类型
类体系结构
流程控制
if
for
while
数组 Array
元组 tuple
集合(4重)
list => ArrayList
=> LinkedList
set => HashSet
Map => HashMap
函数式编程介绍
在学习Scala中将方法,函数,函数式编程和面向对象变成明确一下
1)在Scala中。方法和函数据几乎可以等同(比如他们的定义,使用,运行机制都一样的),只是函数的使用方法更加灵活多样【方法转函数】
2)函数式编程是从编程方式(范式)角度来谈的,可以这样理解:函数式编程吧函数当作一等功名,充分利用函数,支持的函数的多种使用方式。
比如:
在Scala当中,函数是一等功名,像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量,函数的创建不用依赖于类或者对象,而Java当中,函数的创建要依赖于类,抽象类或者接口。
3)面向对象编程是以对象为基础的编程方式。
4)在Scala中函数式编程很面向对象融合在一起了。
object Method2Function {
def main(args: Array[String]): Unit = {
//使用方法
//先创建一个对象
val dog = new Dog
println(dog.sum(10,20))
//方法转成函数,定义默认值 _ ,只能在var里面使用
//数据类型默认值定义时,可以使用“_”,但是只能是var声明的变量
var f1 = dog.sum _
println("f1="+f1)
println("f1="+f1(50,60))
//函数,求两个数之和
val f2 = (n1:Int,n2:Int) => {
n1 + n2 //函数体
}
}
}
class Dog{
//方法
def sum(n1:Int,n2:Int):Int = {
n1+n2
}
}
隐式类型转换:
小的(单精度)往大的(双精度)类型自动转换,大的往小的就会报错,需要使用.toInt进行转换
隐式函数是以implicit关键字声明的带有单个参数的函数。这种函数会将自动应用,将值从一种类型转换成另一种类型。
object ImplicitDemo01 {
def main(args: Array[String]): Unit = {
//编写一个隐式函数转换 Double->Int转换
//隐式函数应当在作用域才能生效
//隐式函数只与函数参数类型和返回值类型有关。
//隐式函数可以有多个(即:隐式函数列表),但是需要保证当前环境下,只有一个隐式函数与之匹配
implicit def f1(d:Double):Int ={//高精度转成低精度
d.toInt
}
val num:Int = 3.5
println("num="+num)
}
}
比如:
var b = 9.6
b:Double = 9.6
var a = 9
a:Int = 9
b = a
//参数类型(前:Double)与返回值类型(后:Int)进行匹配
licit def Double2Int(b : Double) : Int = {
b.toInt
}
a = b
//使用type关键字,定义取别名,可以使用别名声明变量
type 类型别名 = 类型[String]
函数的基本语法
def 函数名 ([参数名:c=参数类型], …) {
语句…
return 返回值
}
1)函数声明关键字def (definition)
2)[参数名:参数类型], …:表示函数的输入(就是参数代表),可以没有。如果有,多个函数使用逗号间隔开
3)函数中的语句:表示为了实现某一共功能代码块
4)函数可以有返回值也可以没有
5)返回值形式1: :返回值类型=
6)返回值形式2: = 表示返回值类型不确定,适用类型推导完成
7)返回值形式3: 表没有返回值,return不生效
8)如果没有return,默认以执行到最后一行的结果返回值。
9)函数式编程:每个函数都是一个值,每一个值都是一个对象,支持高阶函数,柯里化(currying),样例类(case class)(和Java中set/get性质一样)及模式匹配…
10)Scala是一种静态类型语言,扩展性好
面向对象特性
每个值都是对象
对象的数据类型和行为由(Class)和特征(Trait,类似于interface)描述
利用特征实现混入式多重循环
//案例解析
object FunDemo01 {
def main(args: Array[String]): Unit = {
var n1 = 10
var n2 = 20
println("res=" + getRes(1,2,'-'))
}
//定义函数/方法
def getRes(n1:Int,n2:Int,oper:Char) = {
if (oper == '+'){
n1 + n2//返回
} else if (oper == '-'){
n1 - n2
} else {
//返回null
null
}
}
}
函数-递归调用
一个函数在函数体内又调用了本身(自己调用自己)称之为递归调用
函数递归需要遵守的重要的原则(总结)
1)当程序执行一个程序时,就创建一个新的受保护的独立空间(新函数栈)
2)函数局部变量是独立的,不会相互影响
3)递归必须向退出递归的条件逼近,否则就是无限递归,死归了。
4)当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁
package com.atguigu.chapter04.mutlfor
object Exercise03 {
def main(args: Array[String]): Unit = {
//3.打印出九九乘法表
//思路分析
//(1) 使用两层循环, 有 9 行, 每 1 行的列数在增加
//(2) 根据逻辑,我们可以编写代码
val num = 9
for (i <- 1 to num) { //确定行数
for (j <- 1 to i) {//确定列数
printf("%d * %d = %d\t" , j , i , i * j)
}
println()
} } }
//.isInstanceOf[Unit]//查看返回值的类型
//.reverse //逆序的意思,常在循环里面使用
使用 scala 递归的应用案例
题 1:斐波那契数 [学员练习 10min]
请使用递归的方式,求出斐波那契数 1,1,2,3,5,8,13...
给你一个整数 n,求出它的斐波那契数是多少?
题 2:求函数值 [演示]
已知 f(1)=3; f(n) = 2*f(n-1)+1;
请使用递归的思想编程,求出 f(n)的值? 题 3:猴子吃桃子问题
有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃其中的一半,然后
再多吃一个。当到第十天时,想再吃时(还没吃),发现只有 1 个桃子了。问题:最初共多少个桃
子?
代码实现
package com.atguigu.chapter05.recursive
object Exercise01 {
def main(args: Array[String]): Unit = {
/*
题 1:斐波那契数 [学员练习 10min]
请使用递归的方式,求出斐波那契数 1,1,2,3,5,8,13...
给你一个整数 n,求出它的斐波那契数是多少?
*/
println("fbn 的结果是=" + fbn(7))
/*
题 2:求函数值 [演示]
已知 f(1)=3; f(n) = 2*f(n-1)+1;
请使用递归的思想编程,求出 f(n)的值
*/
println(f(2)) //7
尚硅谷 Scala 语言课程
更多 Java –大数据 –前端 –python 人工智能 -区块链资料下载,可访问百度:尚硅谷官网 第 115 页
/*
题 3:猴子吃桃子问题
有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃其中的一半,然后再
多吃一个。当到第十天时,想再吃时(还没吃),发现只有 1 个桃子了。问题:最初共多少个桃子?
*/
println("桃子个数=" + peach(1)) // 1534
}
/*
猴子吃桃子问题
有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃其中的一半,然后再
多吃一个。当到第十天时,想再吃时(还没吃),发现只有 1 个桃子了。问题:最初共多少个桃子
分析思路
1. day = 10 桃子有 1
2. day = 9 桃子有 (day10[1] + 1) *2
3. day = 8 桃子有 (day9[4] + 1) * 2
*/
def peach(day: Int): Int = {
if (day == 10) {
1
} else {
(peach(day + 1) + 1) * 2
}
//题 2 就是简单的套用公式即可
def f(n: Int): Int = {
if (n == 1) {
3
} else {
2 * f(n - 1) + 1
} }
//函数
def fbn(n: Int): Int = {
//分析
//1. 当 n = 1 结果为 1
//2. 当 n = 2 结果是 1
//3. 当 n> 2 是, 结果就是 就是前面两个数的和
if (n == 1 || n == 2) {
1
} else {
fbn(n - 1) + fbn(n - 2)
} } }
函数注意事项和细节讨论
1)函数的形参表可以是多个,如果函数没有形参,调用时 可以不带()
2)形参列表和返回值列表的数据可以是值类型和引用类型。
3)Scala中函数可以根据函数体的最后一行代码自行推断函数返回值类型。那麽在这种情况下,return关键字可以省略
def getSum(n1:Int,n2:Int):Int = {
n1 + n2
}
//可以省略
def getSum(n1:Int,n2:Int)={
n1 + n2
}
4)因为Scala可以自行推断,所以在省略return关键字场合,返回值类型也可以省略
5)如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,这时要明确写成 :返回值类型=,当然如果你什么都不写,即使有return返回值为**()**,这时返回值无效
object Details02 {
def main(args: Array[String]): Unit = {
println(getSum2(10,30))
}
//如果返回值这里买呢什么都没写,即表示该函数没有返回值
//这时return无效
def getSun(n1:Int,n2:Int){
return n1+n2
}
}
//返回值为()
6)如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值
def getSum(n1:Int,n2:Int):Unit = {
return n1 + n2
}
7)如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any)
//什么也不写
def f3(s:String)={注意区别
if(s.length >= 3)
s+"123"
else
3
}
//写高的父类
def f4(s:String):Any={//注意区别
if(s.length >= 3)
s + "123"
else
3
}
8)Scala语法中任何的语法的结构都可以嵌套其他的语法结构(灵活),即:函数中可以在声明/定义函数,类中可以在声明类,方法中可以在声明/定义方法。
9)Scala函数的形式,在生命参数,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会使用默认值,如果指定了实参,则实参会覆盖默认值。
未完待续。。。。。
惰性函数
Java实现懒加载的代码
public class LazyDemo{
public String property;//属性也可能是一个数据库连接,文件等资源
public String getProperty(){
if(property == null){//如果没有初始化过,那么进行初始加
property = initProperty();
}
return property;
}
private String initProperty(){
return"property";
}
}
//比如常用的单例模式懒汉式实现时就使用了上面类似的思路实现。
价绍
当函数返回值被声明为lazy时,函数的执行将被推迟,知道我们首次对此取值,给函数才会被执行。这种函数我们称作为懒性函数,在java的某些框架代码中称之为懒加载(延迟加载)
Scala实现懒汉式加载代码
//关键字:lazy 什么时候需要用到了,才被调用,不忍就不执行了
object lazyDemo01 {
def main(args: Array[String]): Unit = {
lazy val res = sum(10, 20)
println("--------------------------------")
println("res=" + res) //在使用res前,才执行
}
//sum函数,返回和
def sum(n1: Int, n2: Int):Int ={
println("sim()执行了...")
return n1 + n2
}
}
注意事项和细节
1)lazy 不能修饰var类型的变量
2)不但是在调用函数时,加载了lazy,会导致函数的执行被推迟,我们在声明一个变量时,如果给声明lazy,那么变量得分配也会推迟。比如lazy val i = 10
异常处理
介绍:Java异常分为:运行时异常,编译时异常。Scala异常只有运行异常。
Java代码实现
//Java代码实现
public class javaExceptionDemo01 {
public static void main(String[] args) {
try {
//可疑异常
int i = 0;
int b = 10;
int c = b/i;//执行代码时,会抛出Arithmetiception异常
}catch(Exception e){
e.printStackTrace();
}finally {
//最终要执行的代码
System.out.println("java finally");
}
System.out.println("ok~~~继续执行....");
}
}
Java异常处理的注意点。
1)Java语言按照try-catch…-finally的方式来处理异常的
2)不管是有没有异常捕捉,都会执行finally,因为通常可以在finally代码块中释放资源
3)可以有多个atch,分别捕获对应的异常,这时需要把范围小的异常写在前面,把范围大的异常捕获写在后面,否则会出现编译错误,会提示"Exceotion 'java,lang.xxxxxx’has already been caught"
Scala异常处理
object ScalaExceptionDemo {
def main(args: Array[String]): Unit = {
try{
val r = 10/0
}catch {
/*
* 说明:
* 1.在Scala中只有一个catch
* 2.在catch中有多个case,每个case可以匹配一种异常 case ex:ArithmeticException
* 3. => 关键符号,表示后面是对该异常的处理代码块
* 4.finally最重要执行的
* */
case ex:ArithmeticException=> {
println("捕获了除数为零的算数异常")
}
case ex:Exception => println("捕获了异常")
}finally {
//最重要执行的代码
println("scala finally...")
}
println("ok,继续执行。。")
}
Scala异常处理小结:
1)我们将可疑异常代码封装在try块中。在try块之后使用一个catch处理程序来捕获异常。如果发现任何一场,catch处理程序奖处理它,程序将不会异常终止
2)Scala的异常的工作机制和Java一样,但是Scala没有“checked(编译器)”异常,即Scala没有编译异常概念,一场都是运行的时候捕捉处理的。
3)使用throw关键字,可以抛出一个异常对象,所有的一场都是Throw able的子类。throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型
def test(): Nothing = {
throw new ArithmeticException("算术异常")//Exception("异常 NO1 出现~")
}
- 在 Scala 里,借用了模式匹配的思想来做异常的匹配,因此,在 catch 的代码里,是一系列 case
子句来匹配异常。,当匹配上后 => 有多条
语句可以换行写,类似 java 的 switch case x: 代码块…
- 异常捕捉的机制与其他语言中一样,如果有异常发生,catch 子句是按次序捕捉的。因此,在 catch尚硅谷 Scala 语言课程
子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常
写在后,在 scala 中也不会报错,但这样是非常不好的编程风格。
- finally 子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清
理工作,这点和 Java 一样。
- Scala 提供了 throws 关键字来声明异常。可以使用方法定义声明异常。 它向调用者函数提供了
此方法可能引发此异常的信息。 它有助于调用函数处理并将该代码包含在 try-catch 块中,以避免程序
异常终止。在 scala 中,可以使用 throws 注释来声明异常
def main(args: Array[String]): Unit = {
f11()
}
@throws(classOf[NumberFormatException])//等同于 NumberFormatException.class
def f11() = {
"abc".toInt
}
函数随堂练习—九九乘法表
//九九乘法表
import scala.io.StdIn
object Exercise01 {
def main(args: Array[String]): Unit = {
println("请输入数字(1~9)之间的数")
val n = StdIn.readInt()
println99(n)
}
//编写一个函数,树池99乘法表
def println99(n: Int)={
for (i <- 1 to n){
for (j <- 1 to i){
println("%d*%d = %d\t",j,i,j*i)
}
println()
}
}
}
面向对象 ?
Java是面向对象的语言编程,由于历史的原因,Java中还存在着非面向对象的内容:基本类型,null ,静态方法等。
Scala语言来自于Java,所以天生就是面向对象语言,而且Scala是存粹的面向对象语言,即在Scala中,一切皆为对象。
Java与Scala相互对比着学习。
面向对象编程(基础部分)
类,抽象类,进程,接口,单例对象,样例类
类和对象的关系?
答,类相当于模板,任何根据模板创建一个一个对象 。
通过new关键字创建实例。
方法默认public ,修饰符:private,protected,public
在Scala中,类中无法定义静态成员变量和方法
类无需明确定义构造方法
重点部分—>面向对象编程()
//如何创建类?
class A(xc:Int,yc:Int){
var x:Int = _
var y:Int = _
def move(dx:Int,dy:Int) ={
x = x +dx
y = y +dy
}println("---------------------")
}
object test{
def main(args:Array[String]):Unit = {
val s = new A()
}
}
//java 中创建类的方法
public class B{
int a = 0;
int b = 0;
public B(){}
public B(int a,int b){
this.a = a
this.b = b
}
}
//养猫快速入门
object CatDemo {
def main(args: Array[String]): Unit = {
//创建一只猫
val cat = new Cat
//给猫的属性
/*
* 说明
* 1.cat.name = "小白"其实不是直接访问属性,而是cat.name_$eq("小白")
* 2.cat.age = 等价于 cat.name()
* */
cat.name = "小白"//等价
cat.age = 10
cat.color = "白色"
println("ok")
printf("\n小猫的信息如下:%s %d %s",cat.name,cat.age,cat.name)
}
}
//定义一个类Cat
//一个class Cat 对应的字节码文件只有一个 Cat.class,默认是public
class Cat {
//定义/声明三个属性
//1.当我们声明了var name:String时,在底层对应private name
//2.同时会生成 两个public方法name() <=类似=> getter public name_$eq() =>setter
var name:String = "" //给初始值
var age:Int = _ //_ 表示给age一个默认的初始值,如果Int默认是0
var color:String = _ //_ 给color默认值,如果String,默认就是“”
}
类和对象的区别和联系
1)类是抽象的,概念的,代表一类事物,比如人类,猫类
2)对象是具体的,实际的,代表一个具体的事务
3)类是对象的模板,对象是类的一个个体,对应一个实例
4)Scala中类和对象的区别和联系和Java中是一样的
如何创建对象
基本语法
val | var 对象名[: 类型] = new 类型()
说明:
1)如果我们不希望改变对象的引用(即:内存地址),应该声明为val性质的,否则声明var,scala设计者推荐使用val。(应为我们一般只改变)对象的属性值,而不是改便对象的应用值。
2)Scala在声明对象变量时,可以根据创建对象的类型自动判断,所以声明类型就是可以省略,但是当类型和后面的new对象类型有继承关系即多态时,就必须要写了。
//如何创建对象
object MemState {
def main(args: Array[String]): Unit = {
val p1 = new Person2
p1.name = "jack"
p1.age = 10
val p2 = p1
println(p1 == p2)//true
p1.name = "tom"
println("p2.name="+p2.name )
}
}
//先写class类,注意默认值使用时,需要只当类型
class Person2{
var name = ""
//如果是用_ 方式给默认值,则属性必须指定类型
var age:Int = _
}
scala 使用继承时依然使用extends关键字,重写非抽象方法,都要加override关键字。继承的作用:拓展父类中的所有方法(抽象类等)
匿名函数
只不含函数名称的函数
匿名函数的定义
“=>”左面为参数列表(参数列表)=>(函数体)
“=>”右面为函数体
(x:Int)=>x*x
(x:Int)=>{
println(x);x*x
}
() => {
System.getProperty("user.dir")
}
val f1=(x:Int)=>{
println(x);x*x
}
f1(2)
高阶函数
高阶函数可以将其他函数作为参数或者使用函数作为输出结果
常用高阶函数
高阶函数是指使用其他函数作为参数,或者返回一个函数作为结果的函数。在Scala中函数是一等功名,所以允许定义高阶函数,我们约定,使用函数值作为参数,或者返回值为函数值的“函数”和"方法",均称之为“高阶函数”
//重点
map //映射
foreach
filter
fold、foldLeft、foldRight
reduce
zip
flatten
flatMap
//函数作为参数
def doSquare(f:Int=>Int,p:Int)=f(p)
def square(x:Int):Int=x*x
doSquare(square,square(2))
//函数作为返回值
//返回类型为函数(Int=>Int)
def doSquare()={ //无参的
(x:Int)=>x*x
}
doSquare()(2)
//高阶函数简单示例,演示高阶函数的特点
//定义一个函数kk
scala> var kk=(x:Int)=>x*x+1
//把后面函数体完全看成一个变量,然后就能传递变量,发明会变量了。
kk: Int => Int =<functionl>
//abc是一个空壳函数,上面定义的函数kk调入空壳函数里面执行命令。
//只是把函数作为参数传给abc,abc相当于空壳一样的函数,传进来就执行了。
//真正的业务被封装在函数里面,然后再把这个函数传给别人,按照命令执行就行了。
//高阶函数还可以作为返回值,一般是作为参数。
scala> abc(4,kk)
17
函数柯里化?
隐式参数?关键字: implicit
命名参数,参数缺审值?
伴生类与伴生对象?
特点:
特质:
1)Scala中没有接口(interface)的概念
2)特质用于在类在类之间共享程序接口和字段,类似Java接口
3)特质是字段和方法的集合,可以提供字段和方法实现
4)类和单例对象都可以扩展特质(extends)
5)特质不能被实例化,因此没有构造参数,类似Java接口
6)特质使用“trait”关键字定义
7)实现特质中的方法使用“override”
Scala数据结构(上)—集合
Scala集合基本应用介绍
1)Scala同时支持不可变集合和可变集合,不可变集合可以安全的并发访问
2)两个主要的包:
不可变集合:scala.collection.immutable
可变集合:scala.collection.mutable
3)Scala默认采用不可变集合,对于几乎所有版本的集合类,Scala都同时提供了可变(mutable)和不可变(immutable)的版本
4)Scala的集合有三大类,序列Seq,集Set,映射Map,所有的集合都扩展自lterable特质,在Scala中集合有可变(mutable)和不可变(immutable)两种类型。
可变与不可变的区别:
1)不可变集合:Scala不可变集合,就是这个集合的本身不能动态变化(类似于Java数组,是本身长度不可变)
2)可变集合:可变集合,就是这个集合本身可以动态变化的(比如:Array List,是可以动态增长的)
关键字: .hashCode()
import java.util.ArrayList;
public class javaCollection {
public static void main(String[] args) {
//不可变集合类似Java的数组,一旦固定,就无法扩展
int[] nums = new int[3];
nums[2] = 11;
nums[2] = 22;
//可变集合,两次输出的地址不一样
ArrayList a1 = new ArrayList<String>();
a1.add("zs");
a1.add("ls");
System.out.println(a1+""+a1.hashCode());//地址1
a1.add("ww");
System.out.println(a1+""+a1.hashCode());//地址2
}
}
结果:
[zs, ls]125231
[zs, ls, ww]3885969
两次地址不一样
远观Scala集合
不可变集合:IndexeSeq/LinearSeq
小结:不可变集合
1)Set,Map是Java中特有的集合
2)Seq是Java中没有的集合,我们发现List归属到Seq里面了,因此List就是和Java不是同一个概念了
3)我们将前面的for循环有一个1 to 3,就是IndexedSeq下的Vector
4)String也属于IndexeSeq
5)我们发现经典的数据结构比如Queue和Stack被归属到LinearSeq
6)大家注意Scala中的Map体系有一个Sorted Map,说明Scala的Map可支持排序
7)Seq序列(有序)分为(1)IndexedSeq(索引序列)(2)LinearSeq(线性序列)
IndexedSeq索引序列访问数据方式可以通过下标访问(索引速度比线性序列速度快):Range,Array(数组),String(字符串),Vector,NumericRange
LinearSeq线性序列(有头有尾)通过链表或者(数组+链表)形成Hash结构底层,但是应用场景比较多:队列(Queue),栈(Stack),Lint,Stream 这种数据结构一般通过遍历来查找,他的价值在于应用到一些具体的应用场景(电商网站,大数据推荐系统:最经浏览的10个商品等)
可变集合:IndexeSeq/LinearSeq/Buffer
小结可变集合:
与不可变集合相比:Seq下面多了Buffer(作用:缓冲,缓存):ArrayBuffer就是可变的,ListBuffer可变的,Synchronized Buffer(同步Buffer),ObservableBuffer(观察者Buffer)
1)在可变集合中比不可变集合更加丰富,在Seq集合中,增加了Buffer集合,将来开发过程中,我们常用Array Buffer和List Buffer
2)如果涉及到线程安全,则选择使用Synchronized Buffer(同步Buffer),其他说明和不可变集合相似。
名称 | 可变**/**不可变 | 示例 |
---|---|---|
Buffer | mutable | val buffer = scala.collection.mutable.ArrayBuffer[Int](10, 20, 30); buffer+=(2,3) |
Array | mutable | val arr=Array(1,2,3) |
List | immutable | val lst=List(1,2,3) |
Map | mutable | val stu= Map(“name” -> “Jason”, “age” -> “18”) |
Set | mutable/immutable | val set=Set(1,2,3) |
Vector | immutable | val v=Vector(1, 3, 5, 7, 11, 13) |
Stack | mutable/immutable | val st=scala.collection.mutable.Stack(1,2,3) //堆栈,先进后出 |
Queue | mutable/immutable | val q=scala.collection.mutable.Queue(1,2,3) //队列,先进先出 |
BitSet | mutable/immutable | val bit=scala.collection.mutable.BitSet(3,2,0) //位集合 |
ListMap | immutable | val map = scala.collection.immutable.ListMap(1->“one”, 2->“two”) |
HashSet | mutable | val set= scala.collection.mutable.HashSet(1,2,3) |
HashMap | mutable | val stu= scala.collection.mutable.HashMap(“name” -> “Jason”, “age” -> “18”) |
数组定义(声明泛型)
第一种方式
第一种方式定义数组:val arr1 = new Array [Int] (10) // [ ]: 表示泛型 ,():表示定义数组长度,莫热门 每个数组长度为0
//赋值,集合元素采用小括号访问 arr1(1) = 7
代码演示:
//代码演示
object ArrayDemo01 {
def main(args: Array[String]): Unit = {
//说明
//1.创建了一个Array对象.
//2.[Int] 表示泛型,即该数组中,只能存放Int
//3.[Any] 表示 该数组可以存放任意类型
//4.在没有赋值的情况下,各个元素的值默认为 0
//5. arr01(3) = 10 表示修改 地4个元素的值
val arr01 = new Array[Int](4)
println(arr01.length)//4
println("arr01(0)="+arr01(0))//0
//数组的遍历
for (i <- arr01){
println(i)
}
println("------------------------------")
arr01(3) = 10
for (i <- arr01){
println(i)
}
}
}
数组定义:第二种方式
在定义数组时,直接赋值
//使用spply方法创建数组对象
val arr1 = Array(1,2)
代码演示
object ArrayDemo02 {
def main(args: Array[String]): Unit = {
//说明
//1.使用的是 object Array 的 apply
//2. 直接初始化数组,这时因为你给了整数和 " ",这个数组的泛型就是Any
//3.遍历房四海一样
var arr02 = Array(1,3,"xx")
arr02(1) = "xx"
for (i <- arr02) {
println(i)
}
//可以使用我们传统的方式遍历,使用下标的方式遍历
for (index <- 0 until arr02.length){
println("arr02[%d]=s",index,arr02(index)+"\t")
}
}
}
变长数组(声明泛型)
//定义/声明
val arr2 = ArrayBuffer[Int] () //后面必须指定泛型,()可以不写数值
//追加值/元素
arr2.append(7) 追加就用append()
//重新赋值
arr2(0) = 7
//学习集合就是(创建,查询,修改,删除)
代码演示
import scala.collection.mutable.ArrayBuffer
object ArrayBufferDemo01 {
def main(args: Array[String]): Unit = {
//创建ArrayBuffer
val arr01 = ArrayBuffer[Any](3,2,5)
//通过下标访问元素
println("arr01(1)="+ arr01(1))//指定输出返回值的下标
//遍历
for (i <- arr01){
println(i)
}
println(arr01.length)
println("arr01.hash="+arr01.hashCode())
//修改 [修改值,动态增加]
//使用append追加数据,append支持可变参数
//{3,2,5,90,0,13}
arr01.append(90.0,13)//其实就是先创建对象,把原来的老数据导进去这就是数组的扩容
println("arr01.hash="+arr01.hashCode())
arr01(1) = 89//修改{3,89,5,90,0,13}
println("--------------------------------")
for (i <- arr01){
println(i)
}
//删除,是根据下标删除(还可以指定从起点到终点的删除)
arr01.remove(0)//关键字:remove() 其中的0表示把第0个数组删除
println("---------------删除后的元素遍历------------------")
for (i <- arr01){
println(i)//89,5,90,0,13
}
println("最新的长度="+arr01.length)//4
}
}
小结:数组变长(声明泛型)
1)ArrayBuffer是变长数组,类似于Java中的ArrayList
2) val arr2 = ArrayBuffer [Int] () 也就是使用apply方法构建对象
3)def append(elems: A*){appendAll(elems) }接收的是可变参数
4)每append一次,arr在底层就会重新分配空间,进行扩容,arr2的内存地址会发生改变,也就成为新的ArrayBuffer
定长数组与变长数组的转换
说明
在开发中,我们可能使用对定长数组和变长数组,进行转换
arr1.toBuffer //定长数组转可变数组
arr2.toArray //可变数组转定长数组
注意事项:
arr2.toArray 返回结果才是一个定长数组, arr2 本身没有变化
arr1.toBuffer 返回结果才是一个可变数组, arr1 本身没有变化
代码演示
package com.atguigu.chapter10
import scala.collection.mutable.ArrayBuffer
object Array22ArrayBuffer {
def main(args: Array[String]): Unit = {
val arr2 = ArrayBuffer[Int]()
// 追加值
arr2.append(1, 2, 3)
println(arr2)
//说明
//1. arr2.toArray 调用 arr2 的方法 toArray
//2. 将 ArrayBuffer ---> Array
//3. arr2 本身没有任何变化
val newArr = arr2.toArray
println(newArr)
//说明
//1. newArr.toBuffer 是把 Array->ArrayBuffer
//2. 底层的实现
/*
override def toBuffer[A1 >: A]: mutable.Buffer[A1] = {
val result = new mutable.ArrayBuffer[A1](size)
copyToBuffer(result)
result
}
*/
//3. newArr 本身没变化
val newArr2 = newArr.toBuffer
newArr2.append(123)
println(newArr2)
// //案例演示+说明
} }
数组–多维数组
//定义
val arr = Array.ofDim [Double] (3,4)
//说明:二维数组中有三个一维数组,每个一维数组里面有四个元素(l理解:三行四列
//赋值 arr (1)(1) = 11.11 //第一个1,代表第一个元素,第二个1,代表第一个元素里面的第1个元素
object MultiplyArray {
def main(args: Array[String]): Unit = {
//创建
val arr = Array.ofDim[Int](3, 4)
//遍历
for (item <- arr) { //取出二维数组的各个元素(一维数组)
for (item2 <- item) { // 元素(一维数组) 遍历
print(item2 + "\t")
}
println()
}
//指定取出
println(arr(1)(1)) // 0
//修改值
arr(1)(1) = 100
//遍历
println("=====================")
for (item <- arr) { //取出二维数组的各个元素(一维数组)
for (item2 <- item) { // 元素(一维数组) 遍历
print(item2 + "\t")
}
println()
}
//使用传统的下标的方式来进行遍历
println("===================")
for (i <- 0 to arr.length - 1) { //先对
for (j <- 0 to arr(i).length - 1) {
printf("arr[%d][%d]=%d\t", i, j, arr(i)(j))
println()
}
}
}
在Scala中可以通过map映射操作来解决:将集合中的每一个元素通过指定功能(函数)映射(转换)成新的结果集合这里其实就是所谓的将函数作为参数传递给另外一个函数,这是函数式编程的特点。
以HasheSeq为例说明
def map [B] (f:(A) => B) : HashSet[B] //map函数的签名
1)这个就是map映射韩书集合类型都有
2)[B] 是泛型
3)map 是一个高阶函数(可以接受一个函数的函数),可以接收函数:f:(A>B)
4)HashSeq [B] 就是返回的新的集合
问题1:while循环与dowhile相比较特点
步长相关问题?
//答:by关键字表示
scala>List(1 to 100 by 2:_*) map (i=>i*i) sum
res01:Int = 166650
Scala元组?
与列表一样,元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素。
元组的值是通过将单个的值包含在圆括号中构成的
与列表一样,元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素。
元组的值是通过将单个的值包含在圆括号中构成的
val t = (1,3.14,"Fred")//对应的类型分别为[Int,Double,java.lang.String]
目前Scala支持的元组最大的长度为22,再大ixie建议使用集合
val t = (1,2,3,4)
迭代元组
可以使用Tuple.productlterator()方法来迭代输出元组的所有元素:
object Test{
def main(args:Array[String]){
val = {1,2,3,4}
t.productIterator.foreach{
i => println("Value = "+i)
}
}
}
输出结果为:
$ scalac Test.scala
$ scala Test
Value = 4
Value = 3
Value = 2
Value = 1
元组转为字符串
使用Tuple.toString()方法将元组的所有元素组合成一个字符串
object Test{
def main(args:Array[String]){
val t = new Tuple(1,"hello",Console)
println("连接后的字符串为:"+t.toString())
}
}
输出结果为:
$ scalac Test.scala
$ scala Test
连接后的字符串为: (1,hello,scala.Console$@4dd8dc3)
数组相关问题?
//声明数组
var z:Array[String] = new Array[String](3)
或
var z = new Array[String](3)
以上语法中,z 声明一个字符串类型的数组,数组长度为 3 ,可存储 3 个元素。我们可以为每个元素设置值,并通过索引来访问每个元素,如下所示:
z(0) = "Runoob"; z(1) = "Baidu"; z(4/2) = "Google"
最后一个元素的索引使用了表达式 4/2 作为索引,类似于 z(2) = "Google"。
我们也可以使用以下方式来定义一个数组:
var z = Array("Runoob", "Baidu", "Google")
处理数组
//数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用for循环
object Test{
def main(args:Array[String]){
//输出说有数组元素
for(x <- myList ){
println(x)
}
//计算数组所有元素的总和
var total = 0.0;
for(i <- 0 to (myList.length - 1)){
total += myList(i);
}
println("总和为"+total);
//查找数组中最大元素
var max = myList(0);
for(i <- 1 to (myList.length - 1)){
if(myList(i) > max = myList(i));
}
println("最大值为"+max)
}
}
集合问题?
//Scala 中的 Map 介绍
//1) Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,Scala
//中不可变的 Map 是有序的,可变的 Map 是无序的。
//2) Scala 中 , 有 可 变 Map (scala.collection.mutable.Map) 和 不 可 变
//Map(scala.collection.immutable.Map)
Map-构建 Map
10.20.1 方式 1-构造不可变映射
Scala 中的不可变 Map 是有序,构建 Map 中的元素底层是 Tuple2 类型。
代码如下:
object MapDemo01 {
def main(args: Array[String]): Unit = {
//1.默认 Map 是 immutable.Map
//2.key-value 类型支持 Any
//3.在 Map 的底层,每对 key-value 是 Tuple2
val map1 = Map("Alice" -> 10, "Bob" -> 20, "Kotlin" -> "北京")
println(map1)
}
可变的映射(无序Map)
构造可变映射
//1.从输出的结果看到,可变的 map 输出顺序和声明顺序不一致
val map2 = mutable.Map("Alice" -> 10, "Bob" -> 20, "Kotlin" -> "北京")
println(map2)
方式 3-创建空的映射
val map3 = new scala.collection.mutable.HashMap[String, Int]
println(map3)
方式 4-对偶元组
说明
即创建包含键值对的二元组, 和第一种方式等价,只是形式上不同而已。
对偶元组 就是只含有两个数据的元组。
代码演示
//方式 4-对偶元组
val map4 = mutable.Map(("Alice" , 10), ("Bob" , 20), ("Kotlin" , "北京"))
println("map4=" + map4)
Scala构造器?
隐式函数?、Nil:空list(空列表)
val num:Int = 10;
val retVal = for(i:Int <- 1 to num)yield i*2
for(a <- retVal){
println(a)
}
//数组
var a:Array[Int] = Array[String]
a1(0)
scala> c.foreach
override def foreach[U](f:Int => U):Unit
入表达式f:Int => U
Scala>c.map(f=>f*2)
res4: Array[Int] = Array(2,4,6)
scala>c.map(f=>(f,1))
res5: Array[(Int,Int)] = Array(1,1),(2,1),(3,1)
scsala> var tpl = ("zs","ls","ww")
克隆接口:深克隆/浅克隆
scala> tpl.productElement(2)
//按照下标拿函数
res6: Any = 123
Scala> tpl.productPrfix
res7:String = Tuple3
scala> tpl.zipped //压缩
Scala>tpl.invert //函数柯里化
scala>tpl.producIterator.foreach
scala>def mike = 123 -> 3
mike:(Int,Int) = (123,3)//键值队,前面是键后面是值,好处就是去重统计比较方便,可以编程元组,利用元组可以分区。
混合数组和对象解构方法,可以写循环,一个数组里面可以套很多
var{
"na","ag"
}={
"name":"zs"
"age":40
}
na
scala> val words=("hello","world","ccc")
words: (String,String,String) = (hello,....)
scala> var wds = words.productIterator.map(f=>(f,1))
wds: Iterator[(Any,Int)] = non-empty iterator
scala>wds.for
forall foreach formatted
scala> wds.foreach(f=>println(f))
(hello,1)
(world,1)
(ccc,1)
scala>val wds = word.productIterator.map(f=>(f,1)).toList
scala>wds
wds:List[(Any,Int)] = List((hello,1),(),())
scala>for(k <- wds){
println(k)
(hello,1)
(world,1)
(ccc,1)
}
scala> for(k <- wds){
println(k._1)
}
hello
world
ccc
scala> for((k,v) <- wds){
println(k,":",v)
}
(hello,:,1)
(world,:,1)
(ccc,:,1)
List —> ListBuffer
HshMap
scala>c+=表示put加入变量
Scala>e++=hm 两者的区别
e ++: hm e c都是是可变集合 hm是不可变集合
单+是 加数据
双+ 是合并两个集合
永远把可变的放在前面
表达式中,有一个变量是不可变的变量,使用++:则结果还是不可变,如果用++=则结果为可变的
– 与 - 区别和+ ++相似。
Map,Set,seq 和下面的紫色方框。都要整点掌握。
泛型类 [T]
栈:先进后出,top push pop
//测试类
object TestGeneric{
def main(atgs:Array[String]):Unit = {
val ms = new Stack[Int]()
ms.push(10)
ms.showElements()
ms.push(20)
ms.showElements()
val t = ms.pop()
peintln("----------------")
println("t = "+ t1)
ms.showElements()
}
}
class Stsck[T]{
var elements:List[T] = Nil
def push(x:T){elements = x:: elements}
def top:T = elements.head
def pop(){
var t = elements.head
elements = elements.tail
t//zaiScala中直接写返回值
}
def showElements(){
elements.foreach(x=>print(s"$x"))//(s"$x")使用 x=>
println()
}
}
协变:class Foo[+T]//协变类
对于两种类型A和B,如果A是B的子类型,那么Foo[A]就是Foo[B]的子类型
逆变:class Bar[-T]//你便类
对于两种类型A和B,如果A是B的子类型,那么
//协变
class TestXiebian{
//A是B的子类
//Foo[A]也是Foo[B]的子类
def main(args:Array[String]):Unit = {
val a :Foo[AAAA] = new Foo[AAAA]()
val b :Foo[BBBB] = new Foo[AAAA]()
// //Foo[B]也是Foo[A]的子类,
//书写格式不饿能写反了
val b :Foo1[AAAA] = new Foo[BBBB]()
}
}
class BBB{}
class AAAA extends BBB{}
class Foo[+T]{}
classFoo1[-T]{}
内部类:一个类可以作为另一个类的成员,成为内部类
Java内部类是外部类的成员:任何一个外部类对象创建的内部类对象
Scala内部类绑定到外部类的对象实例
//java内部类
oublic class InnerClassTest{
//创建了两个内部类对象
public static void main(String[] args){
Graph g = new Graph()
Graph g1 = new Graph()
Graph.Node node = g.new Node();
Graph.Node node1 = g1.new Node();
node.test(node);
node.test(node1);//两个 类型相同
//Scala内部类绑定到外部类对象的实例
}
}
Scala正则表达式
Scala支持多种正则表达式解析方式
String.matches()方法
正则表达式模式匹配
scala.util.matching.Regex.API
val ZipcodePatten = "([a-zA-Z][0-9][a-zA-Z] [0-9][a-zA-Z][0-9])".r"L3R 6M8"match{
case ZipcodePatten(zc1,zc2) => println(zc1)
case zc => println("")
}
scala.util.matching.Regex
findFirstMatchln()返回第一个匹配
findAllMatchln返回所有匹配结果(Regex.Match)
findAllIn()返回所有匹配结果(String)
按己渡人。
scala 高级使用
思想:做项目最后是工具的统一和通用性的提取,最终提取一个高效的发工具,项目专用型工具(通用型工具),这就会生成又是接口又是特质类的原因,项目要不断地更新迭代,只有这样才会更加通用,这样才会有很多人用。
写代码的进展:
(1)要会写代码,能把事情做了 (2)能把代码熟练,玩的溜( 3)提接口,提特质,提抽象类,让自己代码能写成工具大样式,供大家使用 (4)自写框架
年轻人最缺乏的就是定性,恒心毅力,沉得住气,看得清形式这才是你能走上领导岗位的可能,要有底,给人能定得住心的感觉。一般情况下,不是那种特大情况下,你要静下心来思考。最重要的事情与最紧急的事相互协调转换。
特质trait
带有特制的对象,动态混入,真正实现解耦。
ocp原则(闭合原则,修改源代码关闭,功能扩展开放)
1)除了可以在声明类时继承特之外,还可以在构建对象时混入特质,扩展目标的功能,可以应用于对抽象类功能进行扩展
2)动态混入是Scala特有的方式(Java没有动态混入特质),可在不修改类声明/定义的情况下,扩展类的功能,偶合性低
3)动态混入可以
正则表达式:
package com.atguigu.chapter08.mixin
import scala.util.Failure
object TestAllCatch {
def main(args: Array[String]): Unit = {
scala.util.control.Exception.allCatch.toTry("42".toInt) match{
case i:Int => println(i)
case Failure(e) => println(e)
}
}
}