文章目录
java程序员的scala基础学习笔记,只记录了些基础知识。
hello world
package blog
object HelloWorld {
/* 这是我的第一个 Scala 程序
* 以下程序将输出'Hello World!'
*/
def main(args: Array[String]) {
println("Hello, world!") // 输出 Hello World
}
}
关键字转义
与关键字同名,需要转义,例
Thread.`yield`();
yield为关键字,需要加引号转义
数据类型
变量
scala可以算是弱类型的,用法与js中的有些相似。
var定义变量,val定义常量
var a = 1; //变量
val b = 2; //常量
scala同样支持强类型的定义方法
var a : Int = 1;
具体语法为
var VariableName : DataType [= Initial Value]
或
val VariableName : DataType [= Initial Value]
元组
在 Scala 中,元组是一个可以容纳不同类型元素的类。 元组是不可变的。
当我们需要从函数返回多个值时,元组会派上用场。
var py: (Int, String) = (40, "")
很python的感觉,就用py来命名了。
这东西感觉就像是另一种Object[]一样,只是多了一些特有的方法与限制
另一种更显式的写法
var py2: Tuple2[Int, String] = (40, "")
Tuple2
是类型,后面的数字是数组的元素数量,Tuple2
大致相当于 Object[2]
。
访问元素
可以用下标取值
var py2: Tuple2[Int, String] = (40, "str")
println(py2._1)
println(py2._2)
解构
var py2: Tuple2[Int, String] = (40, "str");
var (v1, v2) = py2;
println(v1);
println(v2);
模式匹配(case when)
val planetDistanceFromSun = List(("Mercury", 57.9), ("Venus", 108.2), ("Earth", 149.6), ("Mars", 227.9), ("Jupiter", 778.3))
planetDistanceFromSun.foreach { tuple =>
{
tuple match {
case ("Mercury", distance) => println(s"Mercury is $distance millions km far from Sun")
case p if (p._1 == "Venus") => println(s"Venus is ${p._2} millions km far from Sun")
case p if (p._1 == "Earth") => println(s"Blue planet is ${p._2} millions km far from Sun")
case _ => println("Too far....")
}
}
}
for中的使用
val numPairs = List((2, 5), (3, -7), (20, 56))
for ((a, b) <- numPairs) {
println(a * b)
}
函数变量
val addOne = (x: Int) => x + 1
println(addOne(1)) // 2
方法
def add(x: Int, y: Int): Int = x + y
println(add(1, 2)) // 3
与函数不同,方法中可以做更多事情
def add(x: Int, y: Int): Int = {
var nv = 9;
return x + y + nv
}
println(add(1, 2)) // 12
甚至多个参数列表
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
访问修饰符
private,protected,public。缺省为public
与java不同的地方
private
private,更严格,只在内部可见。也即外部类中不可见,虽然也没人那么用就是了。用java代码来表示就是类似下面这样的代码将变得非法
public class Test02 {
public static void main(String[] args) {
int w = new Test02().new Inner().i;
}
class Inner{
private int i = 1;
}
}
用scala代码来表示
class Outer{
class Inner{
private def f(){println("f")}
class InnerMost{
f() // 正确
}
}
(new Inner).f() //错误
}
protected
比java更严格,只有当前类,子类可访问
循环
for
查了不少资料,确实有很多种写法,但是本质上都只是foreach,这东西没什么灵活性,随便记几个例子好了。
for (i <- 1 to 3) {
println(i)
}
普通for循环
case class User(name: String, age: Int)
val userBase = List(User("Travis", 28),
User("Kelly", 33),
User("Jennifer", 44),
User("Dennis", 23))
val twentySomethings = for (user <- userBase if (user.age >=20 && user.age < 30))
yield user.name // i.e. add this to a list
twentySomethings.foreach(name => println(name)) // prints Travis Dennis
循环里面加了个判断,并且用了yield关键字——scala的for循环可以通过yield使用返回值
while
与java中的一致
var i : Int= 0;
while(i < 3){
println(i)
i+=1;
}
循环控制
scala中不直接提供break、continue语法,需要额外加一些东西
import util.control.Breaks._
object Test01 {
def main(args: Array[String]): Unit = {
//foreach break
breakable{
for (i <- 1 to 10) {
println(i)
if (i == 3)
break;
}}
//foreach continue
for (i <- 1 to 10) {
breakable {
if (i == 3)
break
println(i)
}
}
//while break
breakable{
var i : Int = 0;
while (i < 10) {
println(i);
if(i == 1)
break;
}}
//while continue
var i : Int = 0;
while (i < 10){
breakable{
println(i);
if(i == 1)
break;
}
}
}
}
嵌套循环控制
大致相当于java中的这种语法
//java
a: for(int i = 0; i < 3; i++){
break a;
}
import util.control.Breaks._
import scala.util.control._
object Test01 {
def main(args: Array[String]) {
var a = 0;
var b = 0;
val numList1 = List(1,2,3,4,5);
val numList2 = List(11,12,13);
val outer = new Breaks;
val inner = new Breaks;
outer.breakable {
for( a <- numList1){
println( "Value of a: " + a );
inner.breakable {
for( b <- numList2){
println( "Value of b: " + b );
if( b == 12 ){
inner.break; //内层break
//outer.break; //直接跳出外层
}
}
} // 内嵌循环中断
}
} // 外部循环中断
}
}
方法与函数
- Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。
- Scala 中的方法跟 Java 的类似,方法是组成类的一部分。
- Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。
- Scala 中使用 val 语句可以定义函数,def 语句定义方法。
这段来自菜鸟教程的话可以带来一个直观的认识——方法与函数基本可以看做一种东西的两种写法。
A Function Type is (roughly) a type of the form (T1, …, Tn) => U, which is a shorthand for the trait FunctionN in the standard library. Anonymous Functions and Method Values have function types, and function types can be used as part of value, variable and function declarations and definitions. In fact, it can be part of a method type.
A Method Type is a non-value type. That means there is no value - no object, no instance - with a method type. As mentioned above, a Method Value actually has a Function Type. A method type is a def declaration - everything about a def except its body.
虽然有许多不同,不过把方法当做java的方法来用,函数当做js的函数来用大概就可以了的感觉。
方法
定义:
def functionName ([参数列表]) : [return type] = {
function body
return [expr]
}
需要注意一下的是方法里面甚至可以再写一个方法(允许嵌套方法)
方法可以接受多个参数列表
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
方法的返回值
: [return type]
定义返回值类型,Unit相当于java中的void,不过即使定义了Unit,也依然可以使用return语句或者使用输出语句将方法打印,不过输出结果都是()
,一个空的元组。
object Test02 {
def main(args: Array[String]): Unit = {
println(mhd() == ()); //true
}
def mhd() : Unit = {
return 123;
}
}
方法中允许省略return关键字,并将最后一行的结果自动识别为返回值。
不过怎么想都是个鸡肋的特性,先不说不少方法都需要多个return来控制逻辑,return这个关键字本身也会有一个提示的作用,帮助更快的理解代码。
函数
函数的一般写法
((x: Int) => x + 1); //定义匿名函数
((x: Int) => println(x))(1); //调用匿名函数
println(((x: Int) => x + 1)(1)); //调用匿名函数并输出返回值
var aa = (x: Int, y: Int) => x + y + 1; //定义多个参数
(x: Int, y: Int) => {
var z = x + y;
z + 1;
}; // 使用块来调用多行代码
高阶函数
higher-order function,就是把函数当变量用,可以作为参数,也可以作为返回值。
- 函数作为参数
var fc = (f : Int => String) => f(1);
println(fc((x) => "" + x));
解释:上面代码中的Int
为型参f函数在fc函数中的参数类型,String
为f的返回类型。
如果f有多个参数,可以这样写
var fc = (f : (Int, Int) => String) => f(1, 2);
println(fc((x, y) => "" + x + y));
- 将函数作为返回值的函数
var ff = () => {(a : Int, b : Int) => {a + b}};
var backFunc = ff();
println(backFunc(1, 2));
提示:(a : Int, b : Int) => {a + b}
是函数ff所返回的匿名函数
与java的整合
scala作为在jvm上执行的语言,基本可以直接调用java代码,但是在一些细节上还是有一些差距,需要记录一下。
网上没找到相关资料,想到一个记一个。
scala会默认引用引用java.lang.*中的,这一点与java一致。若引用别的包,需要手动import。scala对import进行了一定程度的扩展,但是也是完全兼容java语法的。
scala中使用java.util.ArrayList
scala肯定是由自己的集合实现的(https://www.scala-lang.org/api/current/scala/collection/immutable/List.html),但是也可以直接使用java中的类。
import java.util.ArrayList
object Test02 {
def main(args: Array[String]): Unit = {
var list = new ArrayList
println(list.size());
}
}
这里list应该是不能直接添加值的
var list = new ArrayList;
list.add("");
这么写会报错,需要指定泛型
var list = new ArrayList[String];
list.add("");
java与scala对象互相转换
集合
import scala.collection.JavaConverters._
val list: java.util.List[Int] = List(1, 2, 3, 4).asJava
list.size(); //java object
val buffer: scala.collection.mutable.Buffer[Int] = list.asScala
buffer.length; //scala object
简单来说,需要先引入import scala.collection.JavaConverters._
具体规则在官方文档中有详细说明
https://www.scala-lang.org/api/current/scala/collection/JavaConverters$.html
抄过来一点
The following conversions are supported via asScala and asJava:
scala.collection.Iterable <=> java.lang.Iterable
scala.collection.Iterator <=> java.util.Iterator
scala.collection.mutable.Buffer <=> java.util.List
scala.collection.mutable.Set <=> java.util.Set
scala.collection.mutable.Map <=> java.util.Map
scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
The following conversions are supported via asScala and through specially-named extension methods to convert to Java collections, as shown:
scala.collection.Iterable <=> java.util.Collection (via asJavaCollection)
scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration)
scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary)
In addition, the following one-way conversions are provided via asJava:
scala.collection.Seq => java.util.List
scala.collection.mutable.Seq => java.util.List
scala.collection.Set => java.util.Set
scala.collection.Map => java.util.Map
The following one way conversion is provided via asScala:
java.util.Properties => scala.collection.mutable.Map
In all cases, converting from a source type to a target type and back again will return the original source object. For example:
import scala.collection.JavaConverters._
val source = new scala.collection.mutable.ListBuffer[Int]
val target: java.util.List[Int] = source.asJava
val other: scala.collection.mutable.Buffer[Int] = target.asScala
assert(source eq other)
Alternatively, the conversion methods have descriptive names and can be invoked explicitly.
scala> val vs = java.util.Arrays.asList("hi", "bye")
vs: java.util.List[String] = [hi, bye]
scala> val ss = asScalaIterator(vs.iterator)
ss: Iterator[String] = <iterator>
scala> .toList
res0: List[String] = List(hi, bye)
scala> val ss = asScalaBuffer(vs)
ss: scala.collection.mutable.Buffer[String] = Buffer(hi, bye)