首先在 Java 中创建初始化一个整数列表,然后在 Groovy 中做同样的事。
我非常喜欢 Groovy 编程语言。我喜欢它是因为我喜欢 Java,尽管 Java 有时候感觉很笨拙。正因为我是那么喜欢 Java,其他运行在 JVM 上语言都不能吸引我。比方说 Kotlin、Scala 还有 Clojure 语言,它们感觉上就和 Java 不一样,因为它们对于什么是好的编程语言的理解不同。Groovy 和它们都不一样,在我看来,Groovy 是一个完美的选项,特别是对于一部分程序员来说,他们喜欢 Java,但是又需要一个更灵活、更紧凑,并且有时候更直接的语言。
列表 List 这种数据结构是一个很好的例子,它可以容纳一个无序的列表,列表中的元素可以是数字、字符串或者对象,程序员可以用某种方式高效地遍历这些元素,特别是对于编写和维护脚本的人来说,“高效”的关键就是要有简洁清晰的表达,而不需要一大堆“仪式”,把代码的意图都变模糊了。
安装 Java 和 Groovy
Groovy 是基于 Java 的,因此需要同时安装一个 Java 才行。你的 Linux 发行版的仓库中可能有最近的比较好的 Java 版本。或者,你也可以在根据 这些指导 来安装 Groovy。对于 Linux 用户来说,SDKMan 是一个不错的代替选项,你可以使用它来获取多个 Java 和 Groovy 版本,以及许多其他的相关工具。在这篇文章中,我使用的 SDK 发行版是:
- Java: OpenJDK 11 的 11.0.12-open 版本
- Groovy: 3.0.8 版本
言归正传
Java 中有很多方法可以实例化并初始化列表,从它最初被引入的时候就有了(我记得是在 Java 1.5 的时候,但请不要引用我的话)。在这些方法里,有两个有趣的方法,它们涉及到了 java.util.Arrays
和 java.util.List
这两个类。
使用 java.util.Arrays 类
java.util.Arrays
类定义了一个 asList()
静态方法,它可以被用来创建一个基于数组的列表,因此大小是不可变的,尽管其中的元素是可以被修改的。下面是它的使用方式:
var a1 = Arrays.asList(1,2,3,4,5,6,7,8,9,10); // immutable list of mutable elements
System.out.println("a1 = " + a1);
System.out.println("a1 is an instance of " + a1.getClass());
// output is
// a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// a1 is an instance of class java.util.Arrays$ArrayList
a1.set(0,0); // succeeds
System.out.println("a1 = " + a1); // output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a1.add(11); // fails producing
// Exception in thread "main" java.lang.UnsupportedOperationException
System.out.println("a1 = " + a1); // not reached
使用 java.util.List 类
java.util.List
类定义了一个 of()
静态方法,它可以被用来创建一个不可变的列表,其中的元素是否可变要取决于它们本身是否支持修改。下面是它的使用方式:
var a2 = List.of(1,2,3,4,5,6,7,8,9,10);
System.out.println("a2 = " + a2);
System.out.println("a2 is an instance of " + a2.getClass());
// output is
// a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// a2 is an instance of class java.util.ImmutableCollections$ListN
a2.set(0,0); // fails producing
// Exception in thread "main" java.lang.UnsupportedOperationException
System.out.println("a2 = " + a2); // not reached
a2.add(11); // also fails for same reason if above two lines commented out
System.out.println("a2 = " + a2); // not reached
因此,我可以使用 Arrays.asList()
,也可以使用 List.of()
方法,前提是如果我想要的是一个大小不能改变、且不关心元素是否可变的列表。
如果我想要初始化一个可变的列表,我更倾向于把这些不可变的列表作为参数传给一个列表构造器,就像下面这样:
var a1 = new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
System.out.println("a1 = " + a1);
System.out.println("a1 is an instance of " + a1.getClass());
// output is
// a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// a1 is an instance of class java.util.ArrayList
a1.set(0,0);
System.out.println("a1 = " + a1);
//output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a1.add(11);
System.out.println("a1 = " + a1);
// output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
注意,这个 Arrays.asList()
方法是用来初始化这个新的 ArrayList()
的,也就是说,它为这个传进来的列表创建了一个可变的拷贝。
现在,或许只有我这么想,但是这种方式确实看起来需要理解很多关于 java.util.Arrays
和 java.util.List
类的细节才行,而我只是想要创建并初始化一个数字列表而已(尽管真正使用到的语句并没有太多“仪式”)。下面是真正用到的那行代码,仅供参考:
var a1 = new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
Groovy 是怎么做的
下面来看看在 Groovy 中如何实现上述需求:
def a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
println "a1 = $a1"
println "a1 is an instance of ${a1.getClass()}"
// output is
// a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// a1 is an instance of class java.util.ArrayList
a1[0] = 0
println "a1 = $a1"
// output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a1