我想创建一个用于测试目的的选项列表。起初,我是这样做的:
ArrayList<String> places = new ArrayList<String>();
places.add("Buenos Aires");
places.add("Córdoba");
places.add("La Plata");
然后,我将代码重构如下:
ArrayList<String> places = new ArrayList<String>(
Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
有一个更好的方法吗?
ArrasyList<String> places = ["Buenos Aires", "Córdoba", "La Plata"]
如果您只是将其声明为 List
会更简单 - 它必须是 ArrayList 吗?
List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
或者,如果您只有一个元素:
List<String> places = Collections.singletonList("Buenos Aires");
这意味着 places
是不可变的(尝试更改它会导致抛出 UnsupportedOperationException
异常)。
要创建一个具体 ArrayList
的可变列表,您可以从不可变列表创建一个 ArrayList
:
ArrayList<String> places = new ArrayList<>(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
并导入正确的包:
import java.util.Arrays;
实际上,初始化 ArrayList
的“最佳”方法可能是您编写的方法,因为它不需要以任何方式创建新的 List
:
ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
需要注意的是,要引用该 list
实例需要进行大量输入。
还有其他选择,例如使用实例初始化器创建匿名内部类(也称为“双括号初始化”):
ArrayList<String> list = new ArrayList<String>() {{
add("A");
add("B");
add("C");
}};
但是,我不太喜欢这种方法,因为您最终得到的是 ArrayList
的一个子类,它有一个实例初始化程序,并且创建该类只是为了创建一个对象——这似乎有点矫枉过正大部头书。
如果 Project Coin 的 Collection Literals proposal 被接受,那会更好(它计划在 Java 7 中引入,但它也不太可能成为 Java 8 的一部分。):
List<String> list = ["A", "B", "C"];
不幸的是,它在这里对您没有帮助,因为它会初始化一个不可变的 List
而不是 ArrayList
,而且,它还不可用,如果有的话。
简单的答案
Java 9 或更高版本:
List<String> strings = List.of("foo", "bar", "baz");
这将为您提供一个不可变 List
,因此它无法更改。
在大多数情况下,这是您预填充它时想要的。
Java 8 或更早版本:
List<String> strings = Arrays.asList("foo", "bar", "baz");
这将为您提供一个由数组支持的 List
*,因此它无法更改长度。
但您可以调用 List.set(...)
,因此它仍然是可变。
* 实现细节:它是 java.util.Arrays
内的私有嵌套类,名为 ArrayList
,
与 java.util.ArrayList
不同,尽管它们的简单名称相同。
静态导入
您可以使用静态导入使 Java 8 Arrays.asList
更短:
import static java.util.Arrays.asList;
...
List<String> strings = asList("foo", "bar", "baz");
任何现代 IDE* 都会建议并为您执行此操作。
我不建议将 List.of
方法静态导入为 of
,因为它会造成混淆。
* 例如,在 IntelliJ IDEA 中按 Alt+Enter
并选择 Static import method...
使用流
为什么它必须是 List
?
在 Java 8 或更高版本中,您可以使用更灵活的 Stream
:
Stream<String> strings = Stream.of("foo", "bar", "baz");
您可以连接 Stream
:
Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
Stream.of("baz", "qux"));
或者您可以从 Stream
转到 List
:
import static java.util.stream.Collectors.toList;
...
var strings = Stream.of("foo", "bar", "baz").toList(); // Java 16
List<String> strings = Stream.of("foo", "bar", "baz").collect(toList()); // Java 8
但最好只使用 Stream
而不将其收集到 List
。
如果您特别需要 java.util.ArrayList*
如果您想 both 预填充一个 ArrayList
并 然后添加到它,请使用
List<String> strings = new ArrayList<>(List.of("foo", "bar"));
strings.add("baz");
或在 Java 8 或更早版本中:
List<String> strings = new ArrayList<>(asList("foo", "bar"));
strings.add("baz");
或使用 Stream
:
import static java.util.stream.Collectors.toCollection;
List<String> strings = Stream.of("foo", "bar")
.collect(toCollection(ArrayList::new));
strings.add("baz");
但同样,最好直接使用 Stream
,而不是将其收集到 List
。
*您可能不需要专门的 ArrayList
。引用 JEP 269:
有一小部分用例用于使用一组预定义的值初始化可变集合实例。通常最好将这些预定义值放在不可变集合中,然后通过复制构造函数初始化可变集合。
(强调我的)
编程接口,而不是实现
您说您已在代码中将列表声明为 ArrayList
,但只有在使用不在 List
中的 ArrayList
的某些成员时才应这样做。
您很可能不会这样做。
通常您应该只通过您将要使用的最通用接口(例如 Iterable
、Collection
或 List
)声明变量,并使用特定实现(例如 ArrayList
、LinkedList
或Arrays.asList()
)。
否则,您会将代码限制为该特定类型,并且在您想要更改时会更难。
例如,如果您将 ArrayList
传递给 void method(...)
:
// Iterable if you just need iteration, for (String s : strings):
void method(Iterable<String> strings) {
for (String s : strings) { ... }
}
// Collection if you also need .size(), .isEmpty(), or .stream():
void method(Collection<String> strings) {
if (!strings.isEmpty()) { strings.stream()... }
}
// List if you also need random access, .get(index):
void method(List<String> strings) {
strings.get(...)
}
// Don't declare a specific list implementation
// unless you're sure you need it:
void method(ArrayList<String> strings) {
??? // You don't want to limit yourself to just ArrayList
}
另一个示例总是将变量声明为 InputStream
,即使它通常是 FileInputStream
或 BufferedInputStream
,因为不久之后您或其他人会想要使用某种其他类型的 InputStream
。
如果您需要大小为 1 的简单列表:
List<String> strings = new ArrayList<String>(Collections.singletonList("A"));
如果您需要多个对象的列表:
List<String> strings = new ArrayList<String>();
Collections.addAll(strings,"A","B","C","D");
使用 Guava,您可以编写:
ArrayList<String> places = Lists.newArrayList("Buenos Aires", "Córdoba", "La Plata");
在 Guava 中还有其他有用的静态构造函数。您可以阅读它们here。
java.util.Arrays
(例如 List<String> names = Arrays.asList("Beckah", "Sam", "Michael");
)就可以做到这一点
Arrays.asList
创建一个无法修改的列表。如果需要修改列表,Lists.newArrayList
将起作用,而 Arrays.asList
将不起作用。
使用 java-9 及更高版本,如 JEP 269: Convenience Factory Methods for Collections 中所建议的,这可以使用 collection literals 现在与 -
List<String> list = List.of("A", "B", "C");
Set<String> set = Set.of("A", "B", "C");
类似的方法也适用于 Map
-
Map<String, String> map = Map.of("k1", "v1", "k2", "v2", "k3", "v3")
这类似于@coobird 所述的Collection Literals proposal。 JEP中也进一步澄清了 -
备择方案
语言更改已被考虑多次,但被拒绝: Project Coin 提案,2009 年 3 月 29 日 Project Coin 提案,2009 年 3 月 30 日 JEP 186 关于 lambda-dev 的讨论,2014 年 1 月至 3 月此消息中总结的建议。
相关:What is the point of overloaded Convenience Factory Methods for Collections in Java 9
集合文字没有进入 Java 8,但可以使用 Stream API 在一行相当长的行中初始化一个列表:
List<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toList());
如果您需要确保您的 List
是 ArrayList
:
ArrayList<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toCollection(ArrayList::new));
import com.google.common.collect.ImmutableList;
....
List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
Collections.unmodifiableList(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"))
相同,它在静态导入时变为 unmodifiableList(asList("Buenos Aires", "Córdoba", "La Plata"))
。你不需要谷歌收藏。
ImmutableList
传递给采用 List
的其他方法,然后无论如何您都会丢失该文档。
您可以创建一个工厂方法:
public static ArrayList<String> createArrayList(String ... elements) {
ArrayList<String> list = new ArrayList<String>();
for (String element : elements) {
list.add(element);
}
return list;
}
....
ArrayList<String> places = createArrayList(
"São Paulo", "Rio de Janeiro", "Brasília");
但这并不比您的第一次重构好多少。
为了获得更大的灵活性,它可以是通用的:
public static <T> ArrayList<T> createArrayList(T ... elements) {
ArrayList<T> list = new ArrayList<T>();
for (T element : elements) {
list.add(element);
}
return list;
}
在 Java 9 中,我们可以在一行中轻松地初始化 ArrayList
:
List<String> places = List.of("Buenos Aires", "Córdoba", "La Plata");
或者
List<String> places = new ArrayList<>(List.of("Buenos Aires", "Córdoba", "La Plata"));
Java 9 的这种新方法与以前的方法相比具有许多优点:
空间效率不变性线程安全
有关更多详细信息,请参阅此帖子-> What is the difference between List.of and Arrays.asList?
只需使用以下代码,如下所示。
List<String> list = new ArrayList<String>() {{
add("A");
add("B");
add("C");
}};
最紧凑的方法是:
Double array[] = { 1.0, 2.0, 3.0};
List<Double> list = Arrays.asList(array);
这是另一种方式:
List<String> values = Stream.of("One", "Two").collect(Collectors.toList());
使用 Eclipse Collections,您可以编写以下内容:
List<String> list = Lists.mutable.with("Buenos Aires", "Córdoba", "La Plata");
您还可以更具体地了解类型以及它们是可变的还是不可变的。
MutableList<String> mList = Lists.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableList<String> iList = Lists.immutable.with("Buenos Aires", "Córdoba", "La Plata");
你也可以对 Sets 和 Bags 做同样的事情:
Set<String> set = Sets.mutable.with("Buenos Aires", "Córdoba", "La Plata");
MutableSet<String> mSet = Sets.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet<String> iSet = Sets.immutable.with("Buenos Aires", "Córdoba", "La Plata");
Bag<String> bag = Bags.mutable.with("Buenos Aires", "Córdoba", "La Plata");
MutableBag<String> mBag = Bags.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableBag<String> iBag = Bags.immutable.with("Buenos Aires", "Córdoba", "La Plata");
注意:我是 Eclipse Collections 的提交者。
(应该是评论,但太长了,所以新回复)。正如其他人所提到的,Arrays.asList
方法是固定大小的,但这不是唯一的问题。它也不能很好地处理继承。例如,假设您有以下内容:
class A{}
class B extends A{}
public List<A> getAList(){
return Arrays.asList(new B());
}
以上导致编译器错误,因为 List<B>
(Arrays.asList 返回的内容)不是 List<A>
的子类,即使您可以将 B 类型的对象添加到 List<A>
对象。要解决此问题,您需要执行以下操作:
new ArrayList<A>(Arrays.<A>asList(b1, b2, b3))
这可能是最好的方法,尤其是。如果您需要一个无界列表或需要使用继承。
您可以使用以下语句:
代码片段:
String [] arr = {"Sharlock", "Homes", "Watson"};
List<String> names = Arrays.asList(arr);
letters = Arrays.asList(new String[]{"A", "B", "C"});
像 Tom said:
List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
但是既然你抱怨想要一个 ArrayList,你首先应该知道 ArrayList 是 List 的一个子类,你可以简单地添加这一行:
ArrayList<String> myPlaces = new ArrayList(places);
虽然,这可能会让你抱怨“性能”。
在那种情况下,这对我来说没有意义,为什么,因为你的列表是预定义的,它没有被定义为一个数组(因为在初始化时大小是已知的)。如果这是您的选择:
String[] places = {"Buenos Aires", "Córdoba", "La Plata"};
如果您不关心细微的性能差异,那么您也可以非常简单地将数组复制到 ArrayList:
ArrayList<String> myPlaces = new ArrayList(Arrays.asList(places));
好的,但是将来您需要的不仅仅是地名,还需要国家代码。假设这仍然是一个在运行时永远不会更改的预定义列表,那么使用 enum
集是合适的,如果将来需要更改列表,则需要重新编译。
enum Places {BUENOS_AIRES, CORDOBA, LA_PLATA}
会成为:
enum Places {
BUENOS_AIRES("Buenos Aires",123),
CORDOBA("Córdoba",456),
LA_PLATA("La Plata",789);
String name;
int code;
Places(String name, int code) {
this.name=name;
this.code=code;
}
}
Enum 有一个静态 values
方法,该方法返回一个数组,其中包含按声明顺序排列的枚举的所有值,例如:
for (Places p:Places.values()) {
System.out.printf("The place %s has code %d%n",
p.name, p.code);
}
在那种情况下,我猜你不需要你的 ArrayList。
PS Randyaa demonstrated 另一种使用静态实用方法 Collections.addAll 的好方法。
Java 9 有以下方法来创建不可变列表:
List<String> places = List.of("Buenos Aires", "Córdoba", "La Plata");
如果需要,它很容易适应创建一个可变列表:
List<String> places = new ArrayList<>(List.of("Buenos Aires", "Córdoba", "La Plata"));
类似的方法可用于 Set
和 Map
。
List<String> names = Arrays.asList("2","@2234","21","11");
是的,在 Arrays 的帮助下,您可以在一行中初始化数组列表,
List<String> strlist= Arrays.asList("aaa", "bbb", "ccc");
您可以使用 Cactoos 中的 StickyList
:
List<String> names = new StickyList<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
);
试试这个代码行:
Collections.singletonList(provider)
使用 Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
是正确的。但是任何对带有零参数或只有一个参数的 Arrays.asList()
的调用都可以替换为对 Collections.singletonList()
或 Collections.emptyList()
的调用,这将节省一些内存。
注意:Collections.singletonList()
返回的列表是不可变的,而 Arrays.asList()
返回的列表允许调用 set() 方法。在极少数情况下,这可能会破坏代码。
在Java中,你不能这样做
ArrayList<String> places = new ArrayList<String>( Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
正如所指出的,您需要进行双括号初始化:
List<String> places = new ArrayList<String>() {{ add("x"); add("y"); }};
但这可能会迫使您添加注释 @SuppressWarnings("serial")
或生成令人讨厌的串行 UUID。此外,大多数代码格式化程序会将其展开为多个语句/行。
或者你可以做
List<String> places = Arrays.asList(new String[] {"x", "y" });
但是你可能想做一个@SuppressWarnings("unchecked")
。
同样根据javadoc,您应该能够做到这一点:
List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
但我无法让它与 JDK 1.6 一起编译。
Collections.singletonList(messageBody)
如果您需要一个项目的列表!
Collections 来自 java.util 包。
最好的方法:
package main_package;
import java.util.ArrayList;
public class Stackkkk {
public static void main(String[] args) {
ArrayList<Object> list = new ArrayList<Object>();
add(list, "1", "2", "3", "4", "5", "6");
System.out.println("I added " + list.size() + " element in one line");
}
public static void add(ArrayList<Object> list,Object...objects){
for(Object object:objects)
list.add(object);
}
}
只需创建一个可以包含任意数量元素的函数,然后调用它以将它们添加到一行中。
Object
。
这是AbacusUtil的代码
// ArrayList
List<String> list = N.asList("Buenos Aires", "Córdoba", "La Plata");
// HashSet
Set<String> set = N.asSet("Buenos Aires", "Córdoba", "La Plata");
// HashMap
Map<String, Integer> map = N.asMap("Buenos Aires", 1, "Córdoba", 2, "La Plata", 3);
// Or for Immutable List/Set/Map
ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet.of("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet.of("Buenos Aires", 1, "Córdoba", 2, "La Plata", 3);
// The most efficient way, which is similar with Arrays.asList(...) in JDK.
// but returns a flexible-size list backed by the specified array.
List<String> set = Array.asList("Buenos Aires", "Córdoba", "La Plata");
声明:我是AbacusUtil的开发者。
有趣的是,没有一个线程与另一个重载 Stream::collect
方法被列出
ArrayList<String> places = Stream.of( "Buenos Aires", "Córdoba", "La Plata" ).collect( ArrayList::new, ArrayList::add, ArrayList::addAll );
对我来说 Arrays.asList() 是最好和方便的。我总是喜欢这样初始化。如果您是 Java 集合的初学者,那么我希望您参考 ArrayList initialization
add()
方法在一行中创建一个新的 ArrayList 更好?
为什么不做一个简单的实用函数呢?
static <A> ArrayList<A> ll(A... a) {
ArrayList l = new ArrayList(a.length);
for (A x : a) l.add(x);
return l;
}
“ll
”代表“文字列表”。
ArrayList<String> places = ll("Buenos Aires", "Córdoba", "La Plata");
list
,则该名称无需解释 :)
ArrayList
的方法,最好将声明更改为List
。指定接口,而不是实现。asList(...)
返回一个固定大小的List
,它会在remove
和clear
之类的变异操作上崩溃,而List
合约声称支持这些操作。即使您将声明保留为List
,您仍然需要使用List l = new ArrayList(asList(...))
来获取不会引发 OperationNotSupported 异常的对象。里斯科夫替换原则有人吗?