تهيئة ArrayList في سطر واحد
-
05-07-2019 - |
سؤال
أريد إنشاء قائمة بالخيارات لأغراض الاختبار.في البداية فعلت هذا:
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
التي لديها مهيئ سبيل المثال، ويتم إنشاء تلك الفئة فقط لخلق كائن واحد - الذي يبدو تماما مثل قليلا مبالغة بالنسبة لي.
وماذا كان لطيفا وإذا كان مجموعة الحرفية تم قبول الاقتراح للحصول على مشروع عملة (وكان من المقرر أن يتم عرضه في جافا 7، ولكن من غير المحتمل أن تكون جزءا من جافا 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
, ، لذلك لا يمكن تغييره.
وهو ما تريده في معظم الحالات التي تقوم بملءها مسبقًا.
جافا 8 أو أقدم:
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
س
لماذا يجب أن يكون أ 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;
List<String> strings = Stream.of("foo", "bar", "baz").collect(toList());
لكن من الأفضل أن تستخدم فقط Stream
دون جمعها إلى أ List
.
اذا أنت حقًا بحاجة على وجه التحديد أ java.util.ArrayList
(ربما لا تفعل ذلك.)
يقتبس جيب 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
}
مثال آخر سيكون دائمًا الإعلان عن المتغير an 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");
والحرفية مجموعة لم جعله جافا 8، ولكن من الممكن استخدام 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 - 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")
الذي يشبه اقتراح جمع الحرف كما ذكر @coobird أيضًا.مزيد من التوضيح في مستند JEP أيضًا -
البدائل
تم النظر في تغييرات اللغة عدة مرات، وتم رفضها:
اقتراح عملة المشروع، 29 مارس 2009
اقتراح عملة المشروع، 30 مارس 2009
مناقشة JEP 186 حول lambda-dev، يناير-مارس 2014
تم تخصيص مقترحات اللغة جانباً لتفضيل اقتراح قائم على المكتبة كما هو ملخص في هذا رسالة.
ذات صلة => ما هو الهدف من أساليب مصنع الراحة المثقلة للمجموعات في 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؟
مع مجموعات الكسوف يمكنك كتابة ما يلي:
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.
وحول الطريقة الأكثر المدمجة للقيام بذلك هي:
Double array[] = { 1.0, 2.0, 3.0};
List<Double> list = Arrays.asList(array);
وهنا طريقة أخرى:
List<String> values = Stream.of("One", "Two").collect(Collectors.toList());
وببساطة استخدام رمز أدناه على النحو التالي.
List<String> list = new ArrayList<String>() {{
add("A");
add("B");
add("C");
}};
ويمكنك استخدام البيانات التالية:
مقتطف الشفرة:
String [] arr = {"Sharlock", "Homes", "Watson"};
List<String> names = Arrays.asList(arr);
و(يجب أن يكون للتعليق، ولكن وقتا طويلا، والرد الجديد نحو ذلك). كما ذكر آخرون، يتم إصلاح طريقة 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))
وربما هذا هو أفضل طريقة للذهاب نحو القيام بذلك، وإسبانيا. إذا كنت بحاجة إلى لائحة غير محدود أو تحتاج إلى استخدام الميراث.
وكما قلت توم :
List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
ولكن منذ أن اشتكى من الرغبة في ArrayList، يجب أن نعرف أولا أن ArrayList هو فئة فرعية من قائمة ويمكن ببساطة إضافة هذا السطر:
ArrayList<String> myPlaces = new ArrayList(places);
وعلى الرغم من أن قد تجعلك يشكون من "الأداء".
في هذه الحالة فإنه لا معنى له بالنسبة لي، لماذا، لأن محددة مسبقا قائمتك لم يتم تعريف على أنها مجموعة (منذ حجم هو معروف في وقت initialisation). وإذا كان هذا هو خيار لك:
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 الخاص بك.
وP.S. أظهرت Randyaa طريقة أخرى لطيفة باستخدام طريقة فائدة ثابت <لأ href = "http://docs.oracle.com/javase /1.5.0/docs/api/java/util/Collections.html "يختلط =" نوفولو noreferrer "> Collections.addAll .
وجافا 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");
ويمكنك استخدام StickyList
من Cactoos :
List<String> names = new StickyList<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
);
وحاول مع هذا الخط كود:
Collections.singletonList(provider)
ونعم بمساعدة صالحة يمكنك تهيئة قائمة مجموعة في سطر واحد،
List<String> strlist= Arrays.asList("aaa", "bbb", "ccc");
في جاوة، لا يمكنك أن تفعل
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")
.
وأيضا وفقا لجافادوك يجب أن تكون قادرة على القيام بذلك:
List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
ولكن أنا لست قادرا على الحصول عليه للترجمة مع JDK 1.6.
Collections.singletonList(messageBody)
إذا كنت بحاجة إلى قائمة شيء واحد!
المجموعات انه من 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);
}
}
ومجرد إنشاء وظيفة يمكن أن يكون لها العديد من العناصر على النحو الذي تريد والذي يطلق عليه لإضافتها في سطر واحد.
وهنا هو رمز بواسطة 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
وبالنسبة لي Arrays.asList () هو أفضل ومريحة واحد. أحب دائما لتهيئة بهذه الطريقة. إذا كنت مبتدئا في مجموعات جافا ثم أود منك أن أشير 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");
وأنا إنشاء قائمة من messageTemplate من ملف xml المخزنة في مسار قبل في سياق ثابت
public final class TemplateStore {
private TemplateStore(){}
private static final String [] VERSIONS = {"081"};
private static final String TEMPLATE_FILE_MASK = "template/EdiTemplates_v%s.xml";
private static final String ERROR = "Error In Building Edifact Message Template Store";
public static final List<MessageTemplate> TEMPLATE_LIST = Arrays.stream(VERSIONS)
.map(version -> TemplateStore.class
.getClassLoader().getResourceAsStream(String.format(TEMPLATE_FILE_MASK, version)))
.map(inputStream -> {
try {
return ((EdiTemplates) JAXBContext.newInstance(EdiTemplates.class).createUnmarshaller()
.unmarshal(inputStream)).getMessageTemplate();
} catch (JAXBException e) {
throw new IllegalArgumentException(ERROR, e);
}})
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
والواقع، فمن الممكن أن تفعل ذلك في سطر واحد:
Arrays.asList(new MyClass[] {new MyClass("arg1"), new MyClass("arg2")})