أريد إنشاء قائمة خيارات لأغراض الاختبار. في البداية ، فعلت هذا:
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"));
هل هناك طريقة أفضل للقيام بذلك؟
في الواقع ، ربما تكون الطريقة "الأفضل" لتهيئة 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
والتي تحتوي على مُهيئ مثيل ، ويتم إنشاء تلك الفئة فقط لإنشاء كائن واحد - يبدو ذلك كأنه مبالغة بالنسبة لي .
ما كان سيكون لطيفًا لو تم قبول اقتراح مجموعة المقتنيات لـ عملة المشروع (تم عرضه في Java 7 ، لكن من غير المحتمل أن يكون جزءًا من Java 8 أيضًا):
List<String> list = ["A", "B", "C"];
لسوء الحظ ، لن يساعدك ذلك هنا ، حيث إنه سيؤدي إلى تهيئة List
غير قابل للتغيير بدلاً من ArrayList
، وعلاوة على ذلك ، فهو غير متوفر حتى الآن ، إذا كان متاحًا على الإطلاق.
سيكون الأمر أكثر بساطة إذا كنت ستعلنها فقط كـ 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"));
في Java 10 أو 11 أو 12 أو أحدث:
var strings = List.of("foo", "bar", "baz");
في Java 9 أو الأحدث:
List<String> strings = List.of("foo", "bar", "baz");
سيعطيك هذا List
غير قابل للتغيير ، لذلك لا يمكن تغييره.
وهذا هو ما تريده في معظم الحالات حيث تقوم بجمعه مسبقًا.
List<String> strings = Arrays.asList("foo", "bar", "baz");
سيعطيك هذا List
مدعومة بالصفيف ، لذلك لا يمكن تغيير الطول.
ولكن يمكنك الاتصال بـ List.set
، لذلك لا يزال قابلاً للتغيير.
يمكنك جعل Arrays.asList
أقصر من خلال استيراد ثابت:
List<String> strings = asList("foo", "bar", "baz");
الاستيراد الثابت:
import static Java.util.Arrays.asList;
أي حديث IDE سيقترح عليك وينفذها تلقائيًا لك.
على سبيل المثال في IntelliJ IDEA تضغط على Alt+Enter
واختر Static import method...
.
ومع ذلك ، لا أوصي باختصار أسلوب Java 9 List.of
، لأن مجرد of
يصبح مربكًا.List.of
بالفعل قصير بما فيه الكفاية ويقرأ جيدًا.
Stream
sلماذا يجب أن تكون List
؟
باستخدام Java 8 أو إصدار أحدث ، يمكنك استخدام Stream
وهو أكثر مرونة:
Stream<String> strings = Stream.of("foo", "bar", "baz");
يمكنك تسلسل Stream
s:
Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
Stream.of("baz", "qux"));
أو يمكنك الانتقال من Stream
إلى List
:
import static Java.util.stream.Collectors.toList;
List<String> strings = Stream.of("foo", "bar", "baz").collect(toList());
لكن من الأفضل أن تستخدم فقط Stream
دون تجميعها على List
.
Java.util.ArrayList
(ربما لا تفعل ذلك)
للإقتباس JEP 269 (لغم التشديد):
هناك مجموعة صغيرة من حالات الاستخدام لتهيئة مثيل مجموعة قابلة للتغيير مع مجموعة محددة مسبقًا من القيم. من المفضل عادة أن تكون تلك القيم المحددة مسبقًا في مجموعة غير قابلة للتغيير ، ثم تهيئة المجموعة القابلة للتغيير عبر مُنشئ نسخ.
إذا كنت ترغب في (كليهما إعداد مسبق لـ ArrayList
و أضف إليه بعد ذلك (لماذا؟) ، استخدم
ArrayList<String> strings = new ArrayList<>(List.of("foo", "bar"));
strings.add("baz");
أو في Java 8 أو إصدار سابق:
ArrayList<String> strings = new ArrayList<>(asList("foo", "bar"));
strings.add("baz");
أو استخدام Stream
:
import static Java.util.stream.Collectors.toCollection;
ArrayList<String> strings = Stream.of("foo", "bar")
.collect(toCollection(ArrayList::new));
strings.add("baz");
لكن مرة أخرى ، من الأفضل أن تستخدم فقط Stream
مباشرة بدلاً من تجميعها على List
.
لقد ذكرت أنك أعلنت أن القائمة ArrayList
في شفرتك ، لكن يجب عليك القيام بذلك فقط إذا كنت تستخدم بعض أعضاء ArrayList
غير موجود في List
.
الذي أنت على الأرجح لا تفعل.
عادةً ما يجب عليك فقط الإعلان عن المتغيرات من خلال الواجهة الأكثر عمومية التي ستستخدمها (على سبيل المثال ، 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 .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");
لم تدخل القيم الحرفية للمجموعة في 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");
باستخدام Java 9
، كما هو مقترح في JDK Enhancement Proposal - 269 ، يمكن تحقيق ذلك باستخدام مجموعة الحرفية الآن باسم -
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")
وهو مشابه لـ اقتراح مجموعة Literals كما ذكرcoobird أيضًا. مزيد من التوضيح في وثيقة JEP كذلك -
البدائل
تم اعتبار التغييرات اللغوية عدة مرات ، ورفضت:
اقتراح عملة المشروع ، 29 مارس 2009
اقتراح عملة المشروع ، 30 مارس 2009
JEP 186 مناقشة حول lambda-dev ، من يناير إلى مارس 2014
تم وضع المقترحات اللغوية جانبًا في تفضيلها على اقتراح قائم على المكتبة كما هو موضح في هذه الرسالة .
Related => ما هي الفائدة من طرق مصنع الراحة الزائدة للمجموعات في Java 9
يمكنك إنشاء طريقة المصنع:
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 له العديد من المزايا مقارنة بالمزايا السابقة:
راجع هذا المنشور لمزيد من التفاصيل ->ما هو الفرق بين List.of و Arrays.asList؟
مع مجموعات Eclipse يمكنك كتابة ما يلي:
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");
يمكنك أيضًا أن تفعل الشيء نفسه مع مجموعات وحقائب:
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.
إليك طريقة أخرى:
List<String> values = Stream.of("One", "Two").collect(Collectors.toList());
حول الطريقة الأكثر ضغطًا للقيام بذلك هي:
Double array[] = { 1.0, 2.0, 3.0};
List<Double> list = Arrays.asList(array);
ببساطة استخدام رمز أدناه على النحو التالي.
List<String> list = new ArrayList<String>() {{
add("A");
add("B");
add("C");
}};
(يجب أن يكون تعليقًا ، ولكنه طويل جدًا ، رد جديد جدًا). كما ذكر الآخرون ، طريقة 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))
ربما هذه هي أفضل طريقة للقيام بذلك ، esp. إذا كنت بحاجة إلى قائمة غير محدودة أو تحتاج إلى استخدام الميراث.
يمكنك استخدام العبارات أدناه:
String [] arr = {"Sharlock", "Homes", "Watson"};
List<String> names = Arrays.asList(arr);
يحتوي 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> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
ولكن نظرًا لأنك اشتكت من رغبتك في قائمة ArrayList ، فيجب أن تعرف أولاً أن ArrayList هي فئة فرعية من القائمة ويمكنك ببساطة إضافة هذا السطر:
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;
}
}
يحتوي التعداد على طريقة values
ثابتة تقوم بإرجاع صفيف يحتوي على جميع قيم التعداد بالترتيب الذي تم إعلانه به ، على سبيل المثال:
for (Places p:Places.values()) {
System.out.printf("The place %s has code %d%n",
p.name, p.code);
}
في هذه الحالة أعتقد أنك لن تحتاج إلى قائمة ArrayList الخاصة بك.
ملاحظة أظهر Randyaa طريقة لطيفة أخرى باستخدام طريقة الأداة المساعدة الثابتة Collections.addAll .
List<String> names = Arrays.asList("2","@2234","21","11");
يمكنك استخدام StickyList
from Cactoos :
List<String> names = new StickyList<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
);
جرب باستخدام سطر الشفرة هذا:
Collections.singletonList(provider)
نعم بمساعدة Arrays ، يمكنك تهيئة قائمة الصفيف في سطر واحد ،
List<String> strlist= Arrays.asList("aaa", "bbb", "ccc");
في 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.
أفضل طريقة للقيام بذلك:
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);
}
}
فقط قم بإنشاء وظيفة يمكن أن تحتوي على أكبر عدد تريده من العناصر واطلب منه إضافتها في سطر واحد.
Collections.singletonList(messageBody)
إذا كنت بحاجة إلى الحصول على قائمة عنصر واحد !
المجموعات هي من Java.util الحزمة.
هنا هو رمز بواسطة 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.
لماذا لا تجعل وظيفة الأداة المساعدة البسيطة التي تفعل هذا؟
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");
بالنسبة لي Arrays.asList () هو الأفضل والملائم. أنا دائما أحب أن تهيئة بهذه الطريقة. إذا كنت مبتدئًا في مجموعات Java ، فإني أود منك الرجوع تهيئة ArrayList