在 Java 和 Groovy 中创建和初始化列表的不同
Groovy Java

> 
> 首先在 Java 中创建初始化一个整数列表，然后在 Groovy 中做同样的事。
> 
> 
> 


![](/data/attachment/album/202203/29/214023b4r9rauua1gjp59l.jpg "Developing code.")


我非常喜欢 [Groovy 编程语言](http://www.groovy-lang.org/)。我喜欢它是因为我喜欢 Java，尽管 Java 有时候感觉很笨拙。正因为我是那么喜欢 Java，其他运行在 JVM 上语言都不能吸引我。比方说 Kotlin、Scala 还有 Clojure 语言，它们感觉上就和 Java 不一样，因为它们对于什么是好的编程语言的理解不同。Groovy 和它们都不一样，在我看来，Groovy 是一个完美的选项，特别是对于一部分程序员来说，他们喜欢 Java，但是又需要一个更灵活、更紧凑，并且有时候更直接的语言。


<ruby> 列表 <rt>  List </rt></ruby> 这种数据结构是一个很好的例子，它可以容纳一个无序的列表，列表中的元素可以是数字、字符串或者对象，程序员可以用某种方式高效地遍历这些元素，特别是对于编写和维护脚本的人来说，“高效”的关键就是要有简洁清晰的表达，而不需要一大堆“仪式”，把代码的意图都变模糊了。


### 安装 Java 和 Groovy


Groovy 是基于 Java 的，因此需要同时安装一个 Java 才行。你的 Linux 发行版的仓库中可能有最近的比较好的 Java 版本。或者，你也可以在根据 [这些指导](http://www.groovy-lang.org/install.html) 来安装 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<Integer>(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<Integer>()` 的，也就是说，它为这个传进来的列表创建了一个可变的拷贝。


现在，或许只有我这么想，但是这种方式确实看起来需要理解很多关于 `java.util.Arrays` 和 `java.util.List` 类的细节才行，而我只是想要创建并初始化一个数字列表而已（尽管真正使用到的语句并没有太多“仪式”）。下面是真正用到的那行代码，仅供参考：



```
var a1 = new ArrayList<Integer>(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 << 11
println "a1 = $a1"

// output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

```

我们一眼就能发现，Groovy 使用了 `def` 关键字而不是 `var` 关键字。我还发现了，仅仅是把一系列的类型（在这个例子里是整数）放进括号里，我就得到了一个创建好的列表。此外，这样创建出来的列表完全就是我想要的：一个可变的 `ArrayList` 实例。


现在，或许再一次只有我这么想，但是上面的代码看起来要简单多得多 —— 不用记住 `.of()` 和 `.asList()` 返回的是“<ruby> 半不变 <rt>  semi-mutable </rt></ruby>”的结果，也不用为它们做一些补偿。另外一个好处是，我现在可以使用括号和下标来引用列表中的某个特定元素，而不用这个叫 `set()` 方法。另外，这个跟在列表后面的 `<<` 操作符也很方便，我再也不用调用 `add()` 方法来添加元素啦。还有，你注意到代码中没有分号了吗？没错，在 Groovy 里，句末的分号并不是必须的。最后，我们来看看字符串插值，只要在字符串里用 `$变量` 或者 `${表达式}` 就可以实现了哦！


在 Groovy 世界中还藏着许多“有待发掘”的东西。上面的列表定义其实是一个动态类型（Groovy 中默认）和 Java 中的静态类型的对比。在上面的 Groovy 代码定义的那一行，变量 `a1` 的类型是在运行的时候，根据等号右边的表达式的计算结果推断出来的。现在我们都知道，动态语言可以给我们带来强大的功能，有了强大的功能，我们有了很多机会去尝试不同的东西。对于那些不喜欢动态类型的程序员来说，Groovy 也支持静态类型。


### Groovy 相关资源


Apache Groovy 网站上有非常多的文档。另一个很棒的 Groovy 资源是 [Mr. Haki](https://www.mrhaki.com/)。学习 Groovy 还有一个很棒的原因，那就是可以接着学习 [Grails](https://grails.org/)，后者是一个优秀的、高效率的全栈 Web 框架，基于许多优秀组件构建而成，比如有 Hibernate、Spring Boot 和 Micronaut 等。




---


via: <https://opensource.com/article/22/1/creating-lists-groovy-java>


作者：[Chris Hermansen](https://opensource.com/users/clhermansen) 选题：[lujun9972](https://github.com/lujun9972) 译者：[lkxed](https://github.com/lkxed) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
I like the [Groovy programming language](http://www.groovy-lang.org/) a lot. I like it because, in the end, I like Java, even though Java sometimes feels clumsy. And because I like Java so much, I don't find many other JVM languages especially attractive. Kotlin, Scala, and Clojure, for example, don't feel much like Java, pursuing their own perspectives on what makes a good programming language. Groovy is different; in my view, Groovy is the perfect antidote to those situations when a programmer who likes Java just needs something a bit more flexible, compact, and sometimes even straightforward.

A good example is the List data structure, which is used to hold an ordered list of numbers, strings, or objects, and allows the programmer to iterate through those items in an efficient fashion. Especially for people writing and maintaining scripts, "efficiency" is mostly about clear and brief expressions that don't require a bunch of ceremony that obscures the intent of the code.

## Install Java and Groovy


Groovy is based on Java and requires a Java installation as well. Both a recent and decent version of Java and Groovy might be in your Linux distribution's repositories. Otherwise, you can install Groovy by following [these instructions](http://www.groovy-lang.org/install.html). A nice alternative for Linux users is SDKMan, which can be used to get multiple versions of Java, Groovy, and many other related tools. For this article, I use SDK's releases of:

- Java: version 11.0.12-open of OpenJDK 11
- Groovy: version 3.0.8

## Back to the problem

There have been various ways of instantiating and initializing lists in Java since they were first introduced (I think that was Java 1.5, but please don't quote me). Two current interesting ways involve two different libraries: **java.util.Arrays** and **java.util.List**.

### Use java.util.Arrays

**java.util.Arrays** defines the static method **asList()**, which can be used to create a list that is backed by an array and is therefore also immutable, though its elements are mutable. Here it is in action:

```
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
```


### Use java.util.List

**java.util.List** defines the static method **of().** This can be used to create an immutable list with elements that may or may not be immutable, depending on whether the items in the list of elements are immutable. Here is this version in action:

```
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
```


So, I can use either **Arrays.asList()** or **List.of()** if I want a list that can't be grown (or shrunk) and may or may not have alterable elements.

If I want an initialized mutable list I would probably resort to using those immutable-ish lists as arguments to a list constructor, for example:

```
var a1 = new ArrayList<Integer>(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]
```


Note that the **Arrays.AsList()** was used to initialize the new **ArrayList<Integer>()**, which created a mutable copy of the argument.

Now maybe it's just me, but this seems like an awful lot of theory—needing to be situationally aware of the details of **java.util.Arrays** or **java.util.List**—just to create and initialize a mutable list of integers, though the actual statement used is not overly "ceremonial." Here it is again, just for reference:

`var a1 = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));`


## The Groovy approach

Here is the Groovy version of the above:

```
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 << 11
println "a1 = $a1"
// output is
// a1 = [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
```


At a glance, Groovy uses the **def** keyword rather than **var**. I also know that I can create a list representation by putting a list of things—in this case, integers—between brackets. Moreover, the list instance so created is precisely what I want: a mutable instance of **ArrayList**.

Now maybe it's just me, again, but the above seems to be a whole lot simpler—no remembering the semi-immutable results returned by **.of()** or **.asList()** and compensating for them. It's also nice that I can refer to a specific element of the list using the brackets with an index value between them, rather than the method call **set()**, and that the `<<`

operator appends to the end of a list so that I don't have to use the method call **add()**. Also, did you notice the lack of semi-colons? Yep, in Groovy, they're optional. And finally, observe the use of string interpolation, with the **$variable** or **${expression}** inside a double-quoted string providing that capability.

There’s more going on "under the covers" in the Groovy world. That definition is an example of dynamic typing (the default in Groovy) versus the static typing of Java. In the Groovy definition line, the type of **a1** is inferred at runtime from the type of the expression evaluated on the right-hand side. Now we all know that dynamic programming languages give us great power and that with great power comes many good opportunities to mess up. But for programmers who don't like dynamic typing, Groovy offers the option of static typing.

## Groovy resources

The Apache Groovy site I mentioned at the beginning has a lot of great documentation. Another excellent Groovy resource is [Mr. Haki](https://www.mrhaki.com/). And a really good reason to learn Groovy is to go on and learn [Grails](https://grails.org/), which is a wonderfully productive full-stack web framework built on top of excellent components like Hibernate, Spring Boot, and Micronaut.

This article is dedicated to my very dear friend Anil Mukhi, who passed away on 3 January 2022. Thank you, Anil, for giving me the opportunity to learn so much about Groovy, Grails, and horse racing data.

## Comments are closed.