Java SE 9 مجموعهای از متدهای کارخانهای (Factory Methods) را به رابطههای List و Set برای ایجاد لیستها و مجموعهها اضافه کرد. الگو بسیار ساده است: کافی است متد استاتیک List.of() یا Set.of() را فراخوانی کنید و عناصر را ارسال کنید.
خروجی این کد:
String list: [one, two, three]
String set : [one, three, two]
نکات قابل توجهی وجود دارد:
پیادهسازیای که برمیگردانید بسته به تعداد عناصر متفاوت خواهد بود. هیچکدام ArrayList یا HashSet نیستند. کد شما نباید فراتر از رابطههای پایهای List و Set وابسته باشد.
لیست و مجموعهای که دریافت میکنید ساختارهای غیرقابل تغییر (unmodifiable) هستند. نمیتوانید عنصری به آنها اضافه یا حذف کنید و نمیتوانید عناصرشان را تغییر دهید. البته اگر اشیاء داخل این ساختارها mutable باشند، میتوانید خود آن اشیاء را تغییر دهید.
این ساختارها مقدار null نمیپذیرند. اگر سعی کنید مقدار null اضافه کنید، exception دریافت خواهید کرد.
رابطهی Set تکرار را ممنوع میکند. چون ساختن Set با مقادیر تکراری معنایی ندارد، تلاش برای این کار بهعنوان bug در نظر گرفته میشود و exception دریافت خواهید کرد.
پیادهسازیهایی که دریافت میکنید Serializable هستند.
این متدهای of() معمولاً با نام convenience factory methods for collections شناخته میشوند.
پس از موفقیت متدهای کارخانهای کلکشنها، مجموعهی دیگری از متدهای راحت در Java SE 10 اضافه شدند تا کپیهای غیرقابل تغییر از کلکشنها ایجاد کنند.
دو متد وجود دارد: List.copyOf() و Set.copyOf(). هر دو الگوی یکسانی دارند:
خروجی این کد:
List: [one, two, three]
Set: [two, one, three]
در همهی موارد، کلکشنی که قرار است کپی شود نباید null باشد و نباید شامل عناصر null باشد. اگر این کلکشن تکرار داشته باشد، در مورد Set.copyOf() فقط یکی از آنها نگه داشته میشود.
آنچه برمیگردانید، یک کپی غیرقابل تغییر از کلکشن ارسالی است. بنابراین تغییر کلکشن اصلی در لیست یا مجموعهی کپیشده منعکس نمیشود.
هیچکدام از پیادهسازیهای برگشتی مقدار null را نمیپذیرند. اگر سعی کنید کلکشنی با مقادیر null کپی کنید، خطای NullPointerException دریافت خواهید کرد.
Collections Framework کلاسی به نام Arrays با حدود ۲۰۰ متد برای مدیریت آرایهها دارد. بیشتر آنها الگوریتمهای مختلف روی آرایهها مانند مرتبسازی، ادغام و جستجو را پیادهسازی میکنند و در این بخش پوشش داده نمیشوند.
اما یک متد ارزشمند وجود دارد: Arrays.asList(). این متد یک vararg دریافت میکند و یک List از عناصر ارسالی با حفظ ترتیب برمیگرداند. این متد جزو convenience factory methods نیست اما بسیار مفید است.
List برگشتی بهعنوان wrapper روی یک آرایه عمل میکند و رفتاری مشابه آن دارد. ممکن است در نگاه اول کمی گیجکننده باشد. وقتی سایز یک آرایه مشخص شد، دیگر قابل تغییر نیست. یعنی نمیتوانید عنصری اضافه یا حذف کنید. تنها کاری که میتوانید انجام دهید جایگزینی یک عنصر موجود با عنصر دیگر است.
List برگشتی از Arrays.asList() دقیقاً همین کار را انجام میدهد:
UnsupportedOperationException دریافت خواهید کرد، چه مستقیماً و چه از طریق iterator.بنابراین این لیست غیرقابل تغییر نیست، اما محدودیتهایی در نحوهی تغییر آن وجود دارد.
Collections Framework یک کلاس کارخانهای دیگر هم دارد: Collections، با مجموعهای از متدها برای مدیریت کلکشنها و محتوایشان. حدود ۷۰ متد در این کلاس وجود دارد که بررسی تکتک آنها خستهکننده خواهد بود. بنابراین بخشی از آنها را معرفی میکنیم.
کلاس Collections دو متد برای این کار ارائه میدهد: min() و max(). هر دو کلکشن را بهعنوان آرگومان دریافت میکنند و هر دو نسخهی overloaded دیگری هم دارند که یک comparator اضافی دریافت میکند.
اگر comparator ارسال نشود، عناصر کلکشن باید رابطهی Comparable را پیادهسازی کرده باشند. در غیر این صورت خطای ClassCastException پرتاب میشود. اگر comparator ارسال شود، از آن برای تعیین min یا max استفاده میشود.
فراخوانی این متدها روی کلکشن خالی خطای
NoSuchElementExceptionپرتاب میکند.
دو متد برای مکانیابی یک زیرلیست در یک لیست بزرگتر وجود دارد:
indexOfSubList(List<?> source, List<?> target): اولین ایندکس اولین عنصر لیست target در لیست source را برمیگرداند، یا اگر وجود نداشته باشد -1 برمیگرداندlastIndexOfSublist(List<?> source, List<?> target): آخرین ایندکس از این ایندکسها را برمیگرداندچندین متد برای تغییر ترتیب عناصر یک لیست وجود دارد:
sort() لیست را بهصورت درجا مرتب میکند. این متد میتواند یک comparator بهعنوان آرگومان دریافت کند. اگر comparator ارسال نشود، عناصر لیست باید comparable باشند. از Java SE 8 به بعد توصیه میشود از متد sort() رابطهی List استفاده کنید.shuffle() عناصر لیست را بهصورت تصادفی درهمریزی میکند. میتوانید نمونهی Random خود را ارسال کنید اگر به شلوغسازی تکرارپذیر نیاز دارید.rotate() عناصر لیست را میچرخاند. پس از چرخش، عنصری که در ایندکس ۰ بود در ایندکس ۱ قرار میگیرد و به همین ترتیب. عناصر آخر به ابتدای لیست منتقل میشوند. میتوانید subList() و rotate() را ترکیب کنید تا عنصری را از یک ایندکس حذف و در جای دیگری درج کنید:خروجی:
[0, 1, 2, 3, 4]
[0, 2, 3, 1, 4]
عنصر موجود در ایندکس fromIndex از جای خود حذف شده، لیست متناسب با آن بازآرایی شده و عنصر در ایندکس toIndex - 1 درج شده است.
کلاس کارخانهای Collections چندین متد برای ایجاد wrapperهای غیرقابل تغییر برای کلکشنها یا نقشهها (Maps) ارائه میدهد. محتوای ساختار کپی نمیشود؛ آنچه دریافت میکنید یک wrapper دور ساختار شماست. تمام تلاشها برای تغییر آن exception پرتاب میکنند.
همهی این متدها با unmodifiable شروع میشوند و به نام نوع ساختار ختم میشوند. مثلاً برای ایجاد یک wrapper غیرقابل تغییر از یک لیست:
خروجی این کد:
Strings: [0, 1, 2, 3, 4]
Unmodifiable strings: [0, 1, 2, 3, 4]
یک نکتهی مهم: تغییر کلکشن برگشتی از این متدها غیرممکن است. اما این wrapper بر اساس کلکشن ارسالی به متدهای کارخانهای ساخته شده است. پس اگر کلکشن اصلی قابل تغییر باشد و شما آن را تغییر دهید، این تغییر در wrapper هم منعکس میشود.
بیایید این موضوع را در کد زیر ببینیم:
خروجی این مثال:
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
اگر قصد دارید از این الگو برای ایجاد کلکشن غیرقابل تغییر استفاده کنید، انجام یک Defensive Copy در ابتدا اقدام احتیاطی مناسبی است.
دقیقاً مثل wrapperهای غیرقابل تغییر، کلاس کارخانهای Collections میتواند wrapperهای همگامسازیشده (Synchronized) هم ایجاد کند. نامگذاری متدها مشابه wrapperهای غیرقابل تغییر است: با synchronized شروع میشوند و به Collection، List، Set و غیره ختم میشوند.
دو اقدام احتیاطی لازم است:
رعایت نکردن این قوانین کد شما را در معرض Race Condition قرار میدهد.
همگامسازی کلکشنها با متدهای کارخانهای Collections ممکن است بهترین انتخاب شما نباشد. فریمورک Java Util Concurrent (در پکیج java.util.concurrent) راهحلهای بهتری ارائه میدهد.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/