学习路上的新起点:大数据Scala + Spark +(HDFS + HBase),本文主要介绍下Scala的基本语法和用法吧。最后再简单介绍一种Java开发工具IntelliJ IDEA的使用。

Scala

Scala语言是一种面向对象语言,结合了命令式(imperative)和函数式(functional)编程风格,其设计理念是创造一种更好地支持组件的语言。

Object-Oriented Meets Functional

特性

  • 多范式(Multi-Paradigm)编程语言,类似Java、C#;
  • 继承面向对象编程和函数式编程的特性;
    •   面向对象:[1]. 子类继承,[2]. 混入(Mixin)机制;
    •   函数式:支持高阶函数、嵌套函数,模式匹配,支持柯里化(Currying);
    •   类型推断(Type Inference):根据函数体中的具体内容推断方法的返回值类型
  • 更高层的并发模型,可伸缩;
  • 静态类型,编译时检查;
  • 允许与Java互操作(将来会支持与.Net互操作);

与Java对比

  • 如果用作服务器端开发,Scala的简洁、灵活性是Java无法比拟的;
  • 如果是企业级应用开发、Web开发,Java的强大是Scala无法匹敌的;

Scala和Groovy

Groovy的优势在于易用性以及与Java无缝衔接,更注重实效思想,脚本化;

Scala的优势在于性能和一些高级特性,静态类型,更具有学术思想;

关于Lift

一个使用了Scala的开源的Web应用框架,可以使用所有的Java库和Web容器。其他框架:Play、Bowler等。

推荐:Play FrameworkSlick,具体学习待续... ...

  • Play:The High Velocity Web Framework For Java and Scala
  • Slick:Functional Relational Mapping for Scala

环境

Scala SDK: scala-2.10.4.msi

安装路径最好不要带空格和中文字符,否则,在 cmd 命令行窗口执行 scala -version 会报错 此时不应有 \scala\bin\scala.bat) 的问题

安装完成后,确保 ..\lib 目录下包含如下文件:

scala-compiler.jar, scala-library.jar, scala-reflect.jar

注意,.msi 版本是安装版,.zip 解压即可。

在 cmd 命令行中,测试:

Note:本地可以安装多个版本的 Scala SDK,以 scala 2.11 为例:

// scala-2.11.8.zip
Scala_2.11_Home:D:\scala-2.11.8
Path:%Path%; %Scala_2.11_Home%\bin

使用时,用哪个SDK,在Path变量中就将哪个SDK放在前面即可。

基础语法问题

Scala程序的执行入口是提供main方法的独立单例对象。每个Scala函数都有返回值,每个Scala表达式都有返回结果。

在Scala中没有静态的概念,所有东西都是面向对象的。其实object单例对象只是对静态的一种封装而已,在.class文件层面,object单例对象就是用静态(static)来实现的。

一切皆为对象

Scala中所有的操作符都是方法,操作符面向的使用者都是对象

Scala编程的一个基本原则上,能不用var,尽量不用var,能不用mutable变量,尽量不用mutable变量,能避免函数的副作用,尽量不产生副作用。

  • 对于任何对象,如果在其后面使用(),将调用该对象的apply方法,arr(0) == arr.apply(0)
  • 如果对某个使用()的对象赋值,将该对象的update方法,arr(0)=value == arr.update(0,value)

如果一个方法只有一个参数,可以不用 括号和. 来调用这个方法。

字段 + 方法 + 函数

scalac编译器会为类中的var字段自动添加setter和getter方法,会为类中的val方法自动添加getter方法。 其中,getter方法和字段名相同。

在源码中,所有对字段的显示访问,都会在class中编译成通过getter和setter方法来访问。

方法作用于对象,方法是对象的行为。方法定义格式:

def 方法名称(参数列表):返回值 = { 方法体 }

函数定义格式:

val 函数名称 = { (参数列表) => { 函数体 } },即 val 函数名称 = { Lambda表达式 }
或 val 函数名称 : (入参类型 => 出参类型) = { 入参 => 函数体 }

方法名意味着方法调用,函数名只代表函数本身

关于方法(Method)和函数(Function)

  • 函数是一等公民,使用val语句可以定义函数,def语句定义方法;
  • 函数是一个对象,继承自FuctionN,函数对象有curried,equals,isInstanceOf,toString等方法,而方法不具有;
  • 函数是一个值,可以给val变量赋值,方法不是值、也不可以给val变量赋值;
  • 通过将方法转化为函数的方式 method _ 或 method(_) 实现给val变量赋值;
  • 若 method 有重载的情况,方法转化为函数时必须指定参数和返回值的类型;
  • 某些情况下,编译器可以根据上下文自动将方法转换为函数;
  • 无参数的方法 method 没有参数列表(调用:method),无参数的函数 function 有空列表(调用:function());
  • 方法可以使用参数序列,转换为函数后,必须用 Seq 包装参数序列;
  • 方法支持默认参数,函数不支持、会忽略之;

参考:学习Scala:Scala中的字段和方法Scala中Method和Function的区别 - 简书

参数

  • 按名传参:By-name parameter,def fun(param: => T)。Evaluated every time it's used within the body of the function
  • 按值传参:By-value parameter。Evaluated before entry into the function/method

推荐将按值传参(def fun(msg: String))改为按名称传参(def fun(msg: =>String))。这样参数会等到实际使用的时候才会计算,延迟加载计算,可以减少不必要的计算和异常。

case class

case class PubInterfaceLog(interfaceId: Int, busiType: String, respTime: Long, publicId: Long)

最重要的特性是支持模式匹配,Scala官方表示:

It makes only sense to define case classes if pattern matching is used to decompose data structures.

其他特性如下:

  • 编译器自动生成对应的伴生对象和 apply() 方法;
  • 实例化时,普通类必须 new,而 case class 不需要;
  • 主构造函数的参数默认是 public 级别,默认在参数为 val;
  • 默认实现了 equals 和 hashCode,默认是可以序列化的,也就是实现了Serializable,toString 更优雅;
  • 默认生成一个 copy 方法,支持从实例 a 以部分参数生成另一个实例 b;

参考:Scala case class那些你不知道的知识

apply() 方法

apply方法是Scala提供的一个语法糖

  • 类名+括号,调用对象的apply方法
  • 对象名+括号,调用类的apply方法

对apply方法的简单测试:(其中,带 new -- class ApplyTest,不带 new -- object ApplyTest)

class ApplyTest {
println("class ApplyTest")
def apply() {
println("class APPLY method")
}
}
object ApplyTest {
println("object ApplyTest")
def apply() = {
println("object APPLY method")
new ApplyTest()
}
} // 对象名+括号,调用类的apply方法
val a1 = new ApplyTest()
a1() // == a1.apply()
// 输出 class ApplyTest, class APPLY method // 类名+括号,调用对象的apply方法
val a2 = ApplyTest()
// 输出 object ApplyTest, object APPLY method, class ApplyTest val a2 = ApplyTest()
a2()
// 输出 object ApplyTest, object APPLY method, class ApplyTest, class APPLY method val a3 = ApplyTest
// 输出 object ApplyTest val a3 = ApplyTest
a3()
// 输出 object ApplyTest, object APPLY method, class ApplyTest

几个零碎的知识点

  • Array 长度不可变, 值可变;Tuple 亦不可变,但可以包含不同类型的元素;
  • List 长度不可变, 值也不可变,::: 连接两个List,:: 将一个新元素放到List的最前端,空列表对象 Nil
  • _:通配符,类似Java中的*,下划线 "_ " 的用法总结
  • _=:自定义setter方法;
  • _*:参数序列化,将参数序列 Range 转化为 Seq
  • i to j : [i, j]; i until j : [i, j)
  • lazy val表示延迟初始化,无lazy var

映射 + 对偶 + 元组

映射由对偶组成,映射是对偶的集合。对偶即键值对,键->值,(键, 值),是最简单的元组。元组是不同类型的值的聚集。

映射是否可变表示整个映射是否可变,包括元素值、映射中元素个数、元素次序等:

  • 不可变映射:直接用(scala.collection.mutable.)Map声明,维持元素插入顺序,支持 += 、-=;
  • 可变映射:用scala.collection.immutable.Map声明,不维持元素插入顺序,支持 +、-;

构造器

1主构造器

class Student(var ID : String, var Name : String) {
println("主构造器!")
}
  • 主构造器直接跟在类名后面,主构造器的参数最后会被编译成字段
  • 主构造器执行时,会执行类中所有的语句
  • 如果主构造器参数声明时不加val或var,相当于声明为private级别

2从构造器

class Student(var ID : String, var Name : String) {
println("主构造器!") var Age : Int = _
var Address : String = _
private val Email : String = Name + ID + "@163.com" println("从构造器!")
def this(ID:String, Name:String, Age:Int, Address:String) {
this(ID, Name)
this.Age = Age
this.Address = Address
}
}
  • 从构造器定义在类内部,方法名为this
  • 从构造器必须先调用已经存在的主或从构造器

集合

Scala语言的一个设计目标是可以同时利用面向对象和面向函数的方法编码,因此提供的集合类分成了可以修改的集合类和不可以修改的集合类两大类型。Scala除了Array和List,还提供了Set和Map两种集合类。

  • 通过 scala.collection.JavaConversions.mapAsScalaMap 可将 Java 的 Map 转换为 Scala 类型的 Map;
  • 通过 scala.collection.JavaConversions.mapAsJavaMap 可将 Scala 的映射转换为 Java 类型的映射;
  • toMap 方法将对偶集合转化为映射

OptionNoneSome

一致目标:所有皆为对象 + 函数式编程,在变量和函数返回值可能不会引用任何值的时候使用 Option 类型

  • 在没有值的时候,使用None;
  • 如果有值可以引用,使用Some来包含这个值;

None 和 Some 均为 Option 的子类,但是 None 被声明为一个对象,而不是一个类.

伴生对象

当单例对象(object Name,Singleton Object)与类(class Name)同名时,该单例对象称作类的伴生对象(Companion Object),该类称作单例对象的伴生类。没有伴生类的单例对象称为孤立对象(Standalone Object),最常见的就是包含程序入口main()的单例对象。

  • 同名且在同一个源文件中定义
  • 可以互相访问其私有成员

参考:Scala学习笔记-伴生对象于孤立对象

  • 伴生对象的属性、方法指向全局单例对象 MODULE$
  • 伴生类的属性、方法被定义为是对象相关的

单例对象在第一次访问时初始化,不可以new、不能带参数,而类可以new、可以带参数。

  • 伴生对象中定义的字段和方法, 对应同名.class类中的静态方法,对应同名$.class虚构类中的成员字段和方法
  • 伴生类中定义的字段和方法, 对应同名.class类中的成员字段和成员方法

同名.class类中的静态方法,会访问单例的虚构类的实例化对象, 将相关的逻辑调用转移到虚构类中的成员方法中,即:.class类提供程序的入口,$.class提供程序的逻辑调用。

  • 伴生对象中的逻辑,转移到$.class虚构类中去处理
  • 伴生类中的逻辑,转移到.class同名类中的成员方法中去处理

通过伴生对象来访问伴生类的实例,提供了控制实例个数的机会。虚构类的单例性,保证了伴生对象中信息的唯一性。

那么:伴生对象如何体现单例呢?

因为伴生类不是单例的,如何实现单例模式呢?方法2种:

1)将伴生类中的所有逻辑全部移到单例对象中,去除伴生类, 单例对象成为孤立对象, 该孤立对象天然就是单例的

2)若必须存在伴生类,如何保证伴生类是单例的? 将伴生类的主构造器私有, 并在伴生对象中创建一个伴生类的对象, 该对象就是唯一的

class A private {
}
object A {
val single = new A()
}
// true
var a1 = A.single
var a2 = A.single;
println("a1 eq a2 : " + (a1 eq a2))

参考:学习Scala:孤立对象的实现原理学习Scala:伴生对象的实现原理

Trait

特质,类似有函数体的 Interface,利用关键字 with 混入。

IO读写

Scala本身提供 Read API,但是 Write API 需要利用Java的API,文件不存在会自动创建。

1Read

import scala.io.Source
val content = Source.fromURL(url).getLines() // 网络资源
val lines = Source.fromFile(filePath).getLines() // 文件

2Write

import java.io.File
import java.io.PrintWriter
import java.io.FileWriter
import java.io.BufferedWriter // 文件首次写入,ok; 不支持追加
val writer = new PrintWriter(new File("sqh.txt"))
writer.println("xxx") // 支持追加;但是有换行问题
val writer = new FileWriter(new File("sqh.txt"), true)
writer.write("xxx") // 支持追加,换行解决方法1
val writer = new BufferedWriter(new FileWriter(new File("sqh.txt"), true))
writer.write("xxx")
writer.newLine() // 支持追加,换行解决方法2
val writer = new PrintWriter(new FileWriter(new File("sqh.txt"), true))
writer.println("xxx") writer.flush()
writer.close

注意,关闭流前,先刷新。PrintWriter 不支持追加,FileWriter 支持追加,但存在换行问题。可以将 FileWriter 包装成 BufferedWriter 或 PrintWriter 解决换行问题。

参考

关于IntelliJ Idea的使用,参见:https://www.cnblogs.com/wjcx-sqh/p/11129718.html

Scala + IntelliJ IDEA的更多相关文章

  1. Scala & IntelliJ IDEA环境搭建升级版:在JAVA中调用Scala的helloworld

    --------------------- 前言 --------------------- 项目关系,希望用Spark GraphX做数据分析及图像展示,但前提是得会spark:spark是基于sc ...

  2. Scala & IntelliJ IDEA:环境搭建、helloworld

      --------------------- 前言 --------------------- 项目关系,希望用Spark GraphX做数据分析及图像展示,但前提是得回spark:spark是基于 ...

  3. scala + intellij idea 环境搭建及编译、打包

    大数据生态圈中风头正旺的Spark项目完全是采用Scala语言开发的,不懂Scala的话,基本上就没法玩下去了.Scala与Java编译后的class均可以运行于JVM之上,就好象.NET中F#与C# ...

  4. Scala Macros - 元编程 Metaprogramming with Def Macros

    Scala Macros对scala函数库编程人员来说是一项不可或缺的编程工具,可以通过它来解决一些用普通编程或者类层次编程(type level programming)都无法解决的问题,这是因为S ...

  5. Scala - 快速学习02 - 搭建开发环境

    1- 下载与安装 下载链接:http://www.scala-lang.org/download/ CMD To run Scala from the command-line, simply dow ...

  6. 自己给idea下载Scala插件

    场景:有时候在idea上直接下载的scala可能因为太新所以有bug,需要手动下载插件 经验:自己下载完之后发现比较老的版本idea根本不让你装,只能装一些跟idea上推荐的scala相近的版本,感觉 ...

  7. Akka-CQRS(10)- gRPC on SSL/TLS 安全连接

    使用gRPC作为云平台和移动前端的连接方式,网络安全应该是必须考虑的一个重点.gRPC是支持ssl/tls安全通讯机制的.用了一个周末来研究具体使用方法,实际上是一个周末的挖坑填坑过程.把这次经历记录 ...

  8. intellij 调试spark scala 程序 报错

    spark用的是cdh spark-2.0.1 package main.scala import org.apache.spark.rdd.RDD import org.apache.spark.{ ...

  9. intellij安装Scala及Python插件

    1.下载intellij及Scala和Python插件 intellij的下载地址:https://www.jetbrains.com/idea/download/#section=windows S ...

随机推荐

  1. 初学JSON和AJAX心得透过解惑去学习

    虽然复制代码再改参数,也能正常运作.但是看懂里面语法,就可以客制成适合你自己程序.例如录制Excel巨集,会有一些赘句,这时候整合就是很重要工作. [大纲] 时间分配 AJAX Markdown教学及 ...

  2. FM-分解机模型详解

    https://blog.csdn.net/zynash2/article/details/80029969 FM论文地址:https://www.csie.ntu.edu.tw/~b97053/pa ...

  3. Swagger使用

    Swagger 1.集成springboot 第一步:pom <dependency> <groupId>io.springfox</groupId> <ar ...

  4. 编译wiredtiger rpm包

    1.安装rpm-build 使用rpmbuild打包rpm包前,首先安装rpmbuild: yum install rpm-build -y 2.创建打包文件目录 mkdir  -p  /root/r ...

  5. trap实现跳板机

    第一节 跳板机实现原理(图例) 第2节 涉及到的知识点 命令:trap 拓展知识:进程与信号 trap 语法,作用,使用 [jeson@mage-jump-01 ~/]$  trap -l  1) S ...

  6. kafka 学习笔记

    一.为什么需要消息系统 1.解耦: 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余: 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险. ...

  7. 20175314 《Java程序设计》迭代和JDB

    20175314 <Java程序设计>迭代和JDB 要求 1 使用C(n,m)=C(n-1,m-1)+C(n-1,m)公式进行递归编程实现求组合数C(m,n)的功能 2 m,n 要通过命令 ...

  8. sed (未完,待续)

    sed [options] 'command' file(s) options: -e<script>或--expression=<script>:以选项中的指定的script ...

  9. [C++]字符串相关操作

    获取字符串长度 String str str.length(); //获取String类型字符串长度 str.size(); //STL获取容器中元素个数 Char* s strlen(s); //以 ...

  10. PCIe 驱动流程(LTSSM)

     本次的工作是完成刚流片的FPGA中PCIe IP核的bring up,也就是芯片的中PCIe的第一个使用者,将PCIe IP核正常使用起来,并配合公司的EDA团队,完成PCIe IP核到用户的呈现. ...