JGSK - 35.集合的函数式编程
Java
从 Java 1.8 开始 Java 也支持了集合的函数式编程。
Stream
Stream 是 Java 1.8 引入的类,主要用于进行 并行集合的流式操作。
集合可以使用调用 stream()
方法或者使用 Stream
类的静态方法来转换为 Stream
对象。
从 Java 1.8 开始 Java 也支持了集合的函数式编程。
Stream 是 Java 1.8 引入的类,主要用于进行 并行集合的流式操作。
集合可以使用调用 stream()
方法或者使用 Stream
类的静态方法来转换为 Stream
对象。
Memoized 即缓存功能。Groovy 可以对方法和闭包的结果进行缓存,从而再下次传入同样的参数时直接返回缓存的结果。对于那些耗时很久的计算过程来说这一点可以节约不少时间。
所谓的函数字面量指的将函数本身赋值给一个变量。在 Groovy 中,函数字面量是通过闭包来实现的。通过函数字面量,函数本身可以像普通变量一样进行各种操作。
完整的 Kotlin 方法定义语法为
完整的 Scala 方法定义语法为
完整的 Groovy 方法定义语法为
完整的 Java 定义语法为
Lazy变量也就是常说的惰性加载,即变量在初始化时没有进行计算操作,而是延迟到了该变量第一次被使用的时候。在函数式编程中,惰性加载被广泛使用,尤其是对于一些长度未知的列表,如果使用普通方式,恐怕加载时系统就会被拖慢速度甚至于内存溢出。
我们都知道 Android 原生应用基本都是使用 Java 开发的,但是实际上 Groovy 也是运行在 JVM 上的,所以也可以用于开发 Android 应用程序,只是需要做一些额外的准备工作。
注解主要用于标示元数据。Java 中声明一个注解使用符号 @interface
。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Bean {
String name();
}
以上创建了一个名为 Bean
的注解。该注解上使用了标示此自定义注解的两个 JVM 的内置注解:Retention
和 Target
。
Java 中执行 Shell 命令主要依靠 Runtime 和 Process 两个类。
测试过程通常有 N 种分类,一般常说的有那么几种: UT,IT(CT),ST,MT。
UT 单元测试属于白盒测试,是测试中的最小单元,一般用于测试单独的方法,检测方法的正确性。
线程主要用于执行并发任务,提高 CPU 的运行效率。在各种参考中都有线程相关的各种概念,在这里就补多废话了。在Java 中线程相关的概念主要有两个: Thread 和 Runnable。
Groovy,Scala 和 Kotlin 都是 JVM 上的语言,在设计之初就考虑到了与 Java 的兼容性,所以这三门语言几乎都能无缝调用 Java 代码,因此也能很简单地实用现在众多成熟的 Java 类库。而 Java 调用这三门语言也不是太麻烦,所以可以根据实用场景在这四门语言中进行便捷地切换。
Java 中的 IO 操作主要是对各种流进行操作。Java 中流可以分为字节流(InputStream),字符流(FileReader),转换流(InputStreamReader)等。这种设计方式一直都被认为是非常优秀的。 由于流的种类繁多,使用起来有固定的套路,并不复杂,所以本章只是简单介绍一下。
基本概念同 Java。
基本概念同 Java。
Groovy 中使用的就是 Java 的泛型,所以参考 Java 就行了。但是要注意的是由于 Groovy 的动态特性,所以有些Java 会报的编译错误在 Groovy 中只有运行时才会发现。
泛型是 Java 1.5才引进的特性。泛型使类型参数化变得可能。在声明类或接口时,可以使用自定义的占位符来表示类型,在运行时由传入的具体类型进行替换。泛型的引入让集合变得更加好用,使很多错误在编译时就能被发现,也省去了一些强制转换的麻烦。
JSON 是一种键值对形式的轻量级的数据交换格式,除了大量用于 Restful 请求外,其二进制形式的 BSON 也被用于作为 NO SQL 的数据存储格式。相比较 XML 而言,JSON 更为简单,灵活。
XML 也可以用于数据交换,最为有名的就是 SOAP 协议。相比较 JSON 而言由于需要有开始和结束标记所以 XML 略显啰嗦。不过相比较 JSON 的无模式形式,XML 可以通过指定 DTD 而为其中定义的数据指定一定的格式,所以可以作为配置文件,在使用 IDE 进行编辑时也能拥有代码提示功能。
正则表达式功能非常强大,但是写好一个满足各种情况的合格的正则表达式却不是件简单的事。
本章节不会介绍任何正则表达式的语法,而是介绍四种语言中正则表达式最基本的三种用法:匹配,查找和替换的实现方式。
基于 Gradle 进行构建的程序离不开 Gradle 插件。有时现存的插件没有办法满足我们的需求,这时就需要我们自定义 Gradle 插件。本文就是从头编写 Gradle 插件的一个简单例子。
使用的开发环境为 IDEA,开发语言为 Groovy,尽管也可以用 Java 来开发 Gradle 插件,但是开发时配置繁琐且效率低,所以还是推荐使用 Groovy。
枚举是种特殊的类,主要用于构建一组特定的值。在 Java 中通常用于限定某个属性的值只能在一定范围内,在某些场合可以被静态常量代替,但是枚举可以有自己的属性也可以有自己的方法,而静态常量无法做到,且静态常量只能限定类型,不能限定值本身。当然在效率上,枚举并不如静态常量。
Trait 中文名为特质。特质是字段和行为的集合,可以拥有抽象成员也可以拥有普通成员。特质可以看做是一种特殊形式的接口,但是特质主要用于实现多重继承。
多重继承虽然便利,但是会带来 Diamond Problem,即 B 和 C 都实现了 A 的某个方法,而 D 继承了 B 和 C 但是没有重写该方法,此时调用 D 持有的该方法到底来自于 B 还是 C。因此过分使用特质会让程序本身难以理解。
package
来声明一个包。.
作为路径分隔符,且包路径必须与源文件路径相同。package a.b;
class B {}
Java 中异常是种特殊对象,可以分为检查异常和非检查异常,所有 RuntimeException 都属于非检查异常。
非检查异常表示程序正常运行时不应该会发生的异常,所以无需对非检查异常进行额外的检查。
data
声明的类toString()
, componentN()
, copy()
, equals()
和 hashCode()
方法,不在构造方法中定义的属性不会产生在 toString()
结果中。==
进行比较,同样不在构造方法中定义的属性不会用在比较上break
才会停止执行。abstract
声明的类。抽象类与普通类的最大区别是抽象类不能被实例化。abstract
声明。extends
继承普通类,继承时必须重写所有抽象方法。case class
声明的类。它可以隐式调用构造方法进行初始化,样本类没有副构造方法。toString()
, equals()
和 hashCode()
方法,不在构造方法中定义的属性不会产生在 toString()
的结果中。==
进行比较,同样不在构造方法中定义的属性不会用在比较上在 Java 中实现单例对象通常需要自己实现一个类并创建 getInstance()
的方法然后在该方法里使用两次同步块或者使用更为优雅的基于 enum
的方式。而 Scala 中则更加简单,只要使用 object
声明就能创建一个单例对象。实际上之前我们创建的拥有 main()
方法的都是单例对象。
所谓的内部类即定义在类内部的类,而包含这个内部类的类则被称作外部类。通常来说内部类可以访问外部类的私有成员,作为外部类的内部扩展而存在。
静态内部类即以 static
关键字声明的内部类。静态内部类不属于外部类的成员,使用上与普通的外部类没有什么区别。
Kotlin 同 Scala 一样使用关键字 class
来定义类,同时类的属性必须明确指明初始值。
class Person {
// 属性
var age = 0
// 行为
fun say(message: String) {
println(message)
}
}
Scala 中也使用关键字 class
来定义类,但是类的属性必须明确指明初始值,而不是像 Java 和 Groovy 一样有默认值。
class Person {
// 属性
var age = 0
// 行为
def say(message: String) {
println(message)
}
}
Groovy 中也使用关键字 class
来定义类
class Person {
// 属性
def age
// 行为
def say(message) {
println(message)
}
}
类在面向对象编程中是一个最基本的概念。类是对象的模板,用于产生具有相同结构的对象。一个类通常由属性和行为构成。
Java 中使用关键字 class
来定义类
映射是由键值对组成的一组数据的集合。映射通常基于哈希表,最常见的实现就是 HashMap。
元组类似列表,也是表示一组数据,但是元组中的数据通常都是不同类型或者数据间表示不同含义。且元组通常只用于传递数据,所以不能进行修改。
数组在程序中用于表示一组特定的值,通常来说数组的大小是预先指定的,数组的元素类型也是统一的,所以访问数组时可以通过偏移量快速访问任意一个元素。
集合类似数组,很多时候集合也是通过数组实现的,但是集合的长度是可变的,存储的数据类型也可以不一样(尽管一般都是存储同类型的数据)。集合通常有两种:List 和 Set,一般来说,前者有序且元素可以重复,后者无序但元素不能重复。
for
语句可以说是最常用的循环语句了。Java 支持普通的 for
语句以及增强型的 for-each
语句。
for 语句
for (int i = 0; i < 3; i++) {
System.out.println("Repeat For " + i);
}
if 语句用于表达这样一种概念,在某种条件下执行一种操作,在另一种条件下执行另一种操作。 Java 中的 if 语句如果操作只有一行语句的话可以省略花括号,尽管很多书籍不建议使用这种方式。
脚本,是使用一种特定的描述性语言,依据一定的格式编写的可执行文件。通常可以用于执行一些简单的代码。
Java 使用关键字 null
表示空值,即没有任何引用。使用 ==
来判断一个值是否是空值。
Integer x = null;
System.out.println(x == null);
四种语言都支持以下三种注释
// 单行注释
/*
多行注释
*/
/**
* JavaDoc
*/
String s = "Hello World";
for (char c : s.toCharArray()) {
System.out.println(c);
}
语法
数据类型 变量名 = 变量值;
例
String variable = "foo";
Java 的数据类型主要分为基本数据类型和引用数据类型。
Java 的基本类型有 int, long, float, double, char, boolean,即以小写字母开头的数据类型。
本章主要介绍四种程序的基本程序结构和特性。
REPL 为 “Read Evaluate Print Loop” 的简写,即 “读取-求值-打印-循环”,是一些动态语言的标准特性,主要用于进行探索式编程。也就是说当你不清楚某项计算的结果或者忘记了某个方法的作用时,可以输入代码片段并立即获得结果。
在进行各种测试之前,我们先为之后的所有例子建立一个完整的工程项目。我使用的开发工具为 IDEA 14 CE,构建工具选择最为通用的 Maven。
本系列主要是对 Java,Groovy,Scala 和 Kotlin 这四种 JVM 上的语言做一些粗浅的对比。对于那些语言本身提供但是却不提倡使用的功能本系列大都不会提。本系列主要使用的开发环境为 Windows 和 Mac,IDE 为 IDEA 和 Eclipse,构建工具为 Maven 和 Gradle。