Scala的常用小技巧
1."RichString.java".stripSuffix(".java") == "RichString"
"http://my.url.com".stripPrefix("http://") == "my.url.com"
2.Scala中,访问修饰符可以通过使用限定词强调。格式为:private[x] 或 protected[x],这里的x指代某个所属的包、类或单例对象。如果写成private[x],读作"这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,对其它所有类都是private。这种技巧在横跨了若干包的大型项目中非常有用,它允许你定义一些在你项目的若干子包中可见但对于项目外部的客户却始终不可见的东西。
3.保护(Protected)成员
在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。因为它只允许保护成员在定义了该成员的的类的子类中被访问。而在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里的其他类也可以进行访问。
公共(Public)成员
Scala中,如果没有指定任何的修饰符,则默认为 public。这样的成员在任何地方都可以被访问。
私有(Private)成员
用private关键字修饰,带有此标记的成员仅在包含了成员定义的类或对象内部可见,同样的规则还适用内部类。
4.@transient注解将字段标记为瞬态的,瞬态的字段不会被序列化,这对于需要临时保存的缓存数据,或者是能够很容易地重新计算的数据而言是合理的。
5.isAssignableFrom 是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的超类或接口。 通常调用格式是:Class1.isAssignableFrom (Class2)
而instanceof 是用来判断一个对象实例是否是一个类或接口的或其子类子接口的实例。
6.编译器可以自动插入 implicit 的最后一个用法是隐含参数。 比如编译器在需要是可以把 someCall(a)修改为 someCall(a)(b)或者 new someClass(a) 修改为 new SomeClass(a)(b),也就是说编译器在需要的时候会自动补充缺少的参数来完成方法的调用。其中(b)为一组参数,而不仅仅只最后一个参数。这里更详细
7.import java.util.concurrent.atomic.AtomicInteger
new AtomicInteger(0).getAndIncrement()获取自增的id
8.class A {def method1: A = this } class B extends A (def method2: B = this} val b = new B
如果调用b.method2.method1是可以的,但是如果想调用b.method1.method2就不行了。因为method1返回的是A类型的。
当然你可以在B中覆盖method1,以返回正确类型。但是scala中解决这个问题的办法就是this.type
class A { def method1: this.type = this } class B extends A { def method2: this.type = this } val b = new B
如果调用b.method1则编译器会知道method1返回的是B类型的。
9.ConcurrentHashMap是线程安全的,适合并发操作。
10.在Scala中并没有枚举类型,但在标准类库中提供了Enumeration类来产出枚举。扩展Enumeration类后,调用Value方法来初始化枚举中的可能值。
内部类Value实际上是一个抽象类,真正创建的是Val。因为实际上是Val,所以可以为Value传入id和name
如果不指定,id就是在前一个枚举值id上加一,name则是字段名,链接
11.scala product2,product1
12.reflect.classTag[V].runtimeClass.getName反射获取类名
13.Scala中的Either的两个子类(Left,Right)的简单用法
要求(require)和断言(assert)都起到可执行文档的作用。两者都在类型系统不能表达所要求的不变量(invariants)的场景里有用。 assert用于代码假设的不变量(invariants) (内部或外部的) 例如:(译注,不变量 invariant 是指类型不可变,即不支持协变或逆变的类型变量)
val stream = getClass.getResourceAsStream("someclassdata")
assert(stream != null)
相反,require用于表达API契约:
def fib(n: Int) = { require(n > 0) ... }
16.Scala NonFatal
17.Just use Java's java.lang.ThreadLocal class to store the variables.
val tl = new ThreadLocal[String]
tl.set("fish")
tl.get // "fish"
18.Spark 闭包中ClosureCleaner操作
19.AtomicBoolean 在这个Boolean值的变化的时候不允许在之间插入,保持操作的原子性。这个方法主要两个作用
1. 比较AtomicBoolean和expect的值,如果一致,执行方法内的语句。其实就是一个if语句
2. 把AtomicBoolean的值设成update 比较最要的是这两件事是一气呵成的,这连个动作之间不会被打断,任何内部或者外部的语句都不可能在两个动作之间运行。为多线程的控制提供了解决的方案
20.implicit ord: Ordering[T] = null
case class Person(name:String,tel:String) extends Ordered[Person] {
def compare(that: Person): Int = this.name compare that.name
}
val ps5 = Array(Person("peter","138"),Person("peter","55"),Person("john","138"))
sc.parallelize(ps5).distinct.collect。详细解释
21.
Scala中的=>符号可以看做是创建函数实例的语法糖。例如:A => T,A,B => T表示一个函数的输入参数类型是“A”,“A,B”,返回值类型是T。请看下面这个实例:
val f: Int => String = myInt => "The value of myInt is: " + myInt.toString()
f: Int => String = <function1>
println(f(3))
The value of myInt is: 3
上面例子定义函数f:输入参数是整数类型,返回值是字符串。
另外,() => T表示函数输入参数为空,而A => Unit则表示函数没有返回值
22.
scala>val input = List(3, 5, 7, 11)
scala> input.scanLeft(0)(_+_)
res0: List[Int] = List(0, 3, 8, 15, 26)
23.scala flatten
flatten可以把嵌套的结构展开.
scala> List(List(1,2),List(3,4)).flatten
res0: List[Int] = List(1, 2, 3, 4)
24。asScala
25.AtomicReference
java并发库提供了很多原子类来支持并发访问的数据安全性,除了常用的
AtomicInteger、AtomicBoolean、AtomicLong 外还有
AtomicReference 用以支持对象的原子操作:AtomicReference<V> 可以封装引用一个V实例,
通过
public final boolean compareAndSet(V expect, V update)
可以支持并发访问,set的时候进行对比判断,如果当前值和操作之前一样则返回false,否则表示数据没有 变化,例如下面的代码
使用 AtomicReference 实现了并发计数。这里
26.
看scala的源码的话很发现很多源码开头都有一句:self => 这句相当于给this起了一个别名为self。
self不是关键字,可以用除了this外的任何名字命名(除关键字)。就上面的代码,在Self 内部,可以用this指代当前对象,也可以用self指代,两者是等价的。这里
class Self { self => //代表this指针 ,也就是说 self 就 this的别名 val tmp = "scala" def foo = self.tmp + this.tmp }
27
定长数组:指长度不可变的数组Array。
第一种方式:
先声明一个数组,后初始化该数组:
scala> val array = new Array[Double](5)
array: Array[Double] = Array(0.0, 0.0, 0.0, 0.0, 0.0)
赋值方式:array(index) = value
第二种方式:
scala> val array = Array(1, 2, 3, 4, 5)
array: Array[Int] = Array(1, 2, 3, 4, 5)
第三种方式,Array.fill(length)(value):
scala> val array = Array.fill(5)(3.5)
array: Array[Double] = Array(3.5, 3.5, 3.5, 3.5, 3.5)
如果fill第二个参数只写一个值的话,那么该数组的所有元素都是该值,但是如果第二个参数是一个iterator或者random,那么数组就会被赋值为它们的值。
scala> val array = Array.fill(2)(math.random)
array: Array[Double] = Array(0.2810736748034083, 0.7261142068882558)
第四种方式,ofDim[T](length):
scala> val array = Array.ofDim[Double](5)
array: Array[Double] = Array(0.0, 0.0, 0.0, 0.0, 0.0)
赋值方式:array(index) = value
28
Either解决返回值不确定问题(两个值返回一个)
程序设计中经常会有这样的需求,一个函数(或方法)在传入不同参数时会返回不同的值。返回值是两个不相关的类型,分别为: Left 和 Right 。惯例中我们一般认为 Left 包含错误或无效值, Right包含正确或有效值。除了使用match case方式来获取数据,我们还可以分别使用 .right.get 和 .left.get 方法,当然你需要使用 .isRight 或 .isLeft 先判断一下。Left或Right类型也有 filter, flatMap, foreach, get, getOrElse, map 方法,它们还有toOption, toSeq 方法,分别返回一个Option或Seq 。
29
Seq 特质有两个子特质 LinearSeq 和 IndexedSeq。他们并没有增加任何新的操作,只是为Seq中的一些方法提供了更高效的实现: LinearSeq (线性序列)提供了高效的 head 和 tail 方法,而 IndexedSeq(索引序列) 提供了高效的 apply、length 和 update 方法(当集合可变时)。常用的线性序列类的集合有 scala.collection.immutable.List 和 scala.collection.immutable.Stream。常用的索引序列类的集合有 scala.Array 以及 scala.collection.mutable.ArrayBuffer。