Câu hỏi Khởi tạo một ArrayList trong một dòng


Tôi muốn tạo danh sách các tùy chọn cho mục đích thử nghiệm. Lúc đầu, tôi đã làm điều này:

ArrayList<String> places = new ArrayList<String>();
places.add("Buenos Aires");
places.add("Córdoba");
places.add("La Plata");

Sau đó, tôi đã tái cấu trúc mã như sau:

ArrayList<String> places = new ArrayList<String>(
    Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));

Có cách nào tốt hơn để làm điều này?


2164
2018-06-17 04:10


gốc


Nếu điều này là dành cho thử nghiệm đơn vị, hãy thử groovy ra cho một swing. Bạn có thể viết mã thử nghiệm của mình trong khi thử nghiệm mã java và sử dụng ArrasyList<String> places = ["Buenos Aires", "Córdoba", "La Plata"] - ripper234
Trong Java SE 7, bạn có thể thay thế kiểu tham số của hàm tạo bằng một tập rỗng các tham số kiểu (<>): Bản đồ <String, List <String >> myMap = new HashMap <> (); - Rose
Xem thêm stackoverflow.com/questions/157944/create-arraylist-from-array - Christoffer Hammarström
sử dụng đôi giằng khởi tạo :) - Mohammad Reza Khatami
Stream.of ("val1", "val2") thu thập (Collectors.toList ()); // tạo ra ArrayList, giải pháp Java8. - torina


Các câu trả lời:


Trên thực tế, có lẽ cách "tốt nhất" để khởi tạo ArrayList là phương pháp bạn đã viết, vì nó không cần tạo một phương thức mới List theo bất kỳ cách nào:

ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");

Việc nắm bắt là có khá nhiều cách gõ cần thiết để chỉ list ví dụ.

Có các lựa chọn thay thế, chẳng hạn như tạo một lớp bên trong vô danh với một trình khởi tạo thể hiện (còn được gọi là "khởi tạo cú đúp đôi"):

ArrayList<String> list = new ArrayList<String>() {{
    add("A");
    add("B");
    add("C");
}};

Tuy nhiên, tôi không thích phương pháp đó bởi vì điều bạn kết thúc là một phân lớp của ArrayList trong đó có một khởi tạo thể hiện, và lớp đó được tạo ra chỉ để tạo một đối tượng - điều đó dường như có vẻ hơi quá mức đối với tôi.

Điều gì sẽ tốt đẹp nếu Đề xuất Bộ sưu tập Văn học cho Dự án Coin đã được chấp nhận (nó được dự kiến ​​sẽ được giới thiệu trong Java 7, nhưng nó không có khả năng là một phần của Java 8.):

List<String> list = ["A", "B", "C"];

Thật không may nó sẽ không giúp bạn ở đây, vì nó sẽ khởi tạo một bất biến List chứ không phải là ArrayListvà hơn thế nữa, nó chưa có sẵn, nếu nó sẽ có.


1627
2018-06-17 04:13



Xem stackoverflow.com/questions/924285 để biết thêm thông tin về khởi tạo đôi, ưu và nhược điểm. - Eddie
@Eddie: Cuộc gọi tốt cho liên kết - một câu trên khởi tạo đúp cú đúp không đủ để mô tả nó đầy đủ. - coobird
Chỉ hoạt động nếu bạn không dựa vào danh sách Auto boxing <Double> list = [1.0, 2.0, 3.0]; không thành công. - Richard B
Vâng, chỉ cần đi để hiển thị - đường cú pháp của một người đàn ông là một bệnh tiểu đường cú pháp mans. Tôi sẽ tránh xa những 'lựa chọn thay thế' này. - corsiKa
Vì câu trả lời này là Dự án được đề cập nhiều nhất và được đề cập đến, tôi nghĩ bạn nên gọi java 9 được gửi kèm với cú pháp List.of (...): docs.oracle.com/javase/9/docs/api/java/util/List.html#of-E...- - Asaf


Sẽ đơn giản hơn nếu bạn chỉ tuyên bố nó như là một List - nó có phải là một ArrayList không?

List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");

Hoặc nếu bạn chỉ có một phần tử:

List<String> places = Collections.singletonList("Buenos Aires");

Điều này có nghĩa là places Là không thay đổi (cố gắng thay đổi nó sẽ gây ra một UnsupportedOperationException ngoại lệ để được ném).

Để tạo một danh sách có thể thay đổi được là bê tông ArrayList bạn có thể tạo ArrayList từ danh sách bất biến:

ArrayList<String> places = new ArrayList<>(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));

1734
2018-06-17 04:15



@Marcase: Bạn có thể không thay đổi lớp học của mình để sử dụng Danh sách thay vì ArrayList không? - Lawrence Dol
Theo câu trả lời của tôi, nếu bạn không sử dụng các phương pháp cụ thể để ArrayList, sẽ là thiết kế tốt hơn để thay đổi tuyên bố thành List. Chỉ định giao diện, không triển khai. - Christoffer Hammarström
@Christoffer Hammarström: nếu anh ta thay đổi tuyên bố thành Danh sách và sử dụng Liệt kê <String> places = Arrays.asList (...); anh ấy sẽ không thể sử dụng places.add ("blabla") - maks
Chỉ để được rõ ràng, asList(...) trả về một kích thước cố định List điều đó sẽ thổi vào các hoạt động đột biến như remove và clear, mọi thứ List yêu cầu hợp đồng để hỗ trợ. Ngay cả khi bạn để lại tuyên bố List, bạn sill cần phải sử dụng List l = new ArrayList(asList(...)) để có được một đối tượng không ném ngoại lệ OperationNotSupported. Nguyên tắc thay thế Liskov có ai không? - Splash
@Splash: remove và clear là các hoạt động tùy chọn trong List, vì thế asList(...) làm theo hợp đồng. Không có OP nào nói rằng anh ta cần thêm nhiều yếu tố hơn sau, ví dụ chỉ là một List cần được khởi tạo với ba phần tử. - Christoffer Hammarström


Câu trả lời đơn giản

Trong Java 8 trở về trước:

List<String> strings = Arrays.asList("foo", "bar", "baz");

Điều này sẽ cung cấp cho bạn một List được hỗ trợ bởi mảng, vì vậy nó không thể thay đổi độ dài.
Nhưng bạn có thể gọi List.set, do đó, nó vẫn có thể thay đổi.


Trong Java 9:

List<String> strings = List.of("foo", "bar", "baz");

Điều này sẽ cung cấp cho bạn một sự bất biến List, vì vậy nó không thể thay đổi.
Đó là những gì bạn muốn trong hầu hết các trường hợp mà bạn đang chuẩn bị trước nó.


Câu trả lời ngắn hơn

Bạn có thể làm Arrays.asList thậm chí ngắn hơn với nhập tĩnh:

List<String> strings = asList("foo", "bar", "baz");

Nhập tĩnh:

import static java.util.Arrays.asList;  

IDE nào hiện đại sẽ đề xuất và tự động làm cho bạn.
Ví dụ: IntelliJ IDEA bạn nhấn Alt+Enter và chọn Static import method....


Tuy nhiên, tôi không khuyên bạn nên rút ngắn Java 9 List.of phương pháp, bởi vì chỉ có of trở nên khó hiểu.
List.of đã đủ ngắn và đọc tốt.


Sử dụng StreamS

Tại sao nó phải là một List?
Với Java 8 trở lên, bạn có thể sử dụng Stream linh hoạt hơn:

Stream<String> strings = Stream.of("foo", "bar", "baz");

Bạn có thể nối StreamS:

Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
                                       Stream.of("baz", "qux"));

Hoặc bạn có thể đi từ Stream đến một List:

List<String> strings = Stream.of("foo", "bar", "baz").collect(toList());

Nhưng tốt hơn, chỉ cần sử dụng Stream mà không thu thập nó vào một List.


nếu bạn có thật không đặc biệt cần một java.util.ArrayList

(Bạn có lẽ không.)
Để trích JEP 269 (tôi nhấn mạnh):

Đây là một bộ nhỏ các trường hợp sử dụng để khởi tạo một cá thể thu thập có thể thay đổi với một tập các giá trị được xác định trước. Nó thường là thích hợp hơn để có những giá trị được xác định trước được trong một bộ sưu tập bất biến, và sau đó để khởi tạo bộ sưu tập có thể thay đổi thông qua một nhà xây dựng bản sao.


Nếu bạn muốn cả hai chuẩn bị trước ArrayList   thêm vào nó sau đó (tại sao?), sử dụng

List<String> strings = new ArrayList<>(asList("foo", "bar", "baz"));

hoặc trong Java 9:

List<String> strings = new ArrayList<>(List.of("foo", "bar", "baz"));

hoặc sử dụng Stream:

List<String> strings = Stream.of("foo", "bar", "baz")
                             .collect(toCollection(ArrayList::new));

Nhưng một lần nữa, tốt hơn là chỉ cần sử dụng Stream trực tiếp thay vì thu thập nó vào List.


Chương trình giao diện, không triển khai

Bạn nói bạn đã khai báo danh sách như một ArrayList trong mã của bạn, nhưng bạn chỉ nên làm điều đó nếu bạn đang sử dụng một số thành viên của ArrayList không có List.

Mà bạn có nhiều khả năng không làm.

Thông thường, bạn chỉ nên khai báo các biến theo giao diện chung nhất mà bạn sẽ sử dụng (ví dụ: Iterable, Collection, hoặc là List) và khởi tạo chúng với việc triển khai cụ thể (ví dụ: ArrayList, LinkedList hoặc là Arrays.asList()).

Nếu không, bạn đang hạn chế mã của mình theo loại cụ thể đó và sẽ khó thay đổi hơn khi bạn muốn.

Ví dụ:

// Iterable if you just need iteration, for (String s : strings):
Iterable<String> strings = new ArrayList<>();   

// Collection if you also need .size() or .stream():
Collection<String> strings = new ArrayList<>(); 

// List if you also need .get(index):
List<String> strings = new ArrayList<>();       

// Don't declare a specific list implementation
// unless you're sure you need it:
ArrayList<String> strings = new ArrayList<>();  // You don't need ArrayList

Một ví dụ khác sẽ luôn luôn tuyên bố biến một InputStream mặc dù nó thường là FileInputStream hoặc một BufferedInputStream, bởi vì một ngày sớm bạn hoặc ai đó khác sẽ muốn sử dụng một số loại khác InputStream.


582
2017-09-09 12:33



Cảm ơn bạn đã bao giờ rất nhiều. Tôi đã cố gắng bỏ qua 'tĩnh' nhập khẩu trong mã của tôi, nhưng trình biên dịch sẽ không có bất kỳ của nó. Tại sao tĩnh cần thiết để mã hoạt động? - jollyroger
@Jolly Roger: Arrays.asList là một phương pháp tĩnh. Xem docs.oracle.com/javase/1.5.0/docs/guide/language/… - Christoffer Hammarström
@ ChristofferHammarström Trong trường hợp đó, tâm trí mới làm quen của tôi nói với tôi rằng các thanh nhập khẩu tĩnh tương tự với các biến toàn cục và các nguy hiểm liên quan đến việc sử dụng đó. Giả định này có chính xác không và đó cũng là lý do cho câu trả lời tương tự ở trên nhận được nhiều phiếu bầu hơn? - jollyroger
Nếu bạn không muốn nhập khẩu tĩnh, bạn cũng có thể định nghĩa đường dẫn đầy đủ đến phương thức tĩnh asList, như sau: Liệt kê <String> strings = java.util.Arrays.asList ("", ""); - Geert Weening
Hoặc bạn có thể sử dụng nhập khẩu java.util.Arrays; và Arrays.asList ("", ""); Bạn không phải sử dụng nhập tĩnh. Bạn không phải sử dụng đường dẫn đầy đủ. Các phương thức tĩnh không quan tâm đến việc nhập. Họ chỉ nhận được khó chịu nếu bạn sử dụng một thể hiện để tìm thấy chúng. - candied_orange


Nếu bạn cần một danh sách đơn giản về kích thước 1:

List<String> strings = new ArrayList<String>(Collections.singletonList("A"));

Nếu bạn cần danh sách một số đối tượng:

List<String> strings = new ArrayList<String>();
Collections.addAll(strings,"A","B","C","D");

100
2017-08-30 04:33





Với Trái ổi bạn có thể viết:

ArrayList<String> places = Lists.newArrayList("Buenos Aires", "Córdoba", "La Plata");

Trong ổi cũng có các nhà xây dựng tĩnh hữu ích khác. Bạn có thể đọc về chúng đây.


52
2017-07-29 13:24



Tôi chắc rằng bạn có thể làm điều này chỉ với java.util.Arrays nhu la, List<String> names = Arrays.asList("Beckah", "Sam", "Michael"); - beckah
Phương thức @beckah Arrays.asLists tạo đối tượng của List list, trong khi câu hỏi là tạo ArrayList - Paweł Adamski
Phương pháp này không thực sự hữu ích và có thể sẽ không còn được dùng nữa trong tương lai. - shmosel


Các bộ sưu tập các văn bản đã không biến nó thành Java 8, nhưng có thể sử dụng API luồng để khởi tạo một danh sách trong một dòng khá dài:

List<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toList());

Nếu bạn cần đảm bảo rằng List là một ArrayList:

ArrayList<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toCollection(ArrayList::new));

32
2018-04-03 23:21





import com.google.common.collect.ImmutableList;

....

List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");

26
2018-05-12 13:14



Tôi không muốn thêm một phụ thuộc mới chỉ để làm điều đó. - Macarse
Đó là giống như Collections.unmodifiableList(Arrays.asList("Buenos Aires", "Córdoba", "La Plata")), trở thành unmodifiableList(asList("Buenos Aires", "Córdoba", "La Plata")) với nhập tĩnh. Bạn không cần Google Bộ sưu tập cho việc này. - Christoffer Hammarström
Không, nó không giống nhau. Vì ImmutableList đang ghi lại tính bất biến của nó trong kiểu kết quả khi unmodifiableList giả mạo nó như một Danh sách thông thường. - David Pierre
Thay vì không thay đổi, bộ sưu tập google cũng cung cấp danh sách mảng có thể thay đổi: List <String> = Lists.newArrayList ("Buenos Aires", "Córdoba", "La Plata"); - L. Holanda
Bạn sẽ vượt qua điều đó ImmutableList với các phương pháp khác Listvà sau đó bạn đã mất tài liệu đó. - Christoffer Hammarström


Bạn có thể tạo phương thức nhà máy:

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");

Nhưng nó không tốt hơn nhiều so với lần tái cấu trúc đầu tiên của bạn.

Để linh hoạt hơn, nó có thể là chung:

public static <T> ArrayList<T> createArrayList(T ... elements) {
  ArrayList<T> list = new ArrayList<T>();
  for (T element : elements) {
    list.add(element);
  }
  return list;
}

22
2018-05-04 00:57



Nhìn lại bài viết gốc, nó yêu cầu khởi tạo mảng trong một đường thẳng, không phải 7 dòng bổ sung. - L. Holanda
@LeoHolanda: Tạo ra phương pháp nhà máy cho mọi điều nhỏ là quá nhiều, tôi đồng ý. Nhưng tùy về tình hình, và về số lần mà phương pháp đó sẽ được sử dụng, nó có thể có ý nghĩa để tạo ra nó. Tạo thêm lớp trừu tượng có nghĩa là tẩy phức tạp, bằng cách tạo thêm có ý nghĩa phương pháp nắm bắt ý định của nhà thiết kế. - Jordão


Với Java 9, như được đề xuất trong Đề xuất nâng cao JDK - 269, điều này có thể đạt được bằng cách sử dụng bộ sưu tập chữ bây giờ là -

List<String> list = List.of("A", "B", "C");

Set<String> set = Set.of("A", "B", "C");

Một cách tiếp cận tương tự cũng sẽ áp dụng cho Map cũng -

Map<String, String> map = Map.of("k1", "v1", "k2", "v2", "k3", "v3")

tương tự như Đề xuất Bộ sưu tập Văn học như đã nói bởi @coobird. Làm rõ thêm trong tài liệu JEP -


Giải pháp thay thế

Thay đổi ngôn ngữ đã được xem xét nhiều lần và bị từ chối:

Đề xuất đồng xu dự án, ngày 29 tháng 3 năm 2009 

Đề xuất đồng xu dự án, ngày 30 tháng 3 năm 2009 

JEP 186 thảo luận về lambda-dev, tháng 1-tháng 3 năm 2014

Ngôn ngữ   đề xuất được dành riêng cho một đề xuất dựa trên thư viện như   tóm tắt trong này thông điệp.

Chained đọc về cùng một ~> Điểm của phương pháp nhà máy tiện lợi quá tải là gì


17
2018-02-02 17:36