Scala实战三

一、上次课回顾

二、原生代码编写ScalaJDBC

三、Scala中的高阶函数

一、上次课回顾

  • https://blog.csdn.net/SparkOnYarn/article/details/106384630
  1. 讲了函数完整的定义,定义函数的入参,每一个参数的定义;如果有返回值,=号可以不用写
  2. 类是用class来定义的,类中主要有属性(用var、val修饰)和方法,类中需要new出来才能使用;定义属性的时候可以用_占位符来占坑,不过要写明属性的类型;
  3. 主构造器和附属构造器,附属构造器用def this定义
  4. 我们也自己定义了一个SparkConf,形成了一个链式编程;val conf = new SparkConf conf.serAppName("").setMaster("")
  5. 去查看SparkConf.scala的源码

二、原生代码编写ScalaJdbc

首先联想下MySQL JDBC编程:
1)、MySQL的驱动
2)、Connection重量级的过程,借助于POOL连接池
3)、Statement
4)、ResultSet -->SQL执行的结果
5)、close释放资源

IO编程:
1)、打开资源
2)、业务处理
3)、释放资源

添加mysql依赖:

<!--MySQL的驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.28</version>
    </dependency>

Scala最原生的代码连接MySQL数据库:

object ScalaJDBCApp {
	def main(args: Array[String]): Unit = {
		val url="jdbc:mysql://hadoop001:3306/ruozedata_hive"
		val user="root"
		val password="960210"
		val sql="select DB_LOCATION_URI,DB_ID,name from dbs"
		class.forName(className="com.mysql.jdbc.Driver")
		val connection = DriverManager.getConnection(url,user,password)		
		val stmt=connection.createStatement()
		val rs = stmt.executeQuery(sql)
		while (rs.next()){
			val location = rs.getString(1)
			val dbid=rs.getString(2)
			val name=rs.getString(3)
			println(dbid + "" + location + "" + name)
		}
		rs.close()
		stmt.close()
		connection.close()
	}
}

//这段代码要运行在linux服务器上的话需要加上的是class.forName("com.mysql.jdbc.Driver")

2.1、父类和子类

  • 面向对象中已经介绍了class,class中有field属性,method/function方法;如下这些代码都是在一个类中的;

      Class(xx:Int) {
      field
      method/function
      
      def this(xx:Int, yy:String) {		附属构造器
      	this (xx)		调用主构造器
      }	
      }
    

父类和子类:两个类之间

继承的代码:extendsApp

package com.ruozedata.bigdata.scala03

import com.ruozedata.bigdata.scala02.ConstructorDemo.People


object ExtendsApp {
  def main(args: Array[String]): Unit = {
      val bt1 = new bigTree("bigtree","北京",1000f)
  }

}

class bigTree(name:String,city:String,Money:Float) extends People(name, city) {
    println("people 3")

    println("people 4")
}

override重写:

object ExtendsApp {
 def main(args: Array[String]): Unit = {
  val bt1 = new bigTree("bigtree","北京",1000f)
  println(bt1.toString())
 }

}
class bigTree(name:String,city:String,Money:Float) extends People(name, city) {
    println("people 3")

    override def toString() = "test"	
    //为什么在子类中要使用override重写,因为在父类中默认就有一个toString方法;
    println("people 4")
}
运行结果:
test

不在子类中重写toString这个方法,直接在main函数下打印println(bt1.toString)的输出结果为:
com.ruozedata.bigdata.scala03.bigTree@5c7fa833
–> 完整的包名+类名@跟上hash值

去到Object.java中查看toString方法:
public String toString() {
return getClass().getName() + “@” + Integer.toHexString(hashCode());
}

小结:

子类中有一个方法,父类中也有一个相同的方法;override一般是用来在子类中重写父类的方法或者属性,(两项到Java中最顶层的object中就有一个toString方法))

假设我们定义了一个Animal类,Dog\Cat\Pig,每一类东西有某个相同特征,对动物来说,定义一个eat方法;对于狗来说是eat方法,对于猫来说,重写狗的eat方法,就是猫自己的方法;

在框架中一般定义了接口和抽象类,这样的话框架就会很好的扩展;

1、主构造器ConstructorDemmo代码:
package com.ruozedata.bigdata.scala02

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

      val people = new People("john","北京")
    println(people.city + "" + people.name)
      val people2 = new People("sail","苏州",30)
  }

  //跟在class后面的就是主构造器
  class People(var name:String,var city:String){
    println("people 1")

    //附属构造器的第一行必须要调用主构造器或者其它附属构造器
    var age:Int = _

    val money:Int =100000
    def this(name:String,city:String,age:Int){
      this(name,city)
      this.age=age
    }


    println("people 2")
  }

}
//附属构造器中又对money进行定义:

2、继承类ExtendsApp代码:
package com.ruozedata.bigdata.scala03

import com.ruozedata.bigdata.scala02.ConstructorDemo.People


object ExtendsApp {
  def main(args: Array[String]): Unit = {
      val bt1 = new bigTree("bigtree","北京",1000)
      println(bt1.toString())
      println(bt1.money)

  }

}

class bigTree(name:String,city:String,age:Int) extends People(name, city) {
    println("people 3")
    override val money= 1000

//    override def toString() = "test"
    println("people 4")
}

//override val money = 10000;	重写了主类中对money的属性

2.1.1、官方代码中的子类和父类

MemoryManager --> 按住ctrl+t,查看这个类下的子类方法:StaticMemoryManager

子类继承父类:父类中有的东西,子类中必然都是有的;Spark中的内存管理

2.2、抽象类

  • Class Function没有具体的实现

  • 抽象的类不能直接new,不能被实例化;只能通过子类来new,子类不能还是抽象类

      abstract class A {
      	def speak		//定义一个speak函数,没有具体的实现
      	val name:String 	//没有具体赋值的属性,抽象属性
      }
    
  • 等号前面的一些东西就是没有具体实现的方法和属性;

      与正常类做对比:
        class A {
            def speak = {
              val name: String = ""
            }
            }
    
  • 抽象的东西不能直接new,会报错:class A is abstract,can not be instantiated;而是通过子类来new,子类不能还是抽象的;

      object AbstractApp {
          def main(args: Array[String]): Unit = {
            val a = new B()
            a.speak
      
    }
      abstract class A {
        def speak
        val name:String
      }
    
       class B extends A {
         override def speak: Unit = {}
         val name:String=""
          println("b speak")
      }
    
    
      }
    

2.2.1、源码剖析(memorymanager和staticmemorymanager)

  • 抽象类在Spark中的体现:
1、抽象类:
private[spark] abstract class MemoryManager(
    conf: SparkConf,
    numCores: Int,
    onHeapStorageMemory: Long,
    onHeapExecutionMemory: Long) extends Logging {

2、抽象类的子类:
private[spark] class StaticMemoryManager(
    conf: SparkConf,
    maxOnHeapExecutionMemory: Long,
    override val maxOnHeapStorageMemory: Long,
    numCores: Int)
  extends MemoryManager(
    conf,
    numCores,
    maxOnHeapStorageMemory,
    maxOnHeapExecutionMemory) {

    def maxOffHeapStorageMemory: Long
  override def maxOffHeapStorageMemory: Long = 0L

在staticmemorymanager中把这个方法初始化了,也就是在抽象类子类中实现了方法:

具体在Spark中用的地方,查看SparkEnv.scala源码:

2.3、Trait接口

对于继承而言是不能够多继承的,所以只能够使用trait接口;

class后面跟的不仅仅可以是类还可以跟着接口,class A extends C(类) with B(接口)

三、Scala中的高阶函数

高阶函数:
val l = List(1,2,3,4,5,6,7,8)
–> List就是一个框,框里装的是1-8这8个数字

map映射:y=f(x) 为每个x作用上一个相同的函数
println(l.map(x => x*2))

输出结果如下:
List(2, 4, 6, 8, 10, 12, 14, 16)

更精简的写法:
println(l.map(_*2)) -->输出结果也是一样的,此处的_表示的是l中的每个元素,这种表示方法是最精简的;

有一份纯单词的log文件,为每个单词赋上一个1,写法:(_,1)–>集合中的每一个元素;

需求1:
单词*2过后取出大于10的数值:

println(l.map(_*2).filter(_>10))

需求2:

  • 在1的基础上取出前2个数值:

      println(l.map(_*2).filter(_>10).take(2))
    

需求3:

  • 把原始数据list进行两两相加:

      println(l.reduce(_+_))
      println(l.reduce((x:Int,y:Int)=>x+y))
    

需求4:

  • 两两相减

      println(l.reduce(_-_))
      println(l.reduce((x:Int,y:Int)=>x-y))
    
reduceLeft和reduceRight的使用:

在IDEA中参照如下进行测试:

 l.reduceLeft((x:Int,y:Int) => {
  println(x + "" + y)
  x-y
})
fold函数:

概念:初始值

多重list
val a = List(List(1,2),List(3,4),List(5,6))
println(a.flatten)
输出如下:List(1, 2, 3, 4, 5, 6)
flatten的作用是把输出拉平。
FlatMap
 val a =List(List(1,2),List(3,4),List(5,6),List(7,8))
val b = a.flatten
println(b.map(_*2))
-->
println(a.flatMap(_.map(_*2)))
在linux编程环境下词频统计是怎么做的
  1. 第一步操作:lines.flatMap(_.split("\t"))

     得到的结果:
     hello
     world
     hello
     hello
     world
     welcome
     hello
    
  2. 为每个单词赋上一个1
    words.map(x => (x,1)) 为每个元素赋上1个1

  3. 求和两两相加
    reduceByKey(+)
    输出结果:(hello,3)(world,2) (welcome,1)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值