Scala学习

Scala

1、基础知识

/**
 * 变量:在程序的运行过程中,其值可以发生改变的量
 * 在scala中定义一个变量,需要使用一个关键词:var
 *
 * 常量:在程序的运行过程中,其值不可以发生改变的量
 * 在scala中定义一个变量,需要使用一个关键词:val
 *
 * 注意:
 * 1、变量一旦定义,它的类型就确定,可以不用手动指定类型,根据赋的值自动推断出类型
 * 2、也可以手动的指定变量的数据类型,完整的写法:var 变量名:数据类型 = 值
 *
 * scala中的数据类型和java的数据类型对应关系:
 * java:              scala:
 * byte                Byte
 * short               Short
 * int                 Int
 * long                Long
 * float               Float
 * double              Double
 * boolean             Boolean
 * char                Char
 */
 
 * 其实是一个函数,底层是通过StringBuilder链接字符的
     /**
     * scala中字符串的使用
     * 字符串:由若干个字符组成的序列
     */

查看变量数据类型

var a = 100
println(a)
println(a.getClass)

100
int
200
 Scala 中使用三重双引号 (""") 定义的多行字符串,并且使用 stripMargin 方法去除每行开头的垂直线。这种方式在处理 SQL 查询语句等多行字符串时非常常见。
var d:String =
"""
 |select
 |*
 |from
 |pf
 |""".stripMargin
println(d)

select
*
from
pf
java中String类中的功能在scala中正常使用
var e = "python,java,scala,spark"
val arr: Array[String] = e.split(",")
//简式写法 val arr: Array[String] = e split ","
println(arr)
println("=" * 50)
//scala中的数组和java中的数组一样,也是有索引的,也是从0开始的 注意:索引使用小括号括住
println(arr(0))
println(arr(1))
println(arr(2))
println(arr(3))

[Ljava.lang.String;@36d64342
==================================================
python
java
scala
spark
/**
 * 在scala中字符串是如何做拼接的?
 * 1、使用+号拼接 这种拼接方式比较消耗性能
 * 2、使用StringBuilder
 * 3、前提:有一组序列,使用scala特有的函数 mkString
 * 4、使用scala特有的字符串传递方式 s"${变量}" 底层就是使用StringBuilder方式拼接的
 */
var res1 = a1 + "," + a2 + "," + a3

println(res1)

val res2 = new StringBuilder()
res2.append(a1).append("-").append(a2).append("-").append(a3)
println(res2)

val res3: String = arr.mkString("&")
println(res3)

val res4 = s"${a1}#${a2.toUpperCase()}#${a3.toUpperCase}"
println(res4)


I,love,you
I-love-you
python&java&scala&spark
I#LOVE#YOU

Scala只能读文件,不能写文件

//读取文件
val bs: BufferedSource = Source.fromFile("scala/data/words.txt")
val iterator: Iterator[String] = bs.getLines()
while (iterator.hasNext){
val str: String = iterator.next()
println(str)
}

//使用for循环遍历文件内容
for (e <- iterator){
println(e)
}

hello|world
java|hadoop|linux
java|scala|hadoop
hive|java|hello|world

2、异常

scala中的异常和java的很像
package com.shujia.jichu

import java.io.{BufferedReader, FileNotFoundException, FileReader}
import java.util.Scanner


object Demo4Exception {
  def main(args: Array[String]): Unit = {
    /**
     *  scala中的异常和java的很像
     */
    try{
      println(10/0)
      val arr: Array[Int] = Array(1, 2, 3, 4, 5)
      println(arr(5))
      val br: BufferedReader = new BufferedReader(new FileReader("scala/data/words888.txt"))
      /**
       * 也可以手动的抛出异常
       */
      val scanner = new Scanner(System.in)
      print("请输入一个除数:")
      val i: Int = scanner.nextInt()
      if(i!=0){
        println(10/i)
      }else{
        throw new ArithmeticException("你输入的除数为0")
        //自己抛出的异常也会被下面的cath所捕获,且系统的错误提示为自己定义抛出的
      }
    }catch {
      //类似于sql语句中case when
      case e:ArithmeticException=>
        e.printStackTrace() //系统的错误提示
      //println("除0异常") //自定义错误提示
      case e:ArrayIndexOutOfBoundsException=>
      println("数组越界异常")
      case e:FileNotFoundException=>
      println("系统找不到指定的文件")
      //在Scala的模式匹配中,_ 符号通常用作通配符,表示匹配任何值。因此,case _ => 会捕获所有未被前面具体case语句匹配的情况。
      //当该语句放到最前面时则可匹配到任何异常,无法去下面找到具体的异常
      case _=>
      println("出现异常")

    }finally {
      //今后finally中的处理大部分情况下都与释放资源有关
      println("这是finall代码块")
    }
    //当捕获到异常后才能正常打印,否则不能打印。当try代码有多个错误时,当第一个错误被捕获时就不会执行下面有错误的代码了
    println("hello world")
  }

}

3、函数

函数特点

  /**
   * def: 定义函数或者方法的关键字
   * main: 是函数或者方法的名字,符合标识符的命名规则
   * args: 函数形参的名字
   * Array[String]: 参数的数据类型是一个元素为字符串的数组
   * =: 后面跟着函数体
   * Unit: 等同于java中的void 表示无返回值的意思
   * 在不同的地方定义,称呼不一样
   * 函数:在object中定义的叫做函数
   * 方法:在class中定义的叫做方法
   * scala中调用函数必须在函数定义之后
   *调用类里的方法必须要用类的对象调用
   */

def main(args: Array[String]): Unit = {
    //函数体
}

函数的定义

//定义格式一:如果函数有返回值,且最后一句话作为返回值的话return可以不写
def add3(a: Int,b: Int): Int = {
    a + b
}

//定义格式二:如果函数体只有一句话大括号也可以不写
def add4(a: Int,b: Int): Int = a + b

//定义格式三:如果函数没有参数时小括号也可以不写
def show = println("鹏飞是飞蓬大将军")

函数的调用

//调用方式一:Object中的函数可以使用列名调用,类似于静态方法一样
val res4: Int = Demo5Function.add(20, 30)
println(res4)

//调用形式2:object中的函数调用时,可以省略类名
val res4: Int = add(20, 30)
println(res4)

Scala中的递归

object Demo6Function {

  /**
   * scala中的函数也可以递归
   * 方法定义时,调用自身的现象
   * 条件:要有出口,不然就是死递归
   */


  def main(args: Array[String]): Unit = {
    val res: Int = jieCheng(5)
    //当只有一个变量时可以省去大括号
    println(s"5的阶乘是:$res")

    //当调用的方法只有一个参数时
    println(s"5的阶乘是:${Demo6Function jieCheng 5}")
  }


  //求出5的阶乘
  def jieCheng(number: Int): Int = {
    if(number == 1){
      1
    }else{
      number * jieCheng(number - 1)
    }
  }
}

scala中的类与构造方法

class Student(name: String,age: Int){
  //当创建对象时自动打印,相当于对象的初始化
  println("鹏飞你好牛啊")
  /**
   * 定义成员变量
   */
  val _name: String = name
  val _age: Int = age
  var _gender: String = _  这个下划线其实就是起到一个占位的作用,就表示将来会赋予默认值
  /**
   * 构造方法也可以写多个
   */
  //在Scala中,一个辅助构造函数(auxiliary constructor)可以通过调用同一个类的其他构造函数来初始化对象。
  // 您尝试调用了另一个构造函数 this(name: String, age: Int),这是合法的用法,用来避免代码重复。
  def this(name: String,age: Int,gender: String){
    this(name: String,age: Int)
    _gender = gender
  }


  /**
   * 也可以重写方法
   */
  override def toString: String = {
    "姓名:" + _name + "," + "年龄:" + _age + "," + "性别:" + _gender
  }
}

//创建对象
val stu: Student = new Student("鹏飞", 18, "男")
println(stu)

姓名:鹏飞,年龄:18,性别:男

4、Scala样例类

/**
 *  scala提供了一个非常好用的功能:样例类
 *  较少用户创建类所编写代码量,只需要定义成员变量即可,自动扩充成员变量,构造方法,重写toString方法
*/

package com.shujia.jichu

object Demo8CaseClass {
  def main(args: Array[String]): Unit = {
    val pf = new Teacher("鹏飞", 18, "刷百度")
    println(pf)
    println(pf.name)
    println(pf.age)
    println(pf.like)
    //当样例类定义的参数为可变参数时,可以对该参数进行修改
    pf.like = "敲代码"
    println(pf)

  }

}

case class Teacher(name: String,age: Int,var like: String)


Teacher(鹏飞,18,刷百度)
鹏飞
18
刷百度
Teacher(鹏飞,18,敲代码)

scala的apply函数(当创建对象是自动调用该函数)

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

    val book: Book = Book()
    println(book)
  }

}


object Book{
  def apply(): Book = {
    new Book("李白", 20)
  }
}

class Book(name: String,price: Int){
  val _name: String = name
  val _price: Int = price

  override def toString: String = "书名:" + _name + "," + "价格:" + _price
}

书名:李白,价格:20

5、Scala中函数式编程

/**
 * scala中的函数式编程
 *
 * 面向对象编程:将对象当作参数一样传来传去
 * 1、对象可以当作方法参数传递
 * 2、对象也可以当作方法的返回值返回
 * 当看到类,抽象类,接口的时候,今后无论是参数类型还是返回值类型,都需要提供对应的实现类对象
 *
 * 面向函数式编程:将函数当作参数一样传来传去
 * 1、函数A当作函数B的参数进行传递
 * 2、函数A当作函数B的返回值返回
 *
 * 在scala中,将函数也当作一个对象,对象就有类型
 * 函数在scala也有类型的说法
 * 参数类型=>返回值类型
 *
 */
//是一个参数为字符串类型,返回值是整数类型的函数
def fun1(str: String): Int = {
    str.toInt + 100
}

val res1: Int = fun1("100")
println(res1)//200

//将一个函数 fun1 赋值给另一个变量 fun2,并且指定了 fun2 的类型为 String => Int,使得fun2就有了fun1的处理逻辑

val fun2: String => Int = fun1

val res2: Int = fun2("300")
println(res2)//400

/**
 * 函数A作为函数B的参数定义
 * 本质上是将函数A的处理逻辑主体传给了函数B,在函数B中使用这个处理逻辑
*/

def fun1(f: String => Int): Int = {
      val result: Int = f("100")
      result + 100
    }

def show1(s: String): Int = {
    s.toInt
}

val res1: Int = fun1(show1)
println(res1)

def show2(s: String): Int = {
    s.toInt + 100
}

val res2: Int = fun1(show2)
println(res2)

200
300

//当函数的参数类型为函数类型时,该函数参数可以使用另外一个参数
def fun2(s: String,f: String => Int): Int = {
    val re: Int = f(s)
    re + 100
}

def show3(s: String): Int = {
    s.toInt
}

val res3: Int = fun2("100", show3)
println(res3)

200

//使用lambda表达式改写为函数类型作为参数传递的调用形式
println(fun2("100",(s: String) => s.toInt))
println(fun2("100",(s: String) => s.toInt + 100))

200
300

//在scala中,数据类型可以自动类型推断因为函数类型在f中已经定义了
fun2("2000", s => s.toInt+1000)
//如果当作参数的函数的参数(s)只在函数主体(s.toInt+1000)使用了一次,那么可以使用_代替(该函数只有一个参数s)
fun2("2000", _.toInt + 1000)

当函数作为返回值时

/**
 * fun1: 参数是String类型,返回值是一个函数(参数是String类型,返回值是Int)
*/
//定义方式一
def fun1(s: String): String => Int = {
    def show(s1: String): Int = {
        s.toInt + s1.toInt
    }
    //在 Scala 中,当你定义或引用一个函数时,如果该函数没有参数或者只有一个参数,可以省略括号。
    show
}

//定义方式二
def fun1(s: String)(s1: String): Int = {
    s.toInt + s1.toInt
}

//调用方式一
val new_fun1: String => Int = fun1("10")
val res: Int = new_fun1("10")
val res3: Int = new_fun1("20")
val res4: Int = new_fun1("30")
println(res)//10
println(res1)
println(res2)


//调用方式二
val res2: Int = fun1("20")("20")
println(res2)//40

//调用方式三
val new_fun1: String => Int = fun1("10",_)
val res: Int = new_fun1("10")

6、集合

6.1、List

package com.shujia.jichu

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

    //特点元素有序,可以重复,长度固定
    val list1: List[Int] = List(26, 78, 23, 89, 26, 66, 89, 26, 78, 45)
    //获取集合的长度
    println(list1.size)
    println(list1.length)
    println("="*50)

    //可以通过索引获取元素
    println(list1(0))
    println(list1(1))
    println(list1(2))
    println(list1(3))
    println(list1(4))
    println("="*50)

    //获取集合第一个元素和最后一个元素
    println(list1.head)
    println(list1.last)
    println("="*50)

    //指定分隔符来拼接集合中元素
    println(list1.mkString("|"))
    println("="*50)

    //反转集合,返回一个新的集合
    val reverse_list1: List[Int] = list1.reverse
    println(reverse_list1)
    println("="*50)

    //集合去重,返回一个新的集合
    val distinct_list: List[Int] = list1.distinct
    println(distinct_list)
    println("="*50)

    //返回集合,除第一个元素外的其他元素
    val tail_list: List[Int] = list1.tail
    println(tail_list)
    println("="*50)

    //从左边取若干个元素
    val take_list: List[Int] = list1.take(5)
    println(take_list)
    println("="*50)

    //从右边取若干个元素
    val takeRight_list: List[Int] = list1.takeRight(5)
    println(takeRight_list)
    println("="*50)

    //从集合第一个开始判断数据,取符合条件的,遇到不符合条件的停止判断
    val filter_list: List[Int] = list1.takeWhile((e: Int) => e % 2 == 0)
    println(filter_list)
    println("="*50)

    var ouSum: Int = 0
    var jiSum: Int = 0

    /**
     * 高阶函数:
     * foreach: 将集合中的元素依次取出传入到后面的函数中
     * 注意:没有返回值的,要么就输出,要么就其他方式处理掉了
     */
    list1.foreach((e: Int) => {
      if(e % 2 == 0){
        ouSum += e
      }else{
        jiSum += e
      }
    })

    println(s"list1集合中偶数和为:$ouSum")
    println(s"list1集合中奇数和为:$jiSum")
    println("="*50)

    /**
     * 高阶函数:
     * map: 依次处理每一个元素,得到一个新的结果,返回到一个新的集合中
     */
    val mapList: List[Int] = list1.map((e: Int) => e * 2)
    println(mapList)
    println("="*50)

    /**
     * 高阶函数:
     * filter: 保留符合条件的元素
     */
    val filterList: List[Int] = list1.filter((e: Int) => e % 2 == 0)
    println(filterList)
    println("="*50)

    /**
     * 高阶函数:
     * sortBy: 排序
     * sortWith: 两个数之间的关系排序
     */
    val sortByList: List[Int] = list1.sortBy((e: Int) => e)
    println(sortByList)
    println("="*50)

    val sortWithSort: List[Int] = list1.sortWith((x: Int, y: Int) => x > y)
    println(sortWithSort)
    println("="*50)

    /**
     * 高阶函数:
     * flatMap: 扁平化(一个变多个)
     */
    val list2: List[String] = List("hello|world|java", "hello|hadoop|flink", "scala|spark|hadoop")
    val flatMapList: List[String] = list2.flatMap((e: String) => e.split("\\|"))
    println(flatMapList)
    println("="*50)

    /**
     * 高阶函数:
     * groupBy: 分组
     */
    val list3: List[String] = List("hello", "world", "java", "hadoop", "flink", "java", "hadoop", "flink", "flink", "java", "hadoop", "flink", "java", "hadoop", "hello", "world", "java", "hadoop", "hello", "world", "java", "hadoop")
    val groupByList: Map[String, List[String]] = list3.groupBy((e: String) => e)
    println(groupByList)
    println("="*50)


  }

}

10
10
==================================================
26
78
23
89
26
==================================================
26
45
==================================================
26|78|23|89|26|66|89|26|78|45
==================================================
List(45, 78, 26, 89, 66, 26, 89, 23, 78, 26)
==================================================
List(26, 78, 23, 89, 66, 45)
==================================================
List(78, 23, 89, 26, 66, 89, 26, 78, 45)
==================================================
List(26, 78, 23, 89, 26)
==================================================
List(66, 89, 26, 78, 45)
==================================================
List(26, 78)
==================================================
list1集合中偶数和为:300
list1集合中奇数和为:246
==================================================
List(52, 156, 46, 178, 52, 132, 178, 52, 156, 90)
==================================================
List(26, 78, 26, 66, 26, 78)
==================================================
List(23, 26, 26, 26, 45, 66, 78, 78, 89, 89)
==================================================
List(89, 89, 78, 78, 66, 45, 26, 26, 26, 23)
==================================================
List(hello, world, java, hello, hadoop, flink, scala, spark, hadoop)
==================================================
Map(world -> List(world, world, world), java -> List(java, java, java, java, java, java), flink -> List(flink, flink, flink, flink), hadoop -> List(hadoop, hadoop, hadoop, hadoop, hadoop, hadoop), hello -> List(hello, hello, hello))

6.2、Set集合

package com.shujia.jichu

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

    /**
     * set集合:scala中的Set集合也是不可变的,除了排序相关的函数以外,List集合有的高阶函数,Set集合也有
     */

    //Set集合是无序的,但是它本身是自然排序
    val set1: Set[Int] = Set(23, 89, 4, 433, 68)
    val set2: Set[Int] = Set(23, 89, 45, 433, 6823)
    println(s"set1集合的自然排序$set1")
    println(s"set2集合的自然排序$set2")

    //求交集
    val jiaojiSet: Set[Int] = set1.intersect(set2)
    println(jiaojiSet)
    println("="*50)

    //求并集
    val bingjiSet: Set[Int] = set1 | set2
    println(bingjiSet)
    println("="*50)

    //求差集
    val chajiSet: Set[Int] = set1 &~ (set2)
    println(chajiSet)
    println("="*50)

    /**
     * Set集合和List集合能不能互相转换?
     * 可以的
     * 业务对List集合中的元素去重
     */

    val list: List[Int] = List(23, 67, 456, 78, 54, 98, 455, 67, 23, 85)
    println(list)
    val set: Set[Int] = list.toSet
    println(set)
    val newList: List[Int] = set.toList
    println(newList)


  }

}


set1集合的自然排序Set(89, 23, 433, 4, 68)
set2集合的自然排序Set(6823, 89, 45, 23, 433)
Set(89, 23, 433)
==================================================
Set(6823, 89, 45, 23, 433, 4, 68)
==================================================
Set(4, 68)
==================================================
List(23, 67, 456, 78, 54, 98, 455, 67, 23, 85)
Set(78, 85, 456, 54, 98, 455, 67, 23)
List(78, 85, 456, 54, 98, 455, 67, 23)

6.3、可变集合

package com.shujia.jichu

import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.HashSet

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

    /**
     * 通过观察api发现,不可变的集合是属于scala.collection.immutable包下的
     * 如果将来想要使用可变的集合,就要去scala.collection.mutable包下寻找
     */

    /**
     *  这里的可变List集合,上午说的功能函数,这里都可以调用
     *  创建一个可变的List集合ListBuffer
     */

    val mutableList: ListBuffer[Int] = new ListBuffer[Int]
    println(mutableList)
    //添加元素
    mutableList.+=(11)
    mutableList.+=(12)
    mutableList.+=(13)
    mutableList.+=(13)
    mutableList.+=(14)
    mutableList.+=(15)
    println(mutableList)
    println("="*50)

    //删除元素(删除第一个出现的)
    mutableList.-=(13)
    println(mutableList)
    println("="*50)

    //批量添加元素
    mutableList.+=(66,77,88,99)
    println(mutableList)
    println("="*50)

    //批量删除元素
    mutableList.-=(66,77,88,99)
    println(mutableList)
    println("="*50)

    /**
     * 可变的Set集合
     */

    val hashSet = new mutable.HashSet[Int]()
    println(hashSet)
    hashSet.+=(33,45,89,23)
    println(hashSet)

  }

}

ListBuffer()
ListBuffer(11, 12, 13, 13, 14, 15)
==================================================
ListBuffer(11, 12, 13, 14, 15)
==================================================
ListBuffer(11, 12, 13, 14, 15, 66, 77, 88, 99)
==================================================
ListBuffer(11, 12, 13, 14, 15)
==================================================
Set()
Set(33, 45, 89, 23)

6.4、元组(Tuple)

package com.shujia.jichu

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

    /**
     * 大小,值是固定的,根据创建的类来定,每个元素的数据类型可以是不一样,最高可以创建存储22个元素的元组
     */
    val tuple1: (Int, Int, Int, Int) = Tuple4(1, 2, 3, 4)
    println(tuple1)
    println("="*50)

    val stu = new Stu("1001", "鹏飞大将军", 18, "玩三国杀")
    val tuple: (Int, Stu) = Tuple2(1001, stu)
    println(tuple)
    println(tuple._2.name)

  }

}

case class Stu(id: String,name: String,age: Int,like: String)

(1,2,3,4)
==================================================
(1001,Stu(1001,鹏飞大将军,18,玩三国杀))
鹏飞大将军

6.5、Map集合

package com.shujia.jichu

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

    //创建Map集合
    //键是唯一的,键一样的时候,值会被覆盖
    val map: Map[Int, String] = Map((1001, "张三"), (1002, "李四"), (1001, "赵六"), 1003 -> "琪琪")
    println(map)
    println("="*50)


    //通过建获取值
    println(map(1001))

    //通过小括号获取时,当键不存在时,会报错
//    println(map(1004))

    //通过get获取时,当键不存在时会返回一个None
    println(map.get(1004))

    //根据键获取值,若键不存在,返回提供的默认值,默认值的类型可以是任意数据类型
    println(map.getOrElse(1004,"myself"))

    //获取所有的键,返回值为所有键组成的迭代器
    val keys: Iterable[Int] = map.keys
    for (e <- keys){
      println(e)
    }
    println("="*50)

    //获取所有的值,返回值为所有值组成的迭代器
    val values: Iterable[String] = map.values
    for (e <- values){
      println(e)
    }
    println("="*50)

    //遍历Map集合第一种方式,先获取所有的键,根据键获取每个值
    for (e <- keys){
      val value: String = map(e)
//    val value: Option[String] = map.get(e)
//      val value: Any = map.getOrElse(e, 0)
      println(s"map集合的键为$e,对应的值为$value")
    }
    println("="*50)

    //遍历Map集合第二种方式,直接遍历map集合,得到每一个键值对组成的元组
    for (kv <- map){
      println(s"map集合的键为${kv._1},对应的值为${kv._2}")
    }
    println("="*50)

    //遍历Map集合第三种方式,foreach
    map.foreach((kv: (Int,String)) => println(s"map集合的键为${kv._1},对应的值为${kv._2}") )

  }

}

Map(1001 -> 赵六, 1002 -> 李四, 1003 -> 琪琪)
==================================================
赵六
None
myself
1001
1002
1003
==================================================
赵六
李四
琪琪
==================================================
map集合的键为1001,对应的值为赵六
map集合的键为1002,对应的值为李四
map集合的键为1003,对应的值为琪琪
==================================================
map集合的键为1001,对应的值为赵六
map集合的键为1002,对应的值为李四
map集合的键为1003,对应的值为琪琪
==================================================
map集合的键为1001,对应的值为赵六
map集合的键为1002,对应的值为李四
map集合的键为1003,对应的值为琪琪


7、JDBC

package com.shujia.jichu

import java.sql.{Connection, Driver, DriverManager, PreparedStatement, ResultSet}

/**
 * jdbc的连接步骤
 * 1、注册驱动
 * 2、创建数据库连接对象
 * 3、创建数据库执行对象
 * 4、执行Sql语句
 * 5、如果有返回值的话,分析查询结果结果
 * 6、关闭连接对象
 */

object Demo20JDBC {
  def main(args: Array[String]): Unit = {
    //1、注册驱动
    Class.forName("com.mysql.cj.jdbc.Driver")

    //2、创建数据库连接对象
    //jdbc:数据库名//host:port/数据库?xxx=xxx&xxx=xxx
    val conn: Connection = DriverManager.getConnection("jdbc:mysql://master:3306/demo01?useUnicode=true&characterEncoding=UTF-8&useSSL=false", "root", "123456")

    //3、创建数据库执行对象
    val statement: PreparedStatement = conn.prepareStatement("select id,name,age,gender,clazz from students where clazz=?")

    //4、执行sql语句
    statement.setString(1,"理科一班")
    val resultSet: ResultSet = statement.executeQuery()

    //5、分析查询结果
    while (resultSet.next()){
      val id: String = resultSet.getString("id")
      val name: String = resultSet.getString("name")
      val age: Int = resultSet.getInt("age")
      val gender: String = resultSet.getString("gender")
      val clazz: String = resultSet.getString("clazz")
      println(s"学号:$id, 姓名:$name, 年龄:$age, 性别:$gender, 班级:$clazz")
    }

    //6、释放资源
    statement.close()
    conn.close()
  }
}

8、JSON

package com.shujia.jichu

import com.alibaba.fastjson.{JSON, JSONArray, JSONObject}

import scala.io.Source

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

    //将读取到的每一行json语句存储到List集合中
    val lineList: List[String] = Source.fromFile("scala/data/stu.json").getLines().toList
    //将集合中的元素转换为特定格式的字符串(以换行符进行分割)
    val jsonStr: String = lineList.mkString("\r\n")
//    println(jsonSrt)

    //使用fastjson包中的JSON类,将一个字符串转成json对象
    //parseObject 将整体转成一个json格式数据
    //转成json对象之后,可以通过键获取值
    val jsonObj: JSONObject = JSON.parseObject(jsonStr)
    val str: String = jsonObj.getString("student_list")

    //parseArray将一个"[{},{}]"变成一个元素是json对象的数组
    val jSONArray: JSONArray = JSON.parseArray(str)
    var i: Int = 0
    while (i < jSONArray.size()){
      val obj: JSONObject = jSONArray.getJSONObject(i)
      val name: String = obj.getString("name")
      val like: String = obj.getString("like")
      i +=1
      println(s"姓名:$name,爱好:$like")
    }


  }

}

//json文件
{
  "flag": "SUCCESS",
  "student_list": [
    {
      "id": "1001",
      "name": "易政",
      "age": 18,
      "like": ["学习","看美女","打游戏"]
    },{
      "id": "1002",
      "name": "小虎",
      "age": 19,
      "like": ["踢足球","打联盟","睡觉"]
    }
  ]
}

姓名:易政,爱好:["学习","看美女","打游戏"]
姓名:小虎,爱好:["踢足球","打联盟","睡觉"]

9、JAVA集合转换为Scala集合

package com.shujia.jichu
import java.util

object Demo22scala2java {
  def main(args: Array[String]): Unit = {
    val javaList = new util.ArrayList[Int]()
    javaList.add(11)
    javaList.add(12)
    javaList.add(13)
    javaList.add(14)
    javaList.add(15)
    javaList.add(16)
    println(javaList)

    /**
     * 将java中的集合转成scala中的集合
     *
     * java中的集合本来是没有转换scala的功能,需要导入隐式转换
     * scala中的导包,可以在任意地方
     *
     */
    import scala.collection.JavaConverters._
    val scalaList: List[Int] = javaList.asScala.toList
    println(scalaList)

    /**
     * scala中的集合转java的集合
     */

    val newJavaList: util.List[Int] = scalaList.asJava
    println(newJavaList)

  }

}

[11, 12, 13, 14, 15, 16]
List(11, 12, 13, 14, 15, 16)
[11, 12, 13, 14, 15, 16]


10、模式匹配

package com.shujia.jichu

import java.util.Scanner
import scala.io.Source

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

    /**
     * 模式匹配,就可以帮助我们开发的时候,减少代码量,让逻辑看起来更加清晰,以及可以避免一些异常
     * 语法:
     * 表达式 match {
     * case 值|[变量名:类型]|元组|数组|对象=>
     * 匹配成功执行的语句
     * case xxx=>
     * xxx
     * _  xxx=>
     * xxx
     * }
     *
     * 模式匹配中,如果没有对应的匹配,那么就报错!!!
     */

    /**
     * 可以匹配变量值
     * 如果匹配不到则报错
     * 也可以使用_表示匹配到了其他值
     */
    val i: Int = 100

    i match {
      case 20 => println("该值是20")
      case 50 => println("该值是50")
      case _ => println("其他值")
    }

    /**
     * 匹配数据类型
     * _: Int :前面的表示占位符名字任意,:后面的表示数据类型
     */
    val flag: Any = true

    flag match {
      case _: Int => println("该值是Int类型")
      case _: Boolean => println("该值是Boolean类型")
    }

    /**
     * 匹配元组
     */

    val tuple: (String, String, Int) = Tuple3("1001", "李亮", 18)

    tuple match {
      case (id: String,name:String,age:Int) => println(s"学号: $id,姓名:$name,年龄:$age")
    }

    /**
     * 匹配数组
     */

    val array: Array[Any] = Array("1001", "鹏飞大将军", 100, "男", "大数据30期")
    array match {
      case Array(id: String,name: String,age: Int,gender: String,calzz: String) =>
        println(s"学号:$id,姓名:$name,年龄:$age,性别:$gender,班级:$calzz")
    }

    /**
     * 模式匹配的应用1:避免异常
     *
     */

    val map: Map[String, String] = Map(("1001", "张三"), ("1002", "李四"))

    val result1: Option[String] = map.get("1001")
    val result2: Any = map.getOrElse("1001", 0)
    println(result1)
    println(result2)
    println(result1.get)

    val scanner = new Scanner(System.in)
    println("请输入你要查询的键")
    val key: String = scanner.next()

    map.get(key) match {
      case Some(a: Any) => println(s"键为:$key,值为:$a")
      case None => println(s"${key}键不存在")
    }

    /**
     * 模式匹配的应用2:简化代码
     *
     */

    val lineList: List[String] = Source.fromFile("scala/data/students.txt").getLines().toList
    val arrayList: List[Array[String]] = lineList.map((line: String) => line.split(","))
    val tuples: List[(String, String, String, String, String)] = arrayList.map((s: Array[String]) => {
      val id: String = s(0)
      val name: String = s(1)
      val age: String = s(2)
      val gender: String = s(3)
      val calzz: String = s(4)
      (id, name, age, gender, calzz)
    })
    tuples.foreach(println)


    arrayList.map({
      case Array(id:String,name:String,age:String,gender:String,clazz:String) =>
        (id,name,age,gender,clazz)
    }).foreach(println)


  }

}

11、隐式转换

11.1、隐式转换函数

//当调用函数的参数类型为隐式转换函数的返回值时,虽然所给的参数不为函数所需参数,但通过隐式转换函数可以将非所需类型的参数转换为所需类型的参数
//需求:调用fun1函数,就只传字符串,不会报错
//定义隐式转换函数
//在需要返回值类型的功能的时候,自动地根据已有隐式转换函数将参数的类型转成返回值的类型

//应用一:
implicit def implicitFun1(s: String): Int = {
    return Integer.parseInt(s)
}

def fun1(a: Int): Int = {
    a + 100
}

println(fun1("100"))

200

//应用二
implicit def implicitFun4(s: String) = Integer.parseInt(s)

println("1000" + 500)//优先使用字符串的拼接功能
println("1000" - 500)//因为字符串不能进行减法运算,故须通过隐式转换函数来得到需要的类型

500

11.2、隐式转换类

package com.shujia.jichu

import scala.io.Source

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

    val demo1 = new Demo99("scala/data/students.txt")
    demo1.show().foreach(println)

    val demo2 = new Demo99("鹏飞大将军")
    demo2.li()

  }

  //`implicit' modifier cannot be used for top-level objects
  //implicit class Demo12(path: String) {
  //implicit使用的地方,不能超过object作用域
  implicit class Demo99(path: String){

    def show(): List[String] = {
      Source.fromFile(path).getLines().toList
    }

    def li(): Unit = {
      println(s"${path}是一个好孩子")
    }

  }
}

300
300
30
20

11.3、隐式转换变量

package com.shujia.jichu

object Demo26implicit {
  def main(args: Array[String]): Unit = {
    //函数柯里化
    def fun1(a1: Int)(a2: Int): Int = {
      a1 + a2
    }

    //只给一个参数返回的是一个函数
    val newFun1: Int => Int = fun1(100)
    println(newFun1(200))


    //返回的是一个数值
    val result: Int = fun1(100)(200)
    println(result)

    def fun2(a1: Int)(implicit a2: Int): Int = a1 + a2

    implicit val a: Int = 10

    //当提供了足够的变量后,就不会使用隐式转换变量
    println(fun2(10)(20))
    //当提供的变量不足时,就会去寻找是否有符合类型的隐式转换变量
    println(fun2(10))
  }

}

11.4、面试题


    /**
     * 面试题:
     * scala中的隐式转换知道吗?说一说
     * 答:
     *  知道。
     *  1、scala中的隐式转换,本质上就是将一个类型转换成另一个类型去使用另一个类型中的功能
     *  2、scala中的隐式转换分为3种:隐式转换函数,隐式转换类,隐式转换变量
     *  3、隐式转换函数,在使用隐式转换函数返回值类型的功能的时候,可以自动的将参数的类型转成返回值类型进行使用
     *  4、隐式转换类,可以自动的将构造方法的参数类型转成类的类型,将来可以直接使用构造方法中的类型调用类中的方法
     *  5、隐式转换变量,配合函数定义中的隐式转换参数使用,
     *    将来调用函数的时候,可以不用传入隐式转换参数的值,自动使用对应类型的隐式转换变量
     *    当然,也可以手动传入具体的值给隐式转换参数。
     *
     */

12、Scala进阶

12.1、题目

阶段一

基于学生、分数、科目数据使用Scala语言完成下面的练习

中括号为最终要求输出的格式

题目较为基础

  • 统计班级人数 [班级,人数]

    
    
  • 统计学生的总分 [学号,学生姓名,学生年龄,总分]

    
    
阶段二

数据同阶段二一样

题目难度偏大

  • 1、统计年级排名前十学生各科的分数 [学号, 姓名,班级,科目,分数]

    
    
  • 2、统计总分大于年级平均分的学生 [学号,姓名,班级,总分]

    
    
  • 3、统计每科都及格的学生 [学号,姓名,班级,科目,分数]

    
    
  • 4、统计每个班级的前三名 [学号,姓名,班级,分数]

    
    
  • 5、统计偏科最严重的前100名学生 [学号,姓名,班级,科目,分数]

12.2、代码

package com.shujia.jinjie

import scala.collection.immutable
import scala.io.Source

object HomeWork {

  //定义一些变量,样例类,为后续的开发做准备

  /**
   * 定义一些样例类  类似于java的封装
   */
  private case class Student(id: String, name: String, age: Int, gender: String, clazz: String)

  private case class Score(id: String, subject_id: String, score: Int)

  private case class Subject(subject_id: String, subject_name: String, subject_score: Int)

  /**
   * 定义三个存储三个不同对象的List集合
   */
  private var stuList: List[Student] = _
  private var scoreList: List[Score] = _
  private var subjectList: List[Subject] = _

  /**
   * 定义一些map集合
   * stuInfoMap  (stu.id, stu.name + "," + stu.clazz)
   * subNameMap  (subject.subject_id, subject.subject_name)
   * subScoreMap (subject.subject_id, subject.subject_score)
   */
  private var stuInfoMap: Map[String, String] = _
  private var subNameMap: Map[String, String] = _
  private var subScoreMap: Map[String, Int] = _

  //初始化变量
  private def loadData(): Unit = {
    //读取学生数据
    stuList = "scala/data/students.txt".load()
      .map {
        case Array(id: String, name: String, age: String, gender: String, clazz: String) =>
          Student(id, name, age.toInt, gender, clazz)
      }

    //读取成绩数据
    scoreList = "scala/data/score.txt".load()
      .map {
        case Array(id: String, subject_id: String, score: String) =>
          Score(id, subject_id, score.toInt)
      }

    //读取科目数据
    subjectList = "scala/data/subject.txt".load()
      .map {
        case Array(subject_id: String, subject_name: String, subject_score: String) =>
          Subject(subject_id, subject_name, subject_score.toInt)
      }

    //处理三个map集合
    //stuInfoMap 存储了学生的学号为键,姓名和班级作为值
    stuInfoMap = stuList.map((stu: Student) => (stu.id, stu.name + "," + stu.clazz)).toMap
    subNameMap = subjectList.map((sub: Subject) => (sub.subject_id, sub.subject_name)).toMap
    subScoreMap = subjectList.map((sub: Subject) => (sub.subject_id, sub.subject_score)).toMap
  }

  /**
   * 根据学号集合打印【学号,姓名,班级,科目,分数】
   */
  private def printStudentInfoWithId(ids: List[String]): Unit = {
    // 从总的学生成绩信息中过滤出来
    scoreList.filter((sco: Score) => ids.contains(sco.id))
      .map {
        case Score(id: String, subject_id: String, score: Int) => {
          //根据学号,查找姓名和班级 stuInfoMap
          val nameWithClazz: String = stuInfoMap.getOrElse(id, "查无此人")
          //根据科目编号,查找科目的名字 subNameMap
          val subject_name: String = subNameMap.getOrElse(subject_id, "无此科目")
          s"[$id,$nameWithClazz,$subject_name,$score]"
        }
      }.foreach(println)
  }


  /**
   * 统计班级人数 [班级,人数]
   */
  private def xuQiu1(): Unit = {
    stuList.groupBy((stu: Student) => stu.clazz)
      .map((kv: (String, List[Student])) => {
        s"[${kv._1},${kv._2.size}]"
      }).foreach(println)

  }

  /**
   * 统计学生的总分 [学号,学生姓名,学生年龄,总分]
   */
  private def xuQiu2(): Unit = {
    val stringToInt: Map[String, Int] = scoreList.groupBy((sco: Score) => sco.id)
      .map((kv: (String, List[Score])) => {
        (kv._1, kv._2.map(_.score).sum)
      })

    val ids: List[String] = stringToInt.map {
      case (id: String, _: Int) => id
    }.toList

    stuList.filter((stu: Student) => ids.contains(stu.id))
      .map((stu: Student) => {
        val sumScore: Int = stringToInt.getOrElse(stu.id, 0)
        s"[${stu.id},${stu.name},${stu.age},$sumScore]"
      }).foreach(println)
  }


  /**
   * 统计年级排名前十学生各科的分数 [学号,姓名,班级,科目,分数]
   */
  private def xuQiu3(): Unit = {
    val ids: List[String] = scoreList.groupBy((s: Score) => s.id) // 按照学号进行分组
      .map((kv: (String, List[Score])) => {
        (kv._1, kv._2.map(_.score).sum) // 求每个学生的总分
      })
      .toList
      .sortBy(-_._2)
      .take(10)
      .map(_._1)

    printStudentInfoWithId(ids) // 学号,姓名,班级,科目,分数
  }

  /**
   * 统计总分大于年级平均分的学生 [学号,姓名,班级,总分]
   */
  private def xuQiu4(): Unit = {
    //先计算年级平均分 372
    val avgScore: Int = scoreList.map(_.score).sum / stuList.size
    //    println(avgScore)

    //计算每个人总分进行过滤
    scoreList.groupBy((s: Score) => s.id) // 按照学号进行分组
      .map((kv: (String, List[Score])) => {
        (kv._1, kv._2.map(_.score).sum) // 求每个学生的总分
      })
      .filter(_._2 > avgScore)
      .map((t: (String, Int)) => {
        //根据stuInfoMap获取学生的姓名和班级
        val nameWithClazz: String = stuInfoMap.getOrElse(t._1, "查无此人")
        s"[${t._1},$nameWithClazz,${t._2}]"
      }).foreach(println)
  }

  /**
   * 统计每科都及格的学生 [学号,姓名,班级,科目,分数]
   */
  private def xuQiu5(): Unit = {
    //1500100001,1000001,98
    val ids: List[String] = scoreList.filter((sco: Score) => sco.score >= subScoreMap.getOrElse(sco.subject_id, 0) * 0.6)
      .groupBy(_.id) // 根据学号分组,过滤6门考试都及格的学生
      .filter(_._2.size == 6)
      .keys
      .toList

    printStudentInfoWithId(ids)
  }

  /**
   * 统计每个班级的前三名 [学号,姓名,班级,分数]
   */
  private def xuQiu6(): Unit = {
    val ids: List[String] = scoreList
      .groupBy((s: Score) => s.id) // 按照学号进行分组
      .map((kv: (String, List[Score])) => {
        val nameWithClazz: String = stuInfoMap.getOrElse(kv._1, "查无此人")
        val infos: Array[String] = nameWithClazz.split(",")
        val name: String = infos(0)
        val clazz: String = infos(1)
        (kv._1, name, clazz, kv._2.map(_.score).sum) // 求每个学生的总分
      })
      .groupBy(_._3) // 根据班级进行分组
      .flatMap((kv: (String, Iterable[(String, String, String, Int)])) => {
        kv._2.toList.sortBy(-_._4).take(3)
      }).map(_._1).toList

    // 从总的学生成绩信息中过滤出来
    scoreList.filter((sco: Score) => ids.contains(sco.id))
      .map {
        case Score(id: String, subject_id: String, score: Int) => {
          //根据学号,查找姓名和班级 stuInfoMap
          val nameWithClazz: String = stuInfoMap.getOrElse(id, "查无此人")
          s"[$id,$nameWithClazz,$score]"
        }
      }.foreach(println)
  }

  /**
   * 统计偏科最严重的前100名学生  [学号,姓名,班级,科目,分数]
   *
   * 方差
   * (每个人的各科分数-6门考试的平均分)^2 / 科目数
   *
   */
  private def xuQiu7(): Unit = {
    //归一化
    val ids: List[String] = scoreList.map {
      case Score(id: String, subject_id: String, score: Int) =>
        (id: String, subject_id: String, score * 100 / subScoreMap.getOrElse(subject_id, 0))
    }.groupBy(_._1) //根据学号进行分组
      .map((kv: (String, List[(String, String, Int)])) => {
        val id: String = kv._1
        val scoreList: List[(String, String, Int)] = kv._2
        //每个人的平均分
        val avgScore: Int = scoreList.map(_._3).sum / scoreList.size
        //求方差
        val fangCha: Double = scoreList.map((t3: (String, String, Int)) => Math.pow(t3._3 - avgScore, 2)).sum / scoreList.size
        (id, fangCha)
      })
      .toList
      .sortBy(-_._2)
      .take(100)
      .map(_._1)

    printStudentInfoWithId(ids)
  }

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

//        xuQiu1()
    //    xuQiu2()
    //    xuQiu3()
    //    xuQiu4()
    //    xuQiu5()
    //    xuQiu6()
    //    xuQiu7()
  }

  //定义一个隐式转换类
  //将来可以直接通过文件路径获取一个封装了行数据的集合
  implicit class Load(path: String) {
    def load(): List[Array[String]] = {
      Source.fromFile(path).getLines().toList.map((line: String) => line.split(","))
    }
  }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值