Scala + IntelliJ IDEA
学习路上的新起点:大数据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 Framework 和 Slick,具体学习待续... ...
- 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;
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 方法将对偶集合转化为映射
一致目标:所有皆为对象 + 函数式编程,在变量和函数返回值可能不会引用任何值的时候使用 Option 类型
- 在没有值的时候,使用None;
- 如果有值可以引用,使用Some来包含这个值;
None 和 Some 均为 Option 的子类,但是 None 被声明为一个对象,而不是一个类.
伴生对象
当单例对象(object Name,Singleton Object)与类(class Name)同名时,该单例对象称作类的伴生对象(Companion Object),该类称作单例对象的伴生类。没有伴生类的单例对象称为孤立对象(Standalone Object),最常见的就是包含程序入口main()的单例对象。
- 同名且在同一个源文件中定义
- 可以互相访问其私有成员
- 伴生对象的属性、方法指向全局单例对象
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,文件不存在会自动创建。
(1)Read
import scala.io.Source
val content = Source.fromURL(url).getLines() // 网络资源
val lines = Source.fromFile(filePath).getLines() // 文件(2)Write
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的更多相关文章
- Scala & IntelliJ IDEA环境搭建升级版:在JAVA中调用Scala的helloworld
--------------------- 前言 --------------------- 项目关系,希望用Spark GraphX做数据分析及图像展示,但前提是得会spark:spark是基于sc ...
- Scala & IntelliJ IDEA:环境搭建、helloworld
--------------------- 前言 --------------------- 项目关系,希望用Spark GraphX做数据分析及图像展示,但前提是得回spark:spark是基于 ...
- scala + intellij idea 环境搭建及编译、打包
大数据生态圈中风头正旺的Spark项目完全是采用Scala语言开发的,不懂Scala的话,基本上就没法玩下去了.Scala与Java编译后的class均可以运行于JVM之上,就好象.NET中F#与C# ...
- Scala Macros - 元编程 Metaprogramming with Def Macros
Scala Macros对scala函数库编程人员来说是一项不可或缺的编程工具,可以通过它来解决一些用普通编程或者类层次编程(type level programming)都无法解决的问题,这是因为S ...
- Scala - 快速学习02 - 搭建开发环境
1- 下载与安装 下载链接:http://www.scala-lang.org/download/ CMD To run Scala from the command-line, simply dow ...
- 自己给idea下载Scala插件
场景:有时候在idea上直接下载的scala可能因为太新所以有bug,需要手动下载插件 经验:自己下载完之后发现比较老的版本idea根本不让你装,只能装一些跟idea上推荐的scala相近的版本,感觉 ...
- Akka-CQRS(10)- gRPC on SSL/TLS 安全连接
使用gRPC作为云平台和移动前端的连接方式,网络安全应该是必须考虑的一个重点.gRPC是支持ssl/tls安全通讯机制的.用了一个周末来研究具体使用方法,实际上是一个周末的挖坑填坑过程.把这次经历记录 ...
- intellij 调试spark scala 程序 报错
spark用的是cdh spark-2.0.1 package main.scala import org.apache.spark.rdd.RDD import org.apache.spark.{ ...
- intellij安装Scala及Python插件
1.下载intellij及Scala和Python插件 intellij的下载地址:https://www.jetbrains.com/idea/download/#section=windows S ...
随机推荐
- windows上安装Maven与Gradle
(一)安装Maven 1.百度maven,进入官网http://maven.apache.org/download.cgi,选择Download,在选择相应的压缩包apache-maven-3.6.0 ...
- oracle sql developer怎么创建用户
学习数据库的时候,用管理员账户,会有会有很多系统自创的表,很麻烦.所以要自己创建普通用户. create user 用户名 identified by 密码;--创建用户 grant connect, ...
- day39 mysql数据库基本操作
什么是数据库 用来存储数据的仓库 数据库可以在硬盘及内存中存储数据 主要学习硬盘中存储数据,因为内存中的数据总有一天会丢失 数据库与文件存储数据区别 (公司的开发是综合内容的) 数据库本质也是通过文件 ...
- Demo002 IDEA中Junit单元测试的使用(初级篇)
推荐JUnit视频教程:JUnit-Java单元测试必备工具. 1.基本理论 1.1 单元测试 单元测试又称模块测试,属于白盒测试,是最小单位的测试.模块分为程序模块和功能模块.功能模块指实现了一个完 ...
- TZOJ 4602 高桥和低桥(二分或树状数组+二分)
描述 有个脑筋急转弯是这样的:有距离很近的一高一低两座桥,两次洪水之后高桥被淹了两次,低桥却只被淹了一次,为什么?答案是:因为低桥太低了,第一次洪水退去之后水位依然在低桥之上,所以不算“淹了两次”.举 ...
- 《Java程序设计》第二周学习总结(一)
教材学习内容总结 标识符.关键字 基本数据类型 类型转换运算 输入.输出数据 数组 教材学习中的问题和解决过程 问题1:在创建vim并编写完成后出现以下情况 问题1解决方案:打开虚拟机的文件目录,发现 ...
- jquery判断是否是空对象 不含任何属性
code function isEmptyObject(e) { var t; for (t in e) return !1; return !0 }
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- [翻译]高并发框架 LMAX Disruptor 介绍
原文地址:Concurrency with LMAX Disruptor – An Introduction 译者序 前些天在并发编程网,看到了关于 Disruptor 的介绍.感觉此框架惊为天人,值 ...
- 【APP测试(Android)】--性能测试