Google Guava 工具类与 Kotlin 语言的设计
Guava工具类是什么
Guava is a suite of core and expanded libraries that include utility classes, google's collections, io classes, and much much more.
Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。所有这些工具每天都在被Google的工程师应用在产品服务中。
在使用 Kotlin 的过程中,我们发现很多思想都来自于现有 Java 生态库。例如:Guava,Lombok,common-lang等等。
本文主要讲解 Guava 中的工具类的使用与 Kotlin 中同样的问题的解决方式。
guava功能介绍
guava 源码包说明:
com.google.common.annotations:普通注解类型。
com.google.common.base:基本工具类库和接口。
com.google.common.cache:缓存工具包,非常简单易用且功能强大的JVM内缓存。
com.google.common.collect:带泛型的集合接口扩展和实现,以及工具类,这里你会发现很多好玩的集合。
com.google.common.eventbus:发布订阅风格的事件总线。
com.google.common.hash:哈希工具包。
com.google.common.io:I/O工具包。
com.google.common.math:原始算术类型和超大数的运算工具包。
com.google.common.net:网络工具包。
com.google.common.primitives:八种原始类型和无符号类型的静态工具包。
com.google.common.reflect:反射工具包。
com.google.common.util.concurrent:多线程工具包。
1、基本工具类:让使用Java语言更令人愉悦。
使用和避免 null:null 有语言歧义,会产生令人费解的错误,反正他总是让人不爽。很多 Guava的工具类在遇到null时会直接拒绝或出错,而不是默默地接受他们。
前提条件:更容易的对你的方法进行前提条件的测试。
常见的对象方法:简化了Object常用方法的实现, 如 hashCode() 和 toString()。
排序:Guava 强大的 “fluent Comparator”比较器, 提供多关键字排序。
Throwable类:简化了异常检查和错误传播。
2、集合类:集合类库是 Guava 对 JDK 集合类的扩展, 这是 Guava 项目最完善和为人所知的部分。
Immutable collections(不变的集合):防御性编程, 不可修改的集合,并且提高了效率。
New collection types(新集合类型):JDK collections 没有的一些集合类型,主要有:multisets,multimaps,tables, bidirectional maps等等
Powerful collection utilities(强大的集合工具类):java.util.Collections 中未包含的常用操作工具类
Extension utilities(扩展工具类): 给 Collection 对象添加一个装饰器? 实现迭代器? 我们可以更容易使用这些方法。
3、缓存: 本地缓存,可以很方便的操作缓存对象,并且支持各种缓存失效行为模式。
4、Functional idioms(函数式): 简洁, Guava实现了Java的函数式编程,可以显著简化代码。
5、Concurrency(并发):强大,简单的抽象,让我们更容易实现简单正确的并发性代码。
ListenableFuture(可监听的Future): Futures,用于异步完成的回调。
Service: 控制事件的启动和关闭,为你管理复杂的状态逻辑。
6、Strings: 一个非常非常有用的字符串工具类: 提供 splitting,joining, padding 等操作。
7、Primitives: 扩展 JDK 中未提供的对原生类型(如int、char等)的操作, 包括某些类型的无符号的变量。
8、Ranges: Guava 一个强大的 API,提供 Comparable 类型的范围处理, 包括连续和离散的情况。
9、I/O: 简化 I/O 操作, 特别是对 I/O 流和文件的操作, for Java 5 and 6.
10、Hashing: 提供比 Object.hashCode() 更复杂的 hash 方法, 提供 Bloom filters.
11、EventBus: 基于发布-订阅模式的组件通信,但是不需要明确地注册在委托对象中。
12、Math: 优化的 math 工具类,经过完整测试。
13、Reflection: Guava 的 Java 反射机制工具类。
Kotlin简介
Kotlin 是一种兼容Java的语言。比Java更安全,能够静态检测常见的陷阱。如:引用空指针。 比Java更简洁,通过支持variable type inference,higher-order functions (closures),extension functions,mixins and first-class delegation等实现。 比Scala语言更加简单。
Try Kotlin on line: https://play.kotlinlang.org/byExample/overview
Concise
Drastically reduce the amount of boilerplate code.
Create a POJO with getters, setters, equals(), hashCode(), toString() and copy() in a single line:
data class Customer(val name: String, val email: String, val company: String)
Or filter a list using a lambda expression:
val positiveNumbers = list.filter { it > 0 }
Want a singleton? Create an object:
object ThisIsASingleton {
val companyName: String = "JetBrains"
}
Safe
Avoid entire classes of errors such as null pointer exceptions.
Get rid of those pesky NullPointerExceptions, you know, The Billion Dollar Mistake
var output: String
output = null // Compilation error
Kotlin protects you from mistakenly operating on nullable types
val name: String? = null // Nullable type
println(name.length()) // Compilation error
And if you check a type is right, the compiler will auto-cast it for you
fun calculateTotal(obj: Any) {
if (obj is Invoice)
obj.calculateTotal()
}
Interoperable
Leverage existing libraries for the JVM, Android, and the browser.
Use any existing library on the JVM, as there’s 100% compatibility, including SAM support.
import io.reactivex.Flowable
import io.reactivex.schedulers.Schedulers
Flowable
.fromCallable {
Thread.sleep(1000) // imitate expensive computation
"Done"
}
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.single())
.subscribe(::println, Throwable::printStackTrace)
Target either the JVM or JavaScript. Write code in Kotlin and decide where you want to deploy to
import kotlin.browser.window
fun onl oad() {
window.document.body!!.innerHTML += "<br/>Hello, Kotlin!"
}
Tool-friendly
Choose any Java IDE or build from the command line.
A language needs tooling and at JetBrains, it's what we do best!
可空类型与包装类Optional
用 guava 的Optional类:
package com.light.sword.guava
import com.google.common.base.Optional
/**
* Optional用于包含非空对象的不可变对象。Optional对象,用于不存在值表示null。这个类有各种实用的方法,以方便代码来处理为可用或不可用,而不是检查null值。
用 Kotlin 的可空类型:
*/
fun main() {
var a: Int? = null
var b: Int? = null
var s = sum(Optional.fromNullable(a), Optional.fromNullable(b))
println("S=${s}")
a = 1
b = null
s = sum(Optional.fromNullable(a), Optional.fromNullable(b))
println("S=${s}")
a = 1
b = 1
s = sum(Optional.fromNullable(a), Optional.fromNullable(b))
println("S=${s}")
}
fun sum(a: Optional<Int>, b: Optional<Int>): Int {
println("a.isPresent:${a.isPresent}")
println("b.isPresent:${b.isPresent}")
val aa = a.or(0)
val bb = b.or(0)
return aa + bb
}
fun sumK(a: Int?, b: Int?): Int {
return (a ?: 0) + (b ?: 0)
}
fun main() {
// Kotlin
a = null
b = null
println(sumK(a, b))
a = null
b = 1
println(sumK(a, b))
a = 1
b = 1
println(sumK(a, b))
}
fun sumK(a: Int?, b: Int?): Int {
return (a ?: 0) + (b ?: 0)
}
Java 8 中引入了 Optional 类。
字符串工具类
package com.light.sword.guava
import com.google.common.base.Joiner
import com.google.common.base.Splitter
fun main() {
val list = listOf("A","B","C")
val a = Joiner.on("-").join(list)
println(a) // A-B-C
val b = Splitter.on("-").split(a)
println(b) // [A, B, C]
// Kotlin
val c = list.joinToString("-")
val d = c.split("-")
println(c) // A-B-C
println(d) // [A, B, C]
}
Kotlin中的扩展函数特性,使得我们的代码写起来更加简洁优雅。
集合工具类
Lists
package com.light.sword.guava
import com.google.common.collect.ImmutableList
import com.google.common.collect.Lists
fun main() {
// Guava
val list1 = Lists.newArrayList("a", "b", "c")
val list2 = Lists.newArrayList("c", "d", "e")
// Kotlin
val list11 = listOf("a", "b", "c")
val list22 = listOf("c", "d", "e")
val list3 = ImmutableList.builder<Int>().add(1, 2, 3, 4, 5, 6, 7)
println(list3)
val list4 = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7)
val a = Lists.partition(list4, 2)
println(a) // [[1, 2], [3, 4], [5, 6], [7]]
val list5 = listOf(1, 2, 3, 4, 5, 6, 7)
val b = list5.partition {
it < 5
}
println(b) // ([1, 2, 3, 4], [5, 6, 7])
}
Sets
package com.light.sword.guava
import com.google.common.collect.Sets
fun main() {
run {
// Guava
val s1 = Sets.newHashSet("a", "b", "c", "d")
val s2 = Sets.newHashSet("d", "e", "f")
val s3 = Sets.union(s1, s2)
val s4 = Sets.intersection(s1, s2)
println(s3) // [a, b, c, d, e, f]
println(s4) // [d]
}
run {
// Kotlin
val s1 = setOf("a", "b", "c", "d")
val s2 = setOf("d", "e", "f")
val s3 = s1.union(s2)
val s4 = s1.intersect(s2)
println(s3) // [a, b, c, d, e, f]
println(s4) // [d]
}
}
文件 IO
package com.light.sword.guava
import com.google.common.io.Files
import java.io.File
import java.nio.charset.Charset
val file = "/Users/jack/githubcode/kotlin-demo/src/main/kotlin/com/light/sword/guava/test.data"
fun main() {
// Guava
run {
val lines = Files.readLines(File(file), Charset.forName("UTF-8"))
for(line in lines){
println(line)
}
}
// Kotlin
run {
val lines = File(file).readLines(Charsets.UTF_8)
for(line in lines){
println(line)
}
}
}
函数式编程
Guava提供了很多工具方法,以便用Function或Predicate操作集合。这些方法通常可以在集合工具类找到,如Iterables,Lists,Sets,Maps,Multimaps等。
映射 map
Guava 的 Lists.transform 方法:
package com.light.sword.guava
import com.google.common.base.Function
import com.google.common.collect.ImmutableList
import com.google.common.collect.Lists
fun main() {
run {
// Guava
val list1 = Lists.newArrayList("a", "b", "c")
val list2 = Lists.newArrayList("c", "d", "e")
val list3 = ImmutableList.builder<Int>().add(1, 2, 3, 4, 5, 6, 7)
println(list3)
val list4 = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7)
val a = Lists.partition(list4, 2)
println(a) // [[1, 2], [3, 4], [5, 6], [7]]
val list5 = Lists.transform(list4, object : Function<Int, Int> {
override fun apply(e: Int?): Int? {
return e?.times(e)
}
})
println(list5) // [1, 4, 9, 16, 25, 36, 49]
}
}
Kotlin 直接使用 map 函数:
// Kotlin
run {
val list1 = listOf("a", "b", "c")
val list2 = listOf("c", "d", "e")
val list3 = listOf(1, 2, 3, 4, 5, 6, 7)
val b = list3.partition {
it < 5
}
println(b) // ([1, 2, 3, 4], [5, 6, 7])
val list4 = list3.map { e -> e * e }
println(list4) // [1, 4, 9, 16, 25, 36, 49]
}
复合函数
package com.light.sword.guava
import com.google.common.base.Function
import com.google.common.base.Functions
/** Guava Function
* Guava提供了很多工具方法,以便用Function或Predicate操作集合。这些方法通常可以在集合工具类找到,如Iterables,Lists,Sets,Maps,Multimaps等。
*/
interface Function1<A, B> : Function<A, B>
interface Function2<B, C> : Function<B, C>
fun main() {
// Guava
run {
val f1 = object : Function1<String, Int> {
override fun apply(x: String?): Int? {
return x?.length
}
}
val f2 = object : Function2<Int, Boolean> {
override fun apply(x: Int?): Boolean? {
if (x != null) {
return x % 2 == 0
} else {
return false
}
}
}
val f = Functions.compose(f2, f1)
val strings = listOf("a", "ab", "abc", "abcd")
val result = mutableListOf<String>()
for (s in strings) {
val p = f.apply(s)
if (p != null) {
if (p) {
result.add(s)
}
}
}
println(result) // [ab, abcd]
}
// Kotlin
run {
val f1: (String) -> Int = { x -> x.length }
val f2: (Int) -> Boolean = { x -> x % 2 == 0 }
val f: (String) -> Boolean = { x -> f2(f1(x)) }
val strings = listOf("a", "ab", "abc", "abcd")
val result = strings.filter(f)
println(result) // [ab, abcd]
}
}
可以看到,Kotlin 语言的函数式代码写起来就像数学公式一样简洁优雅。
Higher-Order Functions
A higher-order function is a function that takes another function as parameter and/or returns a function.
Taking Functions as Parameters
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}
fun sum(x: Int, y: Int) = x + y
fun main() {
val sumResult = calculate(4, 5, ::sum)
val mulResult = calculate(4, 5) { a, b -> a * b }
println("sumResult sumResult, mulResult mulResult")
}
参考资料
https://github.com/google/guava/wiki
https://play.kotlinlang.org/byExample/overview