跳出循環語句的3種方法java
多維數組正則表達式
內部類獲取外部類的引用jvm
package定義ide
方法一:使用boolean控制變量
while循環:
var flag = true
var res = 0
var n = 0
while(flag) {
res += n
n += 1
if (n == 5) {
flag = false
}
}
for循環:(高級for循環,加上了if守衛)
var flag = true
var res = 0
for (i <- 0 until 10 if flag) {
res += i
if (i == 4) flag = false
}
方法二:在嵌套函數中使用return
def add_outer() = {
var res = 0
def add_inner() {
for (i <- 0 until 10) {
if (i == 5) {
return
}
res += i
}
}
add_inner()
res
}
方法三:使用Breaks對象的break方法
跟java裏面的break比較相似,相對來講,比較靈活好用;與breakable代碼塊配合使用
import scala.util.control.Breaks._
var res = 0
breakable {
for (i <- 0 until 10) {
if (i == 5) {
break;
}
res += i
}
}
什麼是多維數組?:數組的元素,仍是數組,數組套數組,就是多維數組
構造指定行與列的二維數組:Array.ofDim方法
val multiDimArr1 = Array.ofDim[Double](3, 4)
multiDimArr1(0)(0) = 1.0
構造不規則多維數組:
val multiDimArr2 = new Array[Array[Int]](3)
multiDimArr2(0) = new Array[Int] (1)
multiDimArr2(1) = new Array[Int] (2)
multiDimArr2(2) = new Array[Int] (3)
multiDimArr2(1)(1) = 1
Scala代碼中,直接調用JDK(Java)的API,好比調用一個Java類的方法,勢必可能會傳入Java類型的list,此時若是直接把Scala的ArrayBuffer傳入Java接收ArrayList的方法,確定不行。這能夠先將Scala中的Buffer轉換爲Java中的List便可
import scala.collection.JavaConversions.bufferAsJavaList
import scala.collection.mutable.ArrayBuffer
val command = ArrayBuffer("javac", "C:\\Users\\Administrator\\Desktop\\HelloWorld.java") // 調用操做系統命令編譯源碼
// ProcessBuilder爲JDK中的類,構造函數爲:ProcessBuilder(List<String> command),要求的是List,因此須要將Scala的Buffer轉換爲Java中的List,才能在Java中使用
val processBuilder = new ProcessBuilder(command)
val process = processBuilder.start()
val res = process.waitFor()
下面是將Java返回的List轉換爲Buffer:
import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.mutable.Buffer
// ProcessBuilder的command()方法返回的是List<String>,因此須要將List<String>隱式轉換爲Buffer[String],才能在Scala中使用
val cmd: Buffer[String] = processBuilder.command()
import scala.collection.JavaConversions.mapAsScalaMap
val javaScores = new java.util.HashMap[String, Int]()
javaScores.put("Alice", 10)
javaScores.put("Bob", 3)
javaScores.put("Cindy", 8)
val scalaScores: scala.collection.mutable.Map[String, Int] = javaScores // Java Map自動隱式轉換 Scala Map
import scala.collection.JavaConversions.mapAsJavaMap
import java.awt.font.TextAttribute._
val scalaAttrMap = Map(FAMILY -> "Serif", SIZE -> 12)
val font = new java.awt.Font(scalaAttrMap) // Scala Map自動隱式轉換 Java Map
Tuple拉鍊操做指的就是zip操做
zip操做,是Array類的方法,用於將兩個Array,合併爲一個Array
好比Array(v1)和Array(v2),使用zip操做合併後的格式爲Array((v1,v2))
合併後的Array的元素類型爲Tuple
val students = Array("Leo", "Jack", "Jen")
val scores = Array(80, 100, 90)
val studentScores = students.zip(scores)
for ((student, score) <- studentScores)
println(student + " " + score)
若是Array的元素類型是個Tuple,調用Array的toMap方法,能夠將Array轉換爲Map
studentScores.toMap
import scala.collection.mutable.ArrayBuffer
class Class {
class Student(val name: String)
val students = new ArrayBuffer[Student]
def register(name: String) = {
new Student(name)
}
}
val c1 = new Class
val leo = c1.register("leo")
c1.students += leo
val c2 = new Class
val jack = c2.register("jack")
c1.students += jack // error: type mismatch;
object Class {
class Student(val name: String)
}
class Class {
val students = new ArrayBuffer[Class.Student]
def register(name: String) = {
new Class.Student(name)
}
}
val c1 = new Class
val leo = c1.register("leo")
c1.students += leo
val c2 = new Class
val jack = c2.register("jack")
c1.students += jack
class Class {
class Student(val name: String)
val students = new ArrayBuffer[Class#Student] // 明確說明使用的是Class類型中的Student類,而非Class對象中的
def register(name: String) = {
new Student(name)
}
}
val c1 = new Class
val leo = c1.register("leo")
c1.students += leo
val c2 = new Class
val jack = c2.register("jack")
c1.students += jack
class Class(val name: String) {
outer => //名隨便
class Student(val name: String) {
def introduceMyself = "Hello, I'm " + name + ", I'm very happy to join class " + outer.name
}
def register(name: String) = {
new Student(name)
}
}
val c1 = new Class("c1")
val leo = c1.register("leo")
leo.introduceMyself
由於要對多個同名的類進行命名空間的管理,避免同名類發生衝突
好比說,scala.collection.mutable.Map和scala.collection.immutable.Map
package定義的第一種方式: 多層級package定義(比較差的作法,通常不這麼幹)
package com {
package sn {
package scala {
class Test {}
}
}
}
package定義的第二種方式: 串聯式package定義(也不怎麼樣,通常也不這麼幹)
package com.sn.scala {
package service {
class Test {}
}
}
package定義的第三種方式: 文件頂部package定義
package com.sn.scala.service
class Test {
}
同一個包定義,能夠在不一樣的scala源文件中的:
Test1.scala
package com {
package sn {
package scala {
class Test1
}
}
}
Test2.scala
package com {
package sn {
package scala {
class Test2
}
}
}
一個scala源文件內,能夠包含兩個包:
Test3.scala
package com {
package sn {
package scala1 {
class Test
}
}
}
package com {
package sn {
package scala2 {
class Test
}
}
}
子包中的類,能夠訪問父包中的類:
Test.scala
package com {
package sn {
package scala {
object Utils {
def isNotEmpty(str: String): Boolean = str != null && str != ""
}
class Test
package service {
class MyService {
def sayHello(name: String) {
if (Utils.isNotEmpty(name)) {
println("Hello, " + name)
} else {
println("Who are you?")
}
}
}
}
}
}
}
object T {
def main(args: Array[String]) {
import com.sn.scala.service._
new MyService().sayHello("")
new MyService().sayHello("leo")
}
}
相對包名與絕對包名:
package com {
package sn {
package scala {
object Utils {
def isNotEmpty(str: String): Boolean = str != null && str != ""
}
class Test
package collection {}
package service {
class MyService {
// 報錯,默認使用相對報名,從com.sn.scala.collection包中,尋找mutable包下的ArrayBuffer類
// 可是找不到,因此會報錯
// val names = new scala.collection.mutable.ArrayBuffer[String]
// 正確的作法是使用_root_,引用絕對包名
val names = new _root_.scala.collection.mutable.ArrayBuffer[String]
def sayHello(name: String) {
if (Utils.isNotEmpty(name)) {
println("Hello, " + name)
} else {
println("Who are you?")
}
}
}
}
}
}
}
定義package對象(比較少用):
package內的成員,能夠直接訪問package對象內的成員
package com.sn.scala
package object service {
val defaultName = "Somebody"
}
package service {
class MyService {
def sayHello(name: String) {
if (name != null && name != "") {
println("Hello, " + name)
} else {
println("Hello, " + defaultName)//訪問包對象中的成員
}
}
}
}
package可見性:
package com.sn {
package scala {
class Person {
//com.sn.scala包下可見
private[scala] val name = "leo"
//com.sn包下可見
private[sn] val age = 25
}
object T1 {
new Person().name
}
}
object T2 {
import com.sn.scala.Person
new Person().age
}
}
package com.sn.scala
package service {
class MyService {
def sayHello(name: String) {}
}
}
import com.sn.scala.service.MyService;
object MainClass {
def main(args: Array[String]): Unit = {
val service = new MyService
}
}
import特性一: 用import com.sn.scala.service._這種格式,能夠導入包下全部的成員
import特性二: scala與java不一樣之處在於,任何地方均可以使用import,好比類內、方法內,這種方式的好處在於,能夠在必定做用域範圍內使用導入
object MainClass {
def main(args: Array[String]): Unit = {
import com.sn.scala.service._
val service = new MyService
}
}
import特性三: 選擇器、重命名、隱藏
import com.sn.scala.service.{ MyService },僅僅導入com.sn.scala.service包下的MyService類,其它不導入
import com.sn.scala.service.{ MyService => MyServiceImpl },將導入的類進行重命名
import com.sn.scala.service.{ MyService => _, _ },導入com.sn.scala.service包下全部的類,可是隱藏掉MyService類
import特性四: 隱式導入
每一個scala程序默認都會隱式導入如下幾個包下全部的成員
import java.lang._
import scala._
import Predef._
默認狀況下,若是父類中的構造函數代碼用到了被子類重寫(或實現)的field,那麼可能會出現未被正確初始化的問題:
當父類的構造函數執行時,若是使用到了被子類實現或重寫過的field(field重寫或實現至關於對應的getter方法被重寫),會調用子類重寫或實現過的field,因爲子類構造器尚未執行,因此會返回子類中被重寫或實現過的該field的初始值(好比Int爲0,String爲null)。詳細能夠參數《Scala編程基礎》中的「trait field的初始化」相應章節
class Student {
val classNumber: Int = 10
val classScores: Array[Int] = new Array[Int](classNumber) // 會調用子類被重寫過的classNumber字段
}
class PEStudent extends Student {
override val classNumber: Int = 3
}
scala> new PEStudent().classScores
res42: Array[Int] = Array()
原本咱們指望的是,PEStudent,能夠從Student繼承來一個長度爲3的classScores數組,結果PEStudent對象,只有一個長度爲0的classScores數組
此時只能使用Scala對象繼承的一個高級特性: 提早定義,在父類構造函數執行以前,先執行子類的構造函數中的某些代碼
class Student {
val classNumber: Int = 10
val classScores: Array[Int] = new Array[Int](classNumber) // 會調用子類被重寫過的classNumber字段
}
class PEStudent extends {
override val classNumber: Int = 3
} with Student
scala> new PEStudent().classScores
res43: Array[Int] = Array(0, 0, 0)
也能夠這樣,但Student需定義成trait:
trait Student {
val classNumber: Int = 10
val classScores: Array[Int] = new Array[Int](classNumber)
}
class PEStudent extends Student {
}
var ps = new {override val classNumber: Int = 3} with PEStudent with Student
ps.classScores
這裏咱們大概知道一下Scala的繼承層級,咱們寫的全部的Scala trait和class,都是默認繼承自一些Scala根類的,有一些基礎的方法
Scala中,最頂端的兩個trait是Nothing和Null,Null trait惟一的對象就是null
其次是繼承了Nothing trait的Any類
接着Anyval trait和AnyRef類,都繼承自Any類
Any類是個比較重要的類,其中定義了isInstanceOf和asInstanceOf等方法,以及equals、hashCode等對象的基本方法
Any類,有點像Java中的Object基類
AnyRef類,增長了一些多線程的方法,好比wait、notify/notifyAll、synchronized等,也是屬於Java Object類的一部分
這裏,咱們要知道,在scala中,你如何判斷兩個引用變量,是否指向同一個對象實例
AnyRef的eq方法用於檢查兩個變量是否指向同一個對象實例
AnyRef的equals方法默認調用eq方法實現,也就是說,默認狀況下,判斷兩個變量相等,要求必須指向同一個對象實例
一般狀況下,本身能夠重寫equals方法,根據類的fields來斷定是否相等
此外,定義equals方法時,也最好使用一樣的fields,重寫hashCode方法
若是隻是想要簡單地經過是否指向同一個對象實例,斷定變量是否至關,那麼直接使用==操做符便可,默認判斷null,而後調用equals方法
class Product(val name: String, val price: Double) {
final override def equals(other: Any) = {
val that = other.asInstanceOf[Product]
if (that == null) false
else name == that.name && price == that.price
}
final override def hashCode = 13 * name.hashCode + 17 * price.hashCode
}
必須導入scala.io.Source類: import scala.io.Source
方法一: 使用Source.getLines返回的迭代器
val source = Source.fromFile("C://Users//Administrator//Desktop//test.txt", "UTF-8")
val lineIterator = source.getLines
for (line <- lineIterator) println(line)
方法二: 將Source.getLines返回的迭代器轉換成數組
val source = Source.fromFile("C://Users//Administrator//Desktop//test.txt", "UTF-8")
val lines = source.getLines.toArray
for(line <- lines) println(line)
這裏說明一點: 一個BufferedSource對象的getLines方法,只能調用一次,一次調用完以後,遍歷了迭代器裏全部的內容,就已經把文件裏的內容讀取完了
若是反覆調用source.getLines,是獲取不到內容的。此時,必須從新建立一個BufferedSource對象
方法三: 調用Source.mkString,返回文本中全部的內容
val source = Source.fromFile("C://Users//Administrator//Desktop//test.txt", "UTF-8")
val lines = source.mkString
使用完BufferedSource對象以後,調用BufferedSource.close方法,關閉IO流資源
遍歷一個文件中的每個字符
val source = Source.fromFile("C://Users//Administrator//Desktop//test.txt", "UTF-8")
for (c <- source) print(c)// BufferedSource,也實現了一個Iterator[Char]的一個trait
從URL以及字符串中讀取字符
val source = Source.fromURL("http://www.baidu.com", "UTF-8")
val source = Source.fromString("Hello World")
結合Java IO流,讀取任意文件
案例: 結合java IO流,作一個文件拷貝的案例
import java.io._
val f = new File("C:/Users/Administrator/Desktop/1.txt")
val fis = new FileInputStream(f)
val fos = new FileOutputStream(new File("C:/Users/Administrator/Desktop/2.txt"))
val buf = new Array[Byte](f.length.toInt)
fis.read(buf)
fos.write(buf)
fis.close()
fos.close()
結合Java IO流,寫文件
val pw = new PrintWriter("C://Users//Administrator//Desktop//test4.txt")
pw.println("Hello World")
pw.close()
遞歸遍歷指定目錄的全部子目錄:
import java.io._
def getSubdirIterator(dir: File): Iterator[File] = {
//filter:對數組進行過濾,只要目錄的。filter返回的爲數組
val childDirs = dir.listFiles.filter(_.isDirectory)
//childDirs.toIterator:數組轉迭代器。++:兩個迭代器相加
childDirs.toIterator ++ childDirs.toIterator.flatMap(getSubdirIterator _)//對子目錄進行遞歸
}
val iterator = getSubdirIterator(new File("C://Users//Administrator//Desktop"))
for (d <- iterator) println(d)
仍是要藉助於Java序列化和反序列化機制
若是要序列化,那麼就必須讓類,有一個@SerialVersionUID,定義一個版本號
要讓類繼承一個Serializable trait
@SerialVersionUID(42L) class Person(val name: String) extends Serializable
val leo = new Person("leo")
import java.io._
val oos = new ObjectOutputStream(new FileOutputStream("C://Users//Administrator//Desktop//test.obj"))
oos.writeObject(leo)
oos.close()
val ois = new ObjectInputStream(new FileInputStream("C://Users//Administrator//Desktop//test.obj"))
val restoredLeo = ois.readObject().asInstanceOf[Person]
restoredLeo.name
偏函數,是一種高級的函數形式
簡單來講,偏函數是什麼,其實就是沒有定義好明確的輸入參數的函數(或是不能處理全部狀況的函數),函數體就是一連串的case語句
通常的函數:
def getStudentGrade(name: String) = {
...
}
偏函數是PartialFunction[A, B]類的一個實例
這個類有兩個方法,一個是apply()方法,直接調用能夠經過函數體內的case進行匹配,返回結果;
另外一個是isDefinedAt()方法,能夠返回一個輸入,是否跟任何一個case語句匹配
學生成績查詢案例:
val getStudentGrade: PartialFunction[String, Int] = {
case "Leo" => 90; case "Jack" => 85; case "Marry" => 95
}
getStudentGrade("Leo")
getStudentGrade.isDefinedAt("Tom")
import sys.process._
"javac HelloWorld.java" !
"java HelloWorld" !
定義一個正則表達式,使用String類的r方法
此時返回的類型是scala.util.matching.Regex類的對象
val pattern1 = "[a-z]+".r
val str = "hello 123 world 456"
獲取一個字符串中,匹配正則表達式的部分,使用findAllIn,會獲取到一個Iterator,迭代器
而後就能夠去遍歷各個匹配正則的部分,去進行處理
for (matchString <- pattern1.findAllIn(str)) println(matchString)
同理,使用findFirstIn,能夠獲取第一個匹配正則表達式的部分
pattern1.findFirstIn(str)
使用replaceAllIn,能夠將匹配正則的部分,替換掉
pattern1.replaceFirstIn("hello world", "replacement")
使用replaceFirstIn,能夠將第一個匹配正則的部分,替換掉
pattern1.replaceAllIn("hello world", "replacement")
apply方法:
伴生類和伴生對象的概念,companion class和companion object
伴生對象裏面,能夠定義一個apply方法
直接調用類(參數),方式,就至關於在調用apply方法
此時在apply方法中,一般來講(也不必定),會建立一個伴生類的對象,返回回去
這種方式,有一個好處,建立對象呢,很是的方便
不要每次都是new 類(參數),而是 類(參數)
提取器 unapply方法:
和apply方法,顧名思義,那就是反過來
apply方法,能夠理解爲,接收一堆參數,而後返回一個對象
unapply方法,能夠理解爲,接收一個字符串,解析成一個對象的各個字段
提取器就是一個包含了unapply方法的對象,跟apply方法正好相反
apply方法,是接收一堆參數,而後構造出來一個對象
unapply方法,是接收一個字符串,而後解析出對象的屬性值
class Person(val name: String, val age: Int)
object Person {
def apply(name: String, age: Int) = new Person(name, age)
def unapply(str: String) = {
val splitIndex = str.indexOf(" ")
if (splitIndex == -1) None
else Some((str.substring(0, splitIndex), str.substring(splitIndex + 1)))
}
}
scala> val Person(name, age) = "leo 25"// 會調用unapply方法進行解析,將"leo 25"解析成相應成員
name: String = leo
age: String = 25
scala中的樣例類,相似於java中的javabean
java中的JavaBean,包含了一堆屬性,field; 每一個field都有一對getter和setter方法:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
scala中的樣例類,默認就是提供apply方法和unapply方法的
case class Person(name: String, age: Int)
val p = Person("leo", 25)
p match {
case Person(name, age) => println(name + ": " + age)
}
以前,已經跟你們講解過普通的提取器
至關因而,好比說,接收一個字符串,做爲參數
而後從字符串裏面解析出來多個字段值,而後將多個字段值封裝在一個tuple中
做爲Some類型的對象,返回
若是你的類只有一個字段,字符串裏面只有一個字段,
解析出來的一個字段,是沒有辦法放在tuple中的,由於scala中的tuple,規定了,必需要兩個以及兩個以上的值
這個時候,在提取器,unapply方法中,只能將一個字段值,封裝在Some對象中,直接返回
class Person(val name: String)
object Person {
def unapply(input: String): Option[String] = Some(input)
}
val Person(name) = "leo"
代碼中,加入一些特殊的標記。在代碼編譯或運行時,在碰到註解的時候,作一些特殊的操做
scala中,能夠給類、方法、field、local variable、constructor / method / function parameter添加註解
並且scala是支持給某個目標添加多個註解的
這裏有一些特例:若是要給類的主構造函數添加註解,那麼須要在構造函數前添加註解,並加上一對圓括號
好比說
class Person @Unchecked() (val name: String, val age: Int)
還能夠給表達式添加註解,此時須要在表達式後面加上冒號以及註解,好比
val scores = Map("Leo" -> 90, "Jack" -> 60)
(scores.get("Leo"): @unchecked) match { case score => println(score) }
除此以外,還能夠給類型參數和變量的類型定義添加註解
要本身動手開發一個註解,就必須擴展Annotation trait,好比
class Test extends annotation.Annotation
@Test
class myTest
註解中,是能夠有參數的,好比
class Test(var timeout: Int) extends annotation.Annotation
@Test(timeout = 100) class myTest
若是註解只有一個參數的話,那麼也能夠不用指定註解的參數名,好比
@Test(100) class myTest
@volatile var name = "leo" 輕量級的java多線程併發安全控制
jvm,java虛擬機中,能夠有多個線程
每一個線程都有本身的工做區,還有一起全部線程共享的工做區
每次一個線程拿到一個公共的變量,都須要從共享區中拷貝一個副本到本身的工做區中使用和修改
而後修改完之後,再在一個合適的時機,將副本的值,寫回到共享區中
這裏就會出現一個多線程併發訪問安全的問題
多個線程若是同時拷貝了變量副本,都作了不一樣的修改
而後依次將副本修改的值,寫回到共享區中,會依次覆蓋掉以前的一些副本值
就會出現變量的值,是不符合預期的
volatile關鍵字修飾的變量
它能夠保證,一個線程在從共享區獲取一個變量的副本時,都會強制刷新一下這個變量的值
保證本身獲取到的變量的副本值是最新的
因此這樣子作呢,是一種輕量級的多線程併發訪問控制辦法
可是也不是百分之百保險的,仍是有可能會出現錯誤的風險
@transient var name = "leo" 瞬態字段,不會序列化這個字段
以前講序列化,默認會將一個對象中全部的字段的值,都序列化到磁盤文件中去
而後反序列化的時候,還能夠獲取這些字段的值
加了transient的字段,是瞬態的,序列化的時候,不會序列化這個字段
反序列化的時候,這個字段也就沒有值了
@SerialVersionUID(value) 標記類的序列化版本號
序列化版本號,這個什麼意思
若是咱們將一個類的對象序列化到磁盤文件上了
結果過了一段時間之後,這個類在代碼中改變了,此時若是你想將磁盤文件中的對象反序列化回來
就會報錯,由於你的序列化的對象的結構與代碼中的類結構已經不同了
針對這種問題,就應該有一個序列化版本號
若是你的類改變了,就從新生成一個序列化版本號
反序列化的時候,就會發現序列化類型的版本號和代碼中的類的版本號,不同
@native 標註用c實現的本地方法
@throws(classOf[Exception]) def test() {} 給方法標記要拋出的checked異常
@varargs def test(args: String*) {} 標記方法接收的是變長參數
@BeanProperty 標記生成JavaBean風格的getter和setter方法
@BooleanBeanProperty 標記生成is風格的getter方法,用於boolean類型的field
@deprecated(message = "") 讓編譯器提示警告
@unchecked 讓編譯器不提示警告
scala對xml有很好的支持,能夠直接在scala代碼中定義一個xml文檔元素
scala> val books = <books><book>my first scala book</book></books>
books: scala.xml.Elem = <books><book>my first scala book</book></books>
此時doc的類型是scala.xml.Elem,也就是一個xml元素
scala還能夠直接定義多個同級別的xml元素
scala> val books = <book>my first scala book</book><book>my first spark book</book>
books: scala.xml.NodeBuffer = ArrayBuffer(<book>my first scala book</book>, <book>my first spark book</book>)
此時doc的類型是scala.xml.NodeBuffer,也就是一個xml節點序列
Node類是全部XML節點類型的父類型,兩個重要的子類型是Text和Elem。
Elem表示一個XML元素,也就是一個XML節點。scala.xml.Elem類型的label屬性,返回的是標籤名,child屬性,返回的是子元素。
scala.xml.NodeSeq類型,是一個元素序列,能夠用for循環,直接遍歷它。
scala> val books = <books><book></book></books>
books: scala.xml.Elem = <books><book></book></books>
scala> books.label
res10: String = books
能夠經過scala.xml.NodeBuffer類型,來手動建立一個節點序列:
scala> val booksBuffer = new scala.xml.NodeBuffer
booksBuffer: scala.xml.NodeBuffer = ArrayBuffer()
scala> booksBuffer += <book>book1</book>
res2: booksBuffer.type = ArrayBuffer(<book>book1</book>)
scala> booksBuffer += <book>book2</book>
res3: booksBuffer.type = ArrayBuffer(<book>book1</book>, <book>book2</book>)val books: scala.xml.NodeSeq = booksBuffer
scala> for(bb <- booksBuffer) println(bb)
<book>book1</book>
<book>book2</book>
scala> val books: scala.xml.NodeSeq = booksBuffer
books: scala.xml.NodeSeq = NodeSeq(<book>book1</book>, <book>book2</book>)
scala> for(b <- books) println(b)
<book>book1</book>
<book>book2</book>
scala.xml.Elem.attributes屬性,能夠返回這兒xml元素的屬性,是Seq[scala.xml.Node]類型的,繼續調用text屬性,能夠拿到屬性的值
scala> val book = <book id="1" price="10.0">book1</book>
book: scala.xml.Elem = <book id="1" price="10.0">book1</book>
scala> val bookId = book.attributes("id").text
bookId: String = 1
還能夠遍歷屬性
scala> for(attr <- book.attributes) println(attr)
id="1" price="10.0"
price="10.0"
還能夠調用book.attributes.asAttrMap,獲取一個屬性Map
scala> val books = Array("book1", "book2")
books: Array[String] = Array(book1, book2)
scala> <books><book>{ books(0) }</book><book>{ books(1) }</book></books>
res12: scala.xml.Elem = <books><book>book1</book><book>book2</book></books>
scala> <books>{ for (book <- books) yield <book>{book}</book> }</books>
res13: scala.xml.Elem = <books><book>book1</book><book>book2</book></books>
還能夠在xml屬性中嵌入scala代碼:
<book id={ books(0) }>{ books(0) }</book>
默認狀況下,scala中的xml表達式是不可改變的;若是要修改xml元素的話,必須拷貝一份再修改
val books = <books><book>book1</book></books>
添加一個子元素
val booksCopy = books.copy(child = books.child ++ <book>book2</book>)
val book = <book id="1">book1</book>
import scala.xml._
修改一個屬性
val bookCopy = book % Attribute(null, "id", "2", Null)
添加一個屬性
val bookCopy = book % Attribute(null, "id", "2", Attribute(null, "price", "10.0", Null))
import scala.xml._
import java.io._
使用scala的XML類加載
val books = XML.loadFile("C://Users//Administrator//Desktop//books.xml")
使用Java的FileInputStream類加載
val books = XML.load(new FileInputStream("C://Users//Administrator//Desktop//books.xml"))
使用Java的InputStreamReader類指定加載編碼
val books = XML.load(new InputStreamReader(new FileInputStream("C://Users//Administrator//Desktop//books.xml"), "UTF-8"))
將內存中的xml對象,寫入外部xml文檔
XML.save("C://Users//Administrator//Desktop//books2.xml", books)
col :+ ele 將元素添加到集合尾部 Seq
ele +: col 將元素添加到集合頭部 Seq
col + ele 在集合尾部添加元素 Set、Map
col + (ele1, ele2) 將其餘集合添加到集合的尾部 Set、Map
col - ele 將元素從集合中刪除 Set、Map、ArrayBuffer
col - (ele1, ele2) 將子集合從集合中刪除 Set、Map、ArrayBuffer
col1 ++ col2 將其餘集合添加到集合尾部 Iterable
col2 ++: col1 將其餘集合添加到集合頭部 Iterable
ele :: list 將元素添加到list的頭部 List
list2 ::: list1 將其餘list添加到list的頭部 List
list1 ::: list2 將其餘list添加到list的尾部 List
set1 | set2 取兩個set的並集 Set
set1 & set2 取兩個set的交集 Set
set1 &~ set2 取兩個set的diff Set
col += ele 給集合添加一個元素 可變集合
col += (ele1, ele2) 給集合添加一個集合 可變集合
col ++= col2 給集合添加一個集合 可變集合
col -= ele 從集合中刪除一個元素 可變集合
col -= (ele1, ele2) 從集合中刪除一個子集合 可變集合
col —= col2 從集合中刪除一個子集合 可變集合
ele +=: col 向集合頭部添加一個元素 ArrayBuffer
col2 ++=: col 向集合頭部添加一個集合 ArrayBuffer
head、last、tail
length、isEmpty
sum、max、min
count、exists、filter、filterNot
takeWhile、dropWhile
take、drop、splitAt
takeRight、dropRight
sclie
contains、startsWith、endsWith
indexOf
intersect、diff
map操做,一對一映射
scala> val scoreMap = Map("leo" -> 90, "jack" -> 60, "tom" -> 70)
scoreMap: scala.collection.immutable.Map[String,Int] = Map(leo -> 90, jack -> 60, tom -> 70)
scala> val names = List("leo", "jack", "tom")
names: List[String] = List(leo, jack, tom)
scala> names.map(scoreMap(_)) // 根據Key索引從Map中取對應的value
res14: List[Int] = List(90, 60, 70)
flatMap操做,一對多映射
scala> val scoreMap = Map("leo" -> List(80, 90, 60), "jack" -> List(70, 90, 50), "tom" -> List(60,70,40))
scoreMap: scala.collection.immutable.Map[String,List[Int]] = Map(leo -> List(80, 90, 60), jack -> List(70, 90, 50), tom -> List(60, 70, 40))
scala> names.map(scoreMap(_))
res15: List[List[Int]] = List(List(80, 90, 60), List(70, 90, 50), List(60, 70, 40))
scala> names.flatMap(scoreMap(_)) // 展平
res16: List[Int] = List(80, 90, 60, 70, 90, 50, 60, 70, 40)
collect操做,結合偏函數使用
scala> "abc".collect { case 'a' => 1; case 'b' => 2; case 'c' => 3 }
res17: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)
foreach操做,遍歷
names.foreach(println _)
reduce操做
scala> List(1, 2, 3,4).reduceLeft(_ - _) // 1 - 2 - 3 - 4
res21: Int = -8
scala> List(1, 2, 3,4).reduceRight(_ - _) // 1 - ( 2 - (3 - 4) )
res22: Int = 2
fold操做
scala> List(1, 2, 3,4).foldLeft(10)(_ - _) // 10 - 1 - 2 - 3
res23: Int = 0
scala> List(1, 2, 3,4).foldRight(10)(_ - _) // 1 - ( 2 - ( 3 - (4 - 10) ) )
res24: Int = 8
實際上,咱們能夠直接使用reduce,而不用reduceLeft,這時,默認採用的是reduceLeft,以下:
scala> List(1,2,3,4) .reduce(_ - _)
res5: Int = -8