scala 基础知识总结

在最开始处引入 log 相关的 包
import org.apache.log4j.{Logger,Level}

在需要屏蔽日志输出的地方加上这两行代码
// 屏蔽不必要的日志显示在终端上
    Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)


// scala io Case 类与匹配模式示例
package com.converter
import java.io.PrintWriter

import scala.io.Source
case class ICD(code:String,icdValue:Int)
object Demo {

   def main(args:Array[String]):Unit={
     println(apply("FrankLi","gmail"))
     println(unapply("FrankLi@gmail"))
     println(unapply("FrankLigmail"))

     // scala io 读取文件并进行操作
     val strIt=
                 Source.fromFile("input/icd")
                 .getLines()
                 .map{line =>
                   val  sb = new StringBuffer
                   val cols = line.split(",",-1)
                   ICD(cols(0),cols(1).toInt)
                   sb.append(cols(0))
                       .append("|")
                       .append(cols(1))
                   sb.toString
                 }
      val writer = new PrintWriter("input/convertedICD.txt")
       for(str <- strIt){
          writer.write(str)
          writer.write("\r\n")
//          writer.flush()
       }
       writer.close();
       // .foreach(println)
   }
  def apply(userName:String,domain:String):String={
    userName+"@"+domain
  }
  @throws(classOf[NumberFormatException])
  def unapply(emailAddress:String):Option[(String,String)]={
      val parts = emailAddress.split("@")
      if(parts.length == 2){
        Some((parts(0),parts(1)))
      }
      else
        None
  }
}


//提取器 unapply , apply


package com.converter

object Demo {

   def main(args:Array[String]):Unit={
     println(apply("FrankLi","gmail"))
     println(unapply("FrankLi@gmail"))
     println(unapply("FrankLigmail"))
   }
  def apply(userName:String,domain:String):String={
    userName+"@"+domain
  }
  def unapply(emailAddress:String):Option[(String,String)]={
      val parts = emailAddress.split("@")
      if(parts.length == 2){
        Some((parts(0),parts(1)))
      }
      else
        None
  }
}




// scala 基础函数

val testList=(1 to 10)

println("testListRes: "+testList.fold(0)((base,n) => base+n))

println("testListRes: "+testList.foldRight(0)((base,n) => base+n))

foldLeft ,  foldRight
整体替换, 迭代

val str = "abc"
println("strSub: "+str.substring(1,2))

subString 包含左边界不包含右边界
(角标从 0 开始算)

hcc 是个 int
val hccStr:String=String.valueOf(hcc)



Scala是数据挖掘算法领域最有力的编程语言之一,语言本身是面向函数,这也符合了数据挖掘算法的常用场景:在原始数据集上应用一系列的变换,语言本身也对集合操作提供了众多强大的函数,本文将以List类型为例子,介绍常见的集合变换操作。
一、常用操作符(操作符其实也是函数)
++ ++[B](that: GenTraversableOnce[B]): List[B] 从列表的尾部添加另外一个列表
++: ++:[B >: A, That](that: collection.Traversable[B])(implicit bf: CanBuildFrom[List[A], B, That]): That 在列表的头部添加一个列表
+: +:(elem: A): List[A] 在列表的头部添加一个元素
:+ :+(elem: A): List[A] 在列表的尾部添加一个元素
:: ::(x: A): List[A] 在列表的头部添加一个元素
::: :::(prefix: List[A]): List[A] 在列表的头部添加另外一个列表
:\ :[B](z: B)(op: (A, B) ⇒ B): B 与foldRight等价
val left = List(1,2,3)
val right = List(4,5,6)

//以下操作等价
left ++ right   // List(1,2,3,4,5,6)
left ++: right  // List(1,2,3,4,5,6)
right.++:(left)    // List(1,2,3,4,5,6)
right.:::(left)  // List(1,2,3,4,5,6)

//以下操作等价
0 +: left    //List(0,1,2,3)
left.+:(0)   //List(0,1,2,3)

//以下操作等价
left :+ 4    //List(1,2,3,4)
left.:+(4)   //List(1,2,3,4)

//以下操作等价
0 :: left      //List(0,1,2,3)
left.::(0)     //List(0,1,2,3)

看到这里大家应该跟我一样有一点晕吧,怎么这么多奇怪的操作符,这里给大家一个提示,任何以冒号结果的操作符,都是右绑定的,即 0 :: List(1,2,3) = List(1,2,3).::(0) = List(0,1,2,3) 从这里可以看出操作::其实是右边List的操作符,而非左边Int类型的操作符
二、常用变换操作
1.map
map[B](f: (A) ⇒ B): List[B]
定义一个变换,把该变换应用到列表的每个元素中,原列表不变,返回一个新的列表数据
Example1 平方变换
val nums = List(1,2,3)
val square = (x: Int) => x*x   
val squareNums1 = nums.map(num => num*num)    //List(1,4,9)
val squareNums2 = nums.map(math.pow(_,2))    //List(1,4,9)
val squareNums3 = nums.map(square)            //List(1,4,9)
1
2
3
4
5
Example2 保存文本数据中的某几列
val text = List("Homeway,25,Male","XSDYM,23,Female")
val usersList = text.map(_.split(",")(0))    
val usersWithAgeList = text.map(line => {
    val fields = line.split(",")
    val user = fields(0)
    val age = fields(1).toInt
    (user,age)
})

1
2
3
4
5
6
7
8
9
2.flatMap, flatten
flatten: flatten[B]: List[B] 对列表的列表进行平坦化操作 flatMap: flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B] map之后对结果进行flatten
定义一个变换f, 把f应用列表的每个元素中,每个f返回一个列表,最终把所有列表连结起来。
val text = List("A,B,C","D,E,F")
val textMapped = text.map(_.split(",").toList) // List(List("A","B","C"),List("D","E","F"))
val textFlattened = textMapped.flatten          // List("A","B","C","D","E","F")
val textFlatMapped = text.flatMap(_.split(",").toList) // List("A","B","C","D","E","F")

1
2
3
4
5
3.reduce
reduce[A1 >: A](op: (A1, A1) ⇒ A1): A1
定义一个变换f, f把两个列表的元素合成一个,遍历列表,最终把列表合并成单一元素
Example 列表求和

val nums = List(1,2,3)
val sum1 = nums.reduce((a,b) => a+b)   //6
val sum2 = nums.reduce(_+_)            //6
val sum3 = nums.sum                 //6

1
2
3
4
5
6
4.reduceLeft,reduceRight
reduceLeft: reduceLeft[B >: A](f: (B, A) ⇒ B): B
reduceRight: reduceRight[B >: A](op: (A, B) ⇒ B): B
reduceLeft从列表的左边往右边应用reduce函数,reduceRight从列表的右边往左边应用reduce函数
Example

val nums = List(2.0,2.0,3.0)
val resultLeftReduce = nums.reduceLeft(math.pow)  // = pow( pow(2.0,2.0) , 3.0) = 64.0
val resultRightReduce = nums.reduceRight(math.pow) // = pow(2.0, pow(2.0,3.0)) = 256.0

1
2
3
4
5
5.fold,foldLeft,foldRight
fold: fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1 带有初始值的reduce,从一个初始值开始,从左向右将两个元素合并成一个,最终把列表合并成单一元素。
foldLeft: foldLeft[B](z: B)(f: (B, A) ⇒ B): B 带有初始值的reduceLeft
foldRight: foldRight[B](z: B)(op: (A, B) ⇒ B): B 带有初始值的reduceRight

val nums = List(2,3,4)
val sum = nums.fold(1)(_+_)  // = 1+2+3+4 = 9

val nums = List(2.0,3.0)
val result1 = nums.foldLeft(4.0)(math.pow) // = pow(pow(4.0,2.0),3.0) = 4096
val result2 = nums.foldRight(1.0)(math.pow) // = pow(1.0,pow(2.0,3.0)) = 8.0

1
2
3
4
5
6
7
8
6.sortBy,sortWith,sorted
sortBy: sortBy[B](f: (A) ⇒ B)(implicit ord: math.Ordering[B]): List[A] 按照应用函数f之后产生的元素进行排序
sorted: sorted[B >: A](implicit ord: math.Ordering[B]): List[A] 按照元素自身进行排序
sortWith: sortWith(lt: (A, A) ⇒ Boolean): List[A] 使用自定义的比较函数进行排序
val nums = List(1,3,2,4)
val sorted = nums.sorted  //List(1,2,3,4)

val users = List(("HomeWay",25),("XSDYM",23))
val sortedByAge = users.sortBy{case(user,age) => age}  //List(("XSDYM",23),("HomeWay",25))
val sortedWith = users.sortWith{case(user1,user2) => user1._2 < user2._2} //List(("XSDYM",23),("HomeWay",25))

1
2
3
4
5
6
7
7.filter, filterNot
filter: filter(p: (A) ⇒ Boolean): List[A]
filterNot: filterNot(p: (A) ⇒ Boolean): List[A]
filter 保留列表中符合条件p的列表元素 , filterNot,保留列表中不符合条件p的列表元素
val nums = List(1,2,3,4)
val odd = nums.filter( _ % 2 != 0) // List(1,3)
val even = nums.filterNot( _ % 2 != 0) // List(2,4)

1
2
3
4
8.count
count(p: (A) ⇒ Boolean): Int
计算列表中所有满足条件p的元素的个数,等价于 filter(p).length
val nums = List(-1,-2,0,1,2) val plusCnt1 = nums.count( > 0) val plusCnt2 = nums.filter( > 0).length 
9. diff, union, intersect
diff:diff(that: collection.Seq[A]): List[A] 保存列表中那些不在另外一个列表中的元素,即从集合中减去与另外一个集合的交集
union : union(that: collection.Seq[A]): List[A] 与另外一个列表进行连结
intersect: intersect(that: collection.Seq[A]): List[A] 与另外一个集合的交集
val nums1 = List(1,2,3)
val nums2 = List(2,3,4)
val diff1 = nums1 diff nums2   // List(1)
val diff2 = nums2.diff(num1)   // List(4)
val union1 = nums1 union nums2  // List(1,2,3,2,3,4)
val union2 = nums2 ++ nums1        // List(2,3,4,1,2,3)
val intersection = nums1 intersect nums2  //List(2,3)
1
2
3
4
5
6
7
10.distinct
distinct: List[A] 保留列表中非重复的元素,相同的元素只会被保留一次
val list = List("A","B","C","A","B") val distincted = list.distinct // List("A","B","C")
1
11.groupBy, grouped
groupBy : groupBy[K](f: (A) ⇒ K): Map[K, List[A]] 将列表进行分组,分组的依据是应用f在元素上后产生的新元素 
grouped: grouped(size: Int): Iterator[List[A]] 按列表按照固定的大小进行分组
val data = List(("HomeWay","Male"),("XSDYM","Femail"),("Mr.Wang","Male"))
val group1 = data.groupBy(_._2) // = Map("Male" -> List(("HomeWay","Male"),("Mr.Wang","Male")),"Female" -> List(("XSDYM","Femail")))
val group2 = data.groupBy{case (name,sex) => sex} // = Map("Male" -> List(("HomeWay","Male"),("Mr.Wang","Male")),"Female" -> List(("XSDYM","Femail")))
val fixSizeGroup = data.grouped(2).toList // = Map("Male" -> List(("HomeWay","Male"),("XSDYM","Femail")),"Female" -> List(("Mr.Wang","Male")))



12.scan
scan[B >: A, That](z: B)(op: (B, B) ⇒ B)(implicit cbf: CanBuildFrom[List[A], B, That]): That
由一个初始值开始,从左向右,进行积累的op操作,这个比较难解释,具体的看例子吧。
val nums = List(1,2,3)
val result = nums.scan(10)(_+_)   // List(10,10+1,10+1+2,10+1+2+3) = List(10,11,12,13)
1
2
13.scanLeft,scanRight
scanLeft: scanLeft[B, That](z: B)(op: (B, A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
scanRight: scanRight[B, That](z: B)(op: (A, B) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
scanLeft: 从左向右进行scan函数的操作,scanRight:从右向左进行scan函数的操作
val nums = List(1.0,2.0,3.0)
val result = nums.scanLeft(2.0)(math.pow)   // List(2.0,pow(2.0,1.0), pow(pow(2.0,1.0),2.0),pow(pow(pow(2.0,1.0),2.0),3.0) = List(2.0,2.0,4.0,64.0)
val result = nums.scanRight(2.0)(math.pow)  // List(2.0,pow(3.0,2.0), pow(2.0,pow(3.0,2.0)), pow(1.0,pow(2.0,pow(3.0,2.0))) = List(1.0,512.0,9.0,2.0)
1
2
3
14.take,takeRight,takeWhile
take : takeRight(n: Int): List[A] 提取列表的前n个元素 takeRight: takeRight(n: Int): List[A] 提取列表的最后n个元素 takeWhile: takeWhile(p: (A) ⇒ Boolean): List[A] 从左向右提取列表的元素,直到条件p不成立
val nums = List(1,1,1,1,4,4,4,4)
val left = nums.take(4)   // List(1,1,1,1)
val right = nums.takeRight(4) // List(4,4,4,4)
val headNums = nums.takeWhile( _ == nums.head)  // List(1,1,1,1)
1
2
3
4
15.drop,dropRight,dropWhile
drop: drop(n: Int): List[A] 丢弃前n个元素,返回剩下的元素 dropRight: dropRight(n: Int): List[A] 丢弃最后n个元素,返回剩下的元素 dropWhile: dropWhile(p: (A) ⇒ Boolean): List[A] 从左向右丢弃元素,直到条件p不成立
val nums = List(1,1,1,1,4,4,4,4)
val left = nums.drop(4)   // List(4,4,4,4)
val right = nums.dropRight(4) // List(1,1,1,1)
val tailNums = nums.dropWhile( _ == nums.head)  // List(4,4,4,4)
1
2
3
4
16.span, splitAt, partition
span : span(p: (A) ⇒ Boolean): (List[A], List[A]) 从左向右应用条件p进行判断,直到条件p不成立,此时将列表分为两个列表
splitAt: splitAt(n: Int): (List[A], List[A]) 将列表分为前n个,与,剩下的部分
partition: partition(p: (A) ⇒ Boolean): (List[A], List[A]) 将列表分为两部分,第一部分为满足条件p的元素,第二部分为不满足条件p的元素
val nums = List(1,1,1,2,3,2,1)
val (prefix,suffix) = nums.span( _ == 1) // prefix = List(1,1,1), suffix = List(2,3,2,1)
val (prefix,suffix) = nums.splitAt(3)  // prefix = List(1,1,1), suffix = List(2,3,2,1)
val (prefix,suffix) = nums.partition( _ == 1) // prefix = List(1,1,1,1), suffix = List(2,3,2)
1
2
3
4
17.padTo
padTo(len: Int, elem: A): List[A]
将列表扩展到指定长度,长度不够的时候,使用elem进行填充,否则不做任何操作。
 val nums = List(1,1,1)
 val padded = nums.padTo(6,2)   // List(1,1,1,2,2,2)
1
2
18.combinations,permutations
combinations: combinations(n: Int): Iterator[List[A]] 取列表中的n个元素进行组合,返回不重复的组合列表,结果一个迭代器
permutations: permutations: Iterator[List[A]] 对列表中的元素进行排列,返回不重得的排列列表,结果是一个迭代器
val nums = List(1,1,3)
val combinations = nums.combinations(2).toList //List(List(1,1),List(1,3))
val permutations = nums.permutations.toList        // List(List(1,1,3),List(1,3,1),List(3,1,1))
1
2
3
19.zip, zipAll, zipWithIndex, unzip,unzip3
zip: zip[B](that: GenIterable[B]): List[(A, B)] 与另外一个列表进行拉链操作,将对应位置的元素组成一个pair,返回的列表长度为两个列表中短的那个
zipAll: zipAll[B](that: collection.Iterable[B], thisElem: A, thatElem: B): List[(A, B)] 与另外一个列表进行拉链操作,将对应位置的元素组成一个pair,若列表长度不一致,自身列表比较短的话使用thisElem进行填充,对方列表较短的话使用thatElem进行填充
zipWithIndex:zipWithIndex: List[(A, Int)] 将列表元素与其索引进行拉链操作,组成一个pair
unzip: unzip[A1, A2](implicit asPair: (A) ⇒ (A1, A2)): (List[A1], List[A2]) 解开拉链操作
unzip3: unzip3[A1, A2, A3](implicit asTriple: (A) ⇒ (A1, A2, A3)): (List[A1], List[A2], List[A3]) 3个元素的解拉链操作
val alphabet = List("A",B","C")
val nums = List(1,2)
val zipped = alphabet zip nums   // List(("A",1),("B",2))
val zippedAll = alphabet.zipAll(nums,"*",-1)   // List(("A",1),("B",2),("C",-1))
val zippedIndex = alphabet.zipWithIndex  // List(("A",0),("B",1),("C",3))
val (list1,list2) = zipped.unzip        // list1 = List("A","B"), list2 = List(1,2)
val (l1,l2,l3) = List((1, "one", '1'),(2, "two", '2'),(3, "three", '3')).unzip3   // l1=List(1,2,3),l2=List("one","two","three"),l3=List('1','2','3')
1
2
3
4
5
6
7
20.slice
slice(from: Int, until: Int): List[A] 提取列表中从位置from到位置until(不含该位置)的元素列表
val nums = List(1,2,3,4,5)
val sliced = nums.slice(2,4)  //List(3,4)
1
2
21.sliding
sliding(size: Int, step: Int): Iterator[List[A]] 将列表按照固定大小size进行分组,步进为step,step默认为1,返回结果为迭代器
val nums = List(1,1,2,2,3,3,4,4)
val groupStep2 = nums.sliding(2,2).toList  //List(List(1,1),List(2,2),List(3,3),List(4,4))
val groupStep1 = nums.sliding(2).toList //List(List(1,1),List(1,2),List(2,2),List(2,3),List(3,3),List(3,4),List(4,4))
1
2
3
22.updated
updated(index: Int, elem: A): List[A] 对列表中的某个元素进行更新操作
val nums = List(1,2,3,3)
val fixed = nums.updated(3,4)  // List(1,2,3,4)

 

import scala.collection.immutable.StringLike
format(args: Any*)使用本地语言环境
formatLocal(l: Locale, args: Any*)使用指定的语言环境
 
 数据类型到字符串的转换
转  换  符 说    明  示    例
%s 字符串类型 "wwx"
%c 字符类型 'w'
%b 布尔类型 true
%d 整数类型(十进制) 99
%x 整数类型(十六进制) FF
%o 整数类型(八进制) 77
%f 浮点类型 99.99
%a 十六进制浮点类型 FF.35AE
%e 指数类型 9.668e+5
%g 通用浮点类型(f和e类型中较短的)  
%h 散列码  
%% 百分比类型 %
%n 换行符  
%tx 日期与时间类型(x代表不同的日期与时间转换符     
搭配转换符的标志
标    志 说    明 示    例 结    果
+ 为正数或者负数添加符号 ("%+d",112) +112
− 左对齐 ("%-5d",112) |112   |
0 数字前面补0 ("%05d", 99) 00099
空格 在整数之前添加指定数量的空格 ("% 5d", 99) |   99|
, 以“,”对数字分组 ("%,f", 9999.99) 9,999.990000
( 使用括号包含负数 ("%(f", -99.99) (99.990000)
# 如果是浮点数则包含小数点,如果是16进制或8进制则添加0x或0 ("%#x", 99)("%#o", 99) 0x630143
<  格式化前一个转换符所描述的参数 ("%f和%<3.2f", 99.45) 99.450000和99.45
$ 被格式化的参数索引 ("%1s", 89,"abc") 89,abc



   %[argument_index$][flags][width][.precision]conversion
argument_index: 可选,表明参数在参数列表中的位置。第一个参数由 "1

引用,第二个参数由


" 引用,依此类推。
flags: 可选,用来控制输出格式
width: 可选,是一个正整数,表示输出的最小长度
precision:可选,用来限定输出字符数,精度
conversion:必须,用来表示如何格式化参数的字符
  
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 scala> "%1$s-%2$s-%3$s".format("spark","scala","ml")res29: String = spark-scala-ml   // 百分比scala> "%d%%".format(86)res31: String = 86%   // 精度为3,长度为8scala>  "%8.3f".format(11.56789)res36: String = "  11.568"  scala>   "%8.3f".format(11.56789).length()res37: Int = 8    // 精度为3,长度为8,不足的用0填补scala> "%08.3f".format(11.56789)res38: String = 0011.568    // 长度为9,不足的用0填补scala>  "%09d".format(11)res23: String = 000000011    scala> "%.2f".format(11.23456)res25: String = 11.23     scala> val wx=36.6789wx: Double = 36.6789   scala> f"${wx}%.2f"res39: String = 36.68 //###############scala> val name="scala"name: String = scala   scala> s"spark,$name"res40: String = spark,scala   scala> "spark,$name"res41: String = spark,$name   scala> s"spark\n$name"res42: String =sparkscala   scala> "spark\n$name"res43: String =spark$name   scala> raw"spark\n$name"res44: String = spark\nscala
 

  

Scala中的String.split函数
http://www.cnblogs.com/davidhaslanda/p/4050471.html  http://swiftlet.net/archives/709

本篇博文将详细解释scala中String.split的参数及用法。
因为scala中的String复用了Java的String,因此这也是Java中String.split的用法。
split函数主要有两种参数形式:
def split(arg0: String): Array[String]
def split(arg0: String, arg1: Int): Array[String]
我们可以将第一种参数形式看作是默认arg1=0的第二种形式,即调用split(StrToSplit)等同于调用了split(StrToSplit, 0)。因此,我将主要介绍第二种参数形式。第二种参数形式中每个参数的意义如下:
arg0: String 是一个正则表达式,代表分割的边界。这个正则表达式成功匹配一次,split的结果中就会加入一个新的子串。子串包含上次匹配后(如果没有上次匹配就是被分割字符串的起始位置)到这次匹配前的所有字符。最后,split函数会将最后一次匹配后剩余的字串作为最后一个子串加入到结果中。
arg1: Int 是对分割后子串的个数的限定。理解这个参数才能正确的运用split函数。
  当arg1大于0时,它限制arg0最多成功匹配arg1-1次,也就是说字符串最多被分成arg1个子串。此时split会保留分割出的空字符串(当两个arg0连续匹配或者arg0在头尾匹配,会产生空字符串),直到达到匹配上限。比如:

 1 scala> "a-b-c".split("-", 2)
 2 res38: Array[String] = Array(a, b-c)
 3 
 4 scala> "a-b-c".split("-", 4)
 5 res39: Array[String] = Array(a, b, c)
 6 
 7 scala> "-a-b-c--".split("-", 3)
 8 res40: Array[String] = Array("", a, b-c--)
 9 
10 scala> "-a-b-c--".split("-", 6)
11 res41: Array[String] = Array("", a, b, c, "", "")
12 
13 scala> "-a-b-c--".split("-", 5)
14 res42: Array[String] = Array("", a, b, c, -)
15 
16 scala> "-a-b-c--".split("-", 8)
17 res43: Array[String] = Array("", a, b, c, "", "")

  当arg1等于0时,split函数会尽可能多的匹配arg0,但不再保留处于末尾位置的空字符串(这里的一个特殊情况是,当被分割字符串是一个空字符串时,分割结果仍是一个空字符串组成的数组)。比如:

 1 scala> "a-b-c".split("-", 0)
 2 res48: Array[String] = Array(a, b, c)
 3 
 4 scala> "a-b-c---".split("-", 0)
 5 res49: Array[String] = Array(a, b, c)
 6 
 7 scala> "-a--b--c---".split("-", 0)
 8 res50: Array[String] = Array("", a, "", b, "", c)
 9 
10 scala> "".split("-", 0)
11 res51: Array[String] = Array("")

  当arg1小于0时,split函数会尽可能多的匹配arg0,并且保留末尾的空字符串。比如:
1 scala> "a-b-c".split("-", -1)
2 res52: Array[String] = Array(a, b, c)
3 
4 scala> "-a--b--c-".split("-", -1)
5 res53: Array[String] = Array("", a, "", b, "", c, "")

在java.lang包中有String.split()方法的原型是:
public String[] split(String regex, int limit)
split函数是用于使用特定的切割符(regex)来分隔字符串成一个字符串数组,函数返回是一个数组。在其中每个出现regex的位置都要进行分解。
需要注意是有以下几点:
(1)regex是可选项。字符串或正则表达式对象,它标识了分隔字符串时使用的是一个还是多个字符。如果忽略该选项,返回包含整个字符串的单一元素数组。
(2)limit也是可选项。该值用来限制返回数组中的元素个数。
(3)要注意转义字符:“.”和“|”都是转义字符,必须得加"\\"。同理:*和+也是如此的。
如果用“.”作为分隔的话,必须是如下写法:
String.split("\\."),这样才能正确的分隔开,不能用String.split(".");
如果用“|”作为分隔的话,必须是如下写法:
String.split("\\|"),这样才能正确的分隔开,不能用String.split("|");
(4)如果在一个字符串中有多个分隔符,可以用“|”作为连字符,比如:“acountId=? and act_id =? or extra=?”,把三个都分隔出来,可以用
String.split("and|or");
(5)split函数结果与regex密切相关,常见的几种情况如下所示:
1234567891011121314151617181920212223242526272829303132333435 public class SplitTest {public static void main(String[] args) {String str1 = "a-b"; String str2 = "a-b-";String str3 = "-a-b";String str4 = "-a-b-";String str5 = "a";String str6 = "-";String str7 = "--";String str8 = "";split(str1);split(str2);split(str3);split(str4);split(str5);split(str6);split(str7);split(str8);}public static void split(String demo){String[] array = demo.split("-");int len = array.length;System.out.print("\"" + demo + "\" 分割后的长度为:" + len);if(len >= 0){System.out.print(",分割后的结果为:");for(int i=0; i<len; i++){System.out.print(" \""+array[i]+"\"");} }System.out.println();}}
运行结果为:
"a-b" 分割后的长度为:2,分割后的结果为: "a" "b"
"a-b-" 分割后的长度为:2,分割后的结果为: "a" "b"
"-a-b" 分割后的长度为:3,分割后的结果为: "" "a" "b"
"-a-b-" 分割后的长度为:3,分割后的结果为: "" "a" "b"
"a" 分割后的长度为:1,分割后的结果为: "a"
"-" 分割后的长度为:0,分割后的结果为:
"--" 分割后的长度为:0,分割后的结果为:
"" 分割后的长度为:1,分割后的结果为: ""
由此可以得出来:
当字符串只包含分隔符时,返回数组没有元素;
当字符串不包含分隔符时,返回数组只包含一个元素(该字符串本身);
字符串最尾部出现的分隔符可以看成不存在,不影响字符串的分隔;
字符串最前端出现的分隔符将分隔出一个空字符串以及剩下的部分的正常分隔;

  

Scala基础之注解(annotation
在学习Scala的过程中,总会碰到一些注解:
// Predef.scala
@inline def implicitly[T](implicit e: T) = e

@deprecated("Use `sys.error(message)` instead", "2.9.0")
  def error(message: String): Nothing = sys.error(message)

// Spark RDD.scala
abstract class RDD[T: ClassTag](
    @transient private var sc: SparkContext,
    ....)

一般来说,注解可以作用于vals, vars, defs, classes, objects, traits 和 types甚至是表达式的后面。
import scala.reflect.runtime.{ universe => ju }

def meth[A: ju.TypeTag](xs: List[A]) = xs match {
 case strList: List[String @ unchecked] 
    if ju.typeTag[A].tpe =:= ju.typeOf[String] => "list of Strings"
 case barList: List[Bar @ unchecked] 
    if ju.typeTag[A].tpe =:= ju.typeOf[Bar] => "list of Bar"
}

我们知道List[T]在运行时会被类型擦除,相当于变成List。@unchecked 告诉compiler不要去检查这个,否则就会报下面的warning。
non-variable type argument String in type pattern List[String] is unchecked 
since it is eliminated by erasure

另外, 注解实际上也是普通的类只不过编译器对其进行特殊的支持,所以我们才能那样书写。比如说,我们常见的序列号的注解。
class SerialVersionUID(uid: Long) extends scala.annotation.StaticAnnotation

@SerialVersionUID(13567156)
class B {}

@deprecated("use newShinyMethod() instead", "since 2.3")
def bigMistake() =  //...
bigMistake

scalac -deprecation Deprecation2.scala

warning: method bigMistake in class B is deprecated: use newShinyMethod() instead
  println(bigMistake)
          ^
one warning found

@volatile
实际上这个注解或是关键字,大多用于被并发访问的共享变量。在JVM内存模型中happens-before规则有一条就是volatile变量法则(有兴趣可以阅读Java并发编程实践 第16章Java内存模型),对于volatile变量,同一变量的写操作总是先于读操作。
class Person(@volatile var name: String) {
  def set(changedName: String) {
    name = changedName
  }
}

@tailrec
这个注解是与尾递归优化有关的。
// 阶乘
def factorial(n: Int) = {
    @tailrec def go(n: Int, acc: Int): Int = {
        if (n <=0) acc
        else go(n-1, acc * n) 
        // 尾递归,顾名思义方法的调用也必须出现在返回值的位置
    }
    go(n, 1)
}

@Unchecked
一般是在模式匹配的时候用到的,告诉编译器有些地方不用"检查"了。如前所述,List[String @ unchecked]。
@transient
这个注解一般用于序列化的时候,标识某个字段不用被序列化。
import java.io.{ FileOutputStream, FileInputStream }
import java.io.{ ObjectOutputStream, ObjectInputStream }

class Hippie(val name: String, @transient val age: Int) extends Serializable

object Serialization {

    val fos = new FileOutputStream("hippie.txt")
    val oos = new ObjectOutputStream(fos)

    val p1 = new Hippie("zml", 34)
    oos.writeObject(p1)
    oos.close()
}

object Deserialization extends App {

    val fis = new FileInputStream("hippie.txt") 
    val ois = new ObjectInputStream(fis)

    val hippy = ois.readObject.asInstanceOf[Hippie]
    println(hippy.name)
    println(hippy.age)
    ois.close()
}

运行之后的结果
zml
0

由于age被标记为@transient,在反序列化的时候,就获取不到原始值了所以被赋值为默认值。
@inline
这个注解,在Scala.Predef中见到过一次。官方文档中的解释跟没说一样, 倒是StackOverflow上一个的答案,个人觉得比较能说明作用。
Instead of a function call resulting in parameters being placed on the stack and an invoke operation occurring, the definition of the function is copied at compile time to where the invocation was made, saving the invocation overhead at runtime.
大致的意思就是@inline能够避免方法的参数被放到栈上,以及"显示的调用"。因为编译器在编译的时候会将整个方法复制到它被调用的地方。
http://stackoverflow.com/questions/4593710/when-should-i-and-should-i-not-use-scalas-inline-annotation
 

  

转载于:https://www.cnblogs.com/Frank99/p/8295641.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值