تسلط بر Java Collections

بسیاری از توسعه‌دهندگان به طور پیش‌فرض از ArrayList یا HashSet استفاده می‌کنند. این کار برای وظایف ساده جواب می‌دهد، اما زمانی که به سرعت یا مقیاس‌پذیری نیاز دارید، شکست می‌خورد.

من زمانی یک جدول امتیازات بازی را با استفاده از یک ArrayList ساده ساختم. هر بار که امتیازی تغییر می‌کرد، آن را مرتب می‌کردم. رابط کاربری (UI) مدام فریز می‌شد. من به جای استفاده از زبان، در حال جنگیدن با آن بودم.

استفاده از ابزارهای اشتباه را متوقف کنید. از این سه مجموعه (collection) تخصصی برای نوشتن کدی سریع‌تر و تمیزتر استفاده کنید.

۱. EnumSet برای ثابت‌های Enum

اگر از HashSet برای enumها استفاده کنید، هزینه‌ی عملکردی (performance tax) پرداخت می‌کنید. هر درج (insertion)، enum را در یک شیء بسته‌بندی (box) می‌کند. این کار سربار غیرضروری ایجاد می‌کند.

EnumSet از یک بردار بیت (bit vector) استفاده می‌کند. این مجموعه بررسی‌ها را با استفاده از یک دستور واحد CPU انجام می‌دهد.

Before: Set<Ability> abilities = new HashSet<>(); abilities.add(Ability.FIRE);

After: EnumSet<Ability> abilities = EnumSet.of(Ability.FIRE);

۲. NavigableSet برای پرس‌وجوهای بازه‌ای (Range Queries)

پیمایش دستی در یک لیست مرتب‌شده برای یافتن یک بازه، کند و مستعد خطا است. اغلب با باگ‌های off-by-one مواجه می‌شوید.

NavigableSet داده‌های شما را به طور خودکار مرتب نگه می‌دارد. این مجموعه جستجوهای زیرمجموعه (subsets) را با پیچیدگی O(log n) انجام می‌دهد.

Before: Collections.sort(scores); List<Integer> topTen = scores.subList(size - 10, size);

After: NavigableSet<Integer> scores = new TreeSet<>(Comparator.reverseOrder()); scores.add(1542); NavigableSet<Integer> topTen = scores.headSet(scores.first(), true).stream().limit(10).collect(Collectors.toCollection(TreeSet::new));

۳. CopyOnWriteArrayList برای لیست‌های با خواندن بالا (Read-Heavy)

استفاده از بلوک‌های synchronized روی یک ArrayList، سرعت هر عملیات خواندن را کاهش می‌دهد. همچنین اگر یک رشته (thread) در حال نوشتن باشد و رشته دیگری در حال خواندن، باعث بروز ConcurrentModificationException می‌شود.

CopyOnWriteArrayList با هر بار نوشتن، یک کپی جدید از آرایه ایجاد می‌کند. خواننده‌ها به یک تصویر لحظه‌ای (snapshot) از آرایه نگاه می‌کنند.

Before: List<String> log = Collections.synchronizedList(new ArrayList<>()); // Iterating here can crash if a writer joins in.

After: CopyOnWriteArrayList<String> log = new CopyOnWriteArrayList<>(); // Iteration is safe and never crashes.

دیگر به طور پیش‌فرض از همان دو کالکشن استفاده نکنید. ابزاری را انتخاب کنید که با الگوی داده‌های شما همخوانی داشته باشد.

منبع: https://dev.to/timevolt/the-java-collections-force-mastering-the-hidden-gems-like-a-jedi-4438