JavaJava · Chapterبەش 11 · Lectureوانە 11.1

HashMap and HashSetHashMap و HashSet

Find a value by its key: HashMap with put, get, getOrDefault, containsKey, remove and size, loops over keySet, values and entrySet, and counting with a map. Why a HashMap promises no order, and what TreeMap and LinkedHashMap do instead. HashSet keeps each element once: add returns false for a duplicate, contains checks quickly, and retainAll, addAll and removeAll give intersection, union and difference. How hashing picks a bucket, why keys need equals and hashCode, and the traps: null from get, unboxing null, removing inside a for-each loop.

بە بدۆزەرەوە: HashMap بە put، get، getOrDefault، containsKey، remove و size، سووڕانەوە بەسەر keySet، values و entrySetـدا و ژماردن بە . بۆچی HashMap بەڵێنی هیچ ڕیزبەندییەک نادات و TreeMap و LinkedHashMap لە جیاتی ئەوە چی دەکەن. HashSet هەر یەک جار هەڵدەگرێت: add بۆ دووپاتە false دەگەڕێنێتەوە، contains بە خێرایی دەپشکنێت و retainAll، addAll و removeAll ، و دەدەن. هاشکردن چۆن شوێنێک هەڵدەبژێرێت، بۆچی پێویستیان بە equals و hashCode هەیە و تەڵەکان: null لە getـەوە، کردنەوەی null، لابردن لە ناو .

22 min read20 خولەک خوێندنەوە · 22 stepsهەنگاو

What you will learnچی فێر دەبیت

  • Store key–value pairs in a HashMap and use put, get, getOrDefault, containsKey, remove and size.
  • Loop over a map with keySet, values and entrySet, and explain why a HashMap's order is not guaranteed.
  • Count things with a HashMap<String, Integer> and avoid the null traps of get.
  • Keep unique elements in a HashSet and use add, contains, remove and the set operations.
  • Explain how hashing finds a key quickly and why keys need matching equals and hashCode.
  • لە HashMapـێکدا هەڵبگریت و put، get، getOrDefault، containsKey، remove و size بەکار بهێنیت.
  • بە keySet، values و entrySet بەسەر بسووڕێیتەوە و ڕوونی بکەیتەوە بۆچی ڕیزبەندیی HashMap بەڵێن نادرێت.
  • بە ⁦HashMap<String, Integer>⁩ شتەکان بژمێریت و خۆت لە تەڵەکانی nullـی get بپارێزیت.
  • بێ دووپاتە لە HashSetـێکدا هەڵبگریت و add، contains، remove و بەکار بهێنیت.
  • ڕوونی بکەیتەوە هاشکردن چۆن بە خێرایی دەدۆزێتەوە و بۆچی پێویستیان بە equals و hashCodeـی گونجاو هەیە.

Find a value by its keyنرخ بە کلیلەکەی بدۆزەرەوە

A list finds an element by its position: names.get(2) is the third name. Often you know something else: a word, a name, a student number. A Kurdish–English word list works that way. You look up کتێب and read book; you never ask for "word number 37". The word you know is the , the word you get is the , and the two together make a .

بە شوێنەکەی دەدۆزێتەوە: names.get(2) ناوی سێیەمە. زۆرجار شتێکی ترت لەلایە: وشەیەک، ناوێک، ژمارەی قوتابییەک. لیستێکی وشەی کوردی و ئینگلیزی بەم شێوەیە کار دەکات: بەدوای کتێبدا دەگەڕێیت و book دەخوێنیتەوە؛ هەرگیز داوای «وشەی ژمارە ⁦37⁩» ناکەیت. ئەو وشەیەی دەیزانیت ، ئەوەی وەریدەگریت و هەردووکیان پێکەوە پێک دەهێنن.

A word list drawn as a page, HashMap<String, String> words. Four rows, each a key and a value joined by an arrow: کتێب to "book", قوتابخانە to "school", مامۆستا to "teacher", پەنجەرە to "window". On the right, words.get("مامۆستا") points straight at its row and gives "teacher". Notes: each key appears only once; values may repeat; no searching row by row.لیستێکی وشە وەک لاپەڕەیەک، HashMap<String, String> words. چوار ڕیز، هەر یەکەیان کلیلێک و نرخێک کە بە تیرێک بەستراون: کتێب بۆ "book"، قوتابخانە بۆ "school"، مامۆستا بۆ "teacher"، پەنجەرە بۆ "window". لای ڕاست words.get("مامۆستا") ڕاستەوخۆ ئاماژە بە ڕیزەکەی دەکات و "teacher" دەدات. تێبینییەکان: هەر کلیلێک تەنیا یەک جار دێت؛ نرخەکان دەتوانن دووپاتە ببنەوە؛ گەڕانی ڕیز بە ڕیز نییە.
One row = one key–value pairهەر ڕیزێک = CêIT

Java keeps such pairs in a Map, and the one used most is HashMap from java.util. In general the idea is called an ; Python calls it a dictionary (Dictionaries).

Java ئەم جووتانە لە Mapـێکدا هەڵدەگرێت و بەکارهاتووترینیان HashMapـە لە java.util. بە گشتی ئەم بیرۆکەیە پێی دەوترێت ؛ Python پێی دەڵێت (فەرهەنگەکان).

Creating a HashMap: put and getدروستکردنی ⁦HashMap: put⁩ و get

HashMap is in java.util, so it needs an import (import). In angle brackets you give two types: first the key type, then the value type. put(key, value) stores a pair, get(key) gives the value back and size() counts the pairs:

HashMap لە java.utilـدایە، بۆیە importـی پێویستە (import). لە ناو کەوانەی ⁦< >⁩ـدا دوو جۆر دەنووسیت: سەرەتا جۆری ، پاشان جۆری . put(key, value) جووتێک هەڵدەگرێت، get(key) دەگەڕێنێتەوە و size() جووتەکان دەژمێرێت:

WordList.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class WordList {
    public static void main(String[] args) {
        HashMap<String, String> words = new HashMap<>();
        words.put("کتێب", "book");
        words.put("قوتابخانە", "school");
        words.put("مامۆستا", "teacher");
        System.out.println(words.get("کتێب"));
        System.out.println(words.get("مامۆستا"));
        System.out.println(words.size() + " pairs");
        System.out.println(words);
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 5

Keys are Strings and values are Strings: HashMap<String, String>.

Stringـن و Stringـن: HashMap<String, String>.

Lineدێڕی 6-8

Three put calls store three pairs.

سێ بانگکردنی put سێ جووت هەڵدەگرن.

Lineدێڕی 12

Printing the whole map shows each pair as key=value.

چاپکردنی هەموو هەر جووتێک وەک key=value پیشان دەدات.

The line HashMap<String, String> words = new HashMap<>(); under import java.util.HashMap;, split into parts: HashMap, the class from java.util; the first String, the key type, a class and never int; the second String, the value type, a class too; words, the variable; new HashMap<>(), a new, empty map, where <> means the same types. Note: read it as: words is a map from String keys to String values.دێڕی HashMap<String, String> words = new HashMap<>(); لە ژێر import java.util.HashMap;، کە بەسەر بەشەکاندا دابەش کراوە: HashMap، کلاسەکە لە java.util؛ یەکەم String، جۆری کلیل، کلاسێک و هەرگیز int؛ دووەم String، جۆری نرخ، ئەویش کلاسێک؛ words، گۆڕاوەکە؛ new HashMap<>()، ڕیزەکێکی پەیوەندیداری نوێی بەتاڵ، کە <> واتە هەمان جۆرەکان.
Two types: the key type, then the value typeدوو جۆر: جۆری ، پاشان جۆری CêIT

Two things to notice. The printed order is not the order of the put calls; The order is not guaranteed explains why. And the keys are Kurdish words, so on Windows with JDK 17 compile this file with javac -encoding UTF-8 (Kurdish source files).

سەرنجی دوو شت بدە. ڕیزبەندیی چاپکراو ڕیزی بانگکردنەکانی put نییە؛ ڕیزبەندی بەڵێن نادرێت هۆکارەکەی ڕوون دەکاتەوە. هەروەها وشەی کوردین، بۆیە لە Windows بە ⁦JDK 17⁩ ئەم بە javac -encoding UTF-8 کۆمپایل بکە (فایلەکانی کۆدی سەرچاوەی کوردی).

Creating a HashMap: put and getدروستکردنی ⁦HashMap: put⁩ و get

A key that is not thereکلیلێک کە نییە

get with a key that is not in the map does not stop the program: it returns null, Java's "no value" (null). getOrDefault(key, other) returns other instead. containsKey and containsValue only ask whether the key or the value is there:

get بە کە لە نییە ناوەستێنێت: null دەگەڕێنێتەوە، واتە «هیچ »ـی Java (null). getOrDefault(key, other) لە جیاتی ئەوە other دەگەڕێنێتەوە. containsKey و containsValue تەنیا دەپرسن ئایا یان هەیە:

MissingKey.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class MissingKey {
    public static void main(String[] args) {
        HashMap<String, String> words = new HashMap<>();
        words.put("کتێب", "book");
        words.put("مامۆستا", "teacher");
        System.out.println(words.get("پەنجەرە"));
        System.out.println(words.getOrDefault("پەنجەرە", "(not in the list)"));
        System.out.println(words.containsKey("کتێب"));
        System.out.println(words.containsKey("پەنجەرە"));
        System.out.println(words.containsValue("teacher"));
    }
}
The map words with two pairs, کتێب to "book" and مامۆستا to "teacher". پەنجەرە is not a key here. Four calls: words.get("پەنجەرە") gives null, nothing found; words.getOrDefault("پەنجەرە", "-") gives "-", your own answer instead of null; words.containsKey("پەنجەرە") gives false; words.containsKey("کتێب") gives true.ڕیزەکی پەیوەندیداری words بە دوو جووت، کتێب بۆ "book" و مامۆستا بۆ "teacher". پەنجەرە لێرە کلیل نییە. چوار بانگکردن: words.get("پەنجەرە") null دەدات، هیچ نەدۆزرایەوە؛ words.getOrDefault("پەنجەرە", "-") "-" دەدات، وەڵامی خۆت لە جیاتی null؛ words.containsKey("پەنجەرە") false دەدات؛ words.containsKey("کتێب") true دەدات.
A missing key: null, your default, or a yes/no question first نەبوو: null، وەڵامی خۆت، یان سەرەتا پرسیارێکی بەڵێ و نەخێرCêIT

Changing a map: put again, remove, clearگۆڕینی ڕیزەکێکی پەیوەندیدار: put دووپاتە، remove، clear

A key appears only once. put with a key that is already there replaces its value and returns the old value, so size() stays the same. remove(key) takes the whole pair away and returns its value, or null when the key was not there. clear() removes every pair and isEmpty() asks whether anything is left:

هەر تەنیا یەک جار دێت. put بە کە پێشتر هەیە دەگۆڕێتەوە و کۆن دەگەڕێنێتەوە، بۆیە size() وەک خۆی دەمێنێت. remove(key) هەموو جووتەکە لادەبات و دەگەڕێنێتەوە، یان null ئەگەر نەبووبێت. clear() هەموو جووتەکان لادەبات و isEmpty() دەپرسێت ئایا بەتاڵە:

ChangeWords.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class ChangeWords {
    public static void main(String[] args) {
        HashMap<String, String> words = new HashMap<>();
        words.put("کتێب", "book");
        words.put("پێنووس", "pencil");
        words.put("پەنجەرە", "window");
        String old = words.put("پێنووس", "pen");      // the same key again: the value is replaced
        System.out.println("old: " + old + ", now: " + words.get("پێنووس"));
        System.out.println("size: " + words.size());
        String removed = words.remove("پەنجەرە");
        System.out.println("removed: " + removed + ", size: " + words.size());
        System.out.println(words.remove("پەنجەرە"));  // not there any more
        words.clear();
        System.out.println("empty? " + words.isEmpty());
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 9

پێنووس means pen: the second put fixes the value and returns the old one.

پێنووس واتە pen: putـی دووەم ڕاست دەکاتەوە و کۆنەکە دەگەڕێنێتەوە.

Three stages of the same map. Start: کتێب to "book", پێنووس to "pencil", پەنجەرە to "window", size() 3. After words.put("پێنووس", "pen"): the row پێنووس now holds "pen", size() still 3, and the call returns the old value "pencil". After words.remove("پەنجەرە"): that row is gone (dashed and crossed), size() 2, and the call returns the value it removed, "window".سێ قۆناغی هەمان ڕیزەکی پەیوەندیدار. سەرەتا: کتێب بۆ "book"، پێنووس بۆ "pencil"، پەنجەرە بۆ "window"، size() 3. دوای words.put("پێنووس", "pen"): ڕیزی پێنووس ئێستا "pen"ـی تێدایە، size() هێشتا 3ـە و بانگکردنەکە نرخی کۆن "pencil" دەگەڕێنێتەوە. دوای words.remove("پەنجەرە"): ئەو ڕیزە نەماوە (پچڕپچڕ و خەتلێدراو)، size() 2ـە و بانگکردنەکە ئەو نرخەی لایبرد دەیگەڕێنێتەوە، "window".
put replaces; remove takes the pair awayput دەیگۆڕێتەوە؛ remove جووتەکە لادەباتCêIT

Looping over a map: keySet, values, entrySetسووڕانەوە بەسەر ڕیزەکێکی پەیوەندیداردا: keySet، values، entrySet

A map has no index, so a counting for loop does not work. Ask the map for a collection and loop over it with a for-each loop (for-each): keySet() gives the keys, values() the values and entrySet() the pairs. Each pair is a Map.Entry with getKey() and getValue():

نییە، بۆیە forـی ژماردن کار ناکات. داوای کۆکراوەیەک لە بکە و بە بەسەریدا بسووڕێوە (خولی foreach): keySet() دەدات، values() و entrySet() جووتەکان. هەر جووتێک Map.Entryـێکە بە getKey() و getValue():

LoopWords.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;
import java.util.Map;

public class LoopWords {
    public static void main(String[] args) {
        HashMap<String, String> words = new HashMap<>();
        words.put("کتێب", "book");
        words.put("قوتابخانە", "school");
        words.put("مامۆستا", "teacher");
        for (String key : words.keySet()) {
            System.out.println("key: " + key);
        }
        for (String value : words.values()) {
            System.out.println("value: " + value);
        }
        for (Map.Entry<String, String> pair : words.entrySet()) {
            System.out.println(pair.getKey() + " = " + pair.getValue());
        }
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 16

Map.Entry<String, String>: one key–value pair.

Map.Entry<String, String>: یەک .

The map words with three pairs and three ways out of it. keySet() gives the keys, a Set: کتێب, مامۆستا, قوتابخانە. values() gives the values, a Collection that may hold repeats: "book", "teacher", "school". entrySet() gives the pairs, each with getKey() and getValue(): کتێب=book, مامۆستا=teacher, قوتابخانە=school.ڕیزەکی پەیوەندیداری words بە سێ جووت و سێ ڕێگەی دەرچوون لێی. keySet() کلیلەکان دەدات، کۆمەڵەیەک: کتێب، مامۆستا، قوتابخانە. values() نرخەکان دەدات، کۆکراوەیەک کە دەکرێت دووپاتەی تێدا بێت: "book"، "teacher"، "school". entrySet() جووتەکان دەدات، هەر یەکەیان بە getKey() و getValue(): کتێب=book، مامۆستا=teacher، قوتابخانە=school.
Keys, values or whole pairs، یان جووتی تەواوCêIT

When you need both parts, loop over entrySet(). A loop over keySet() that calls get(key) for every key also works, but it looks every key up a second time.

کاتێک هەردوو بەشت پێویستە، بەسەر entrySet()ـدا بسووڕێوە. بەسەر keySet()ـدا کە بۆ هەر get(key) بانگ دەکات کاریش دەکات، بەڵام بۆ هەر جارێکی تر لە دەگەڕێت.

The order is not guaranteedڕیزبەندی بەڵێن نادرێت

A HashMap keeps each pair in a place that its hashing chooses (How a HashMap finds a key), not in the order you put the pairs in. The Java API says that the class makes no guarantee about the order, and that the order may not stay the same over time:

HashMap هەر جووتێک لەو شوێنەدا هەڵدەگرێت کە هاشکردنەکەی هەڵیدەبژێرێت (HashMap چۆن کلیلێک دەدۆزێتەوە)، نەک بەو ڕیزەی جووتەکانی پێ دەخەیتە ناوەوە. APIـی Java دەڵێت ئەم هیچ گەرەنتییەک لەسەر ڕیزبەندی نادات و ڕیزبەندییەکە لەوانەیە بە تێپەڕبوونی کات وەک خۆی نەمێنێت:

HomeTowns.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class HomeTowns {
    public static void main(String[] args) {
        HashMap<String, String> home = new HashMap<>();
        home.put("Aram", "Hawler");
        home.put("Shilan", "Slemani");
        home.put("Karwan", "Duhok");
        home.put("Dilan", "Halabja");
        home.put("Rebin", "Zakho");
        System.out.println(home);
    }
}
Top: the order of put(), Aram, Shilan, Karwan, Dilan, Rebin, and the printed order, Aram, Rebin, Shilan, Dilan, Karwan. Bottom: a map of 12 keys prints Zhilwan first; after marks.put("Sirwan", 70), the 13th key, the map grows from 16 to 32 buckets and prints Aram, Kawa, Rebin, Soran, Shilan, Bawan, Lana, Hana, Karwan, Zhilwan, Sirwan, Dilan, Narin. Zhilwan, Dilan and Narin are marked. Note: never count on the order of a HashMap.سەرەوە: ڕیزی put()، Aram، Shilan، Karwan، Dilan، Rebin و ڕیزی چاپکراو، Aram، Rebin، Shilan، Dilan، Karwan. خوارەوە: ڕیزەکێکی پەیوەندیدار بە 12 کلیل Zhilwan یەکەم چاپ دەکات؛ دوای marks.put("Sirwan", 70)، کلیلی سێزدەیەم، ڕیزەکە پەیوەندیدارەکە لە 16 شوێنەوە دەبێتە 32 و چاپ دەکات Aram، Kawa، Rebin، Soran، Shilan، Bawan، Lana، Hana، Karwan، Zhilwan، Sirwan، Dilan، Narin. Zhilwan، Dilan و Narin نیشانە کراون. تێبینی: هەرگیز پشت بە ڕیزبەندیی HashMap مەبەستە.
Put order, printed order, and the order after the map growsڕیزی put، ڕیزی چاپکراو و ڕیزبەندی دوای گەورەبوونی CêIT

Shilan was put in second but printed third, and Rebin, put in last, was printed second. The lower half of the picture shows a stronger surprise from the next screen: the order changes while the program runs.

Shilan دووەم خرایە ناوەوە بەڵام سێیەم چاپ کرا و Rebin کە دوایین بوو دووەم چاپ کرا. نیوەی خوارەوەی وێنەکە سەرسوڕمانێکی گەورەتر لە پەڕەی داهاتوو پیشان دەدات: ڕیزبەندییەکە لە کاتی کارکردنی دەگۆڕێت.

The order is not guaranteedڕیزبەندی بەڵێن نادرێت

The order can even changeڕیزبەندییەکە دەتوانێت بگۆڕێت

Here twelve names go into a map, then a thirteenth. A HashMap starts with 16 buckets and doubles them when it is three quarters full (12 pairs), so the 13th put builds a bigger table and every key gets a new place:

لێرە دوازدە ناو دەچنە ناو ، پاشان سێزدەیەم. HashMap بە ⁦16⁩ شوێن دەست پێ دەکات و کاتێک سێ چارەکی پڕ بوو (⁦12⁩ جووت) دوو هێندەیان دەکات، بۆیە putـی سێزدەیەم گەورەتر دروست دەکات و هەموو شوێنێکی نوێ وەردەگرێت:

OrderChanges.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class OrderChanges {
    public static void main(String[] args) {
        String[] names = {"Aram", "Shilan", "Karwan", "Dilan", "Rebin", "Hana",
                          "Soran", "Lana", "Kawa", "Narin", "Bawan", "Zhilwan"};
        HashMap<String, Integer> marks = new HashMap<>();
        for (String name : names) {
            marks.put(name, 70);
        }
        System.out.println(marks.keySet());
        marks.put("Sirwan", 70);          // the 13th key: the map makes itself bigger
        System.out.println(marks.keySet());
    }
}

Zhilwan was printed first and is tenth now; Dilan and Narin moved to the end. Nothing is wrong: the map never promised an order. A program that needs an order must choose a map that keeps one (next screen) or sort the keys itself.

Zhilwan یەکەم جار چاپ کرا و ئێستا دەیەمە؛ Dilan و Narin چوونە کۆتایی. هیچ هەڵەیەک نییە: هەرگیز بەڵێنی ڕیزبەندیی نەدابوو. کە ڕیزبەندیی پێویستە دەبێت هەڵبژێرێت کە ڕیزبەندی دەپارێزێت (پەڕەی داهاتوو) یان خۆی ڕیز بکات.

The order is not guaranteedڕیزبەندی بەڵێن نادرێت

When order matters: TreeMap and LinkedHashMapکاتێک ڕیزبەندی گرنگە: TreeMap و LinkedHashMap

Java has two more maps with the same methods. A TreeMap keeps its keys sorted (A to Z for Strings); a LinkedHashMap keeps the order in which keys were first put in. The method fill puts the same five pairs into all three:

Java دوو تری هەیە بە هەمان . TreeMap ڕیزکراو دەهێڵێتەوە (لە A تا Z بۆ Stringـەکان)؛ LinkedHashMap ئەو ڕیزە دەپارێزێت کە یەکەم جار پێی خرانە ناوەوە. fill هەمان پێنج جووت دەخاتە ناو هەر سێکیانەوە:

ThreeOrders.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

public class ThreeOrders {
    static void fill(Map<String, String> m) {
        m.put("Shilan", "Slemani");
        m.put("Aram", "Hawler");
        m.put("Rebin", "Zakho");
        m.put("Dilan", "Halabja");
        m.put("Karwan", "Duhok");
    }

    public static void main(String[] args) {
        Map<String, String> hash = new HashMap<>();
        Map<String, String> tree = new TreeMap<>();
        Map<String, String> linked = new LinkedHashMap<>();
        fill(hash);
        fill(tree);
        fill(linked);
        System.out.println("HashMap:       " + hash);
        System.out.println("TreeMap:       " + tree);
        System.out.println("LinkedHashMap: " + linked);
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 7

The parameter type is the interface Map, so any of the three maps fits.

جۆری Mapـە، بۆیە هەر یەکێک لەو سێ دەگونجێت.

The five put() calls in order: Shilan, Aram, Rebin, Dilan, Karwan. HashMap prints Aram, Rebin, Shilan, Dilan, Karwan: no promised order. TreeMap prints Aram, Dilan, Karwan, Rebin, Shilan: sorted by key from A to Z. LinkedHashMap prints Shilan, Aram, Rebin, Dilan, Karwan: the order of put(). Note: all three are a Map, so Map<String, String> m = new TreeMap<>(); works the same way.پێنج بانگکردنی put() بە ڕیز: Shilan، Aram، Rebin، Dilan، Karwan. HashMap چاپ دەکات Aram، Rebin، Shilan، Dilan، Karwan: ڕیزبەندیی بەڵێندراو نییە. TreeMap چاپ دەکات Aram، Dilan، Karwan، Rebin، Shilan: ڕیزکراو بە کلیل لە A تا Z. LinkedHashMap چاپ دەکات Shilan، Aram، Rebin، Dilan، Karwan: ڕیزی put(). تێبینی: هەر سێکیان Mapـن، بۆیە Map<String, String> m = new TreeMap<>(); بە هەمان شێوە کار دەکات.
Same pairs, three ordersهەمان جووتەکان، سێ ڕیزبەندیCêIT

All three implement the interface Map, so a variable of type Map<String, String> can hold any of them (An interface is also a type), and you can change one line to switch. A HashMap is usually the fastest; choose the others only when you need their order.

هەر سێکیان Map جێبەجێ دەکەن، بۆیە جۆری Map<String, String> دەتوانێت هەر یەکێکیان هەڵبگرێت (نێوبەستەیەک جۆریشە) و بە گۆڕینی یەک دێڕ دەتوانیت بیانگۆڕیت. HashMap زۆرجار خێراترینە؛ تەنیا کاتێک ڕیزبەندیت پێویستە ئەوانی تر بەکار بهێنە.

Numbers as values: HashMap<String, Integer>ژمارە وەک نرخ: ⁦HashMap<String, Integer>⁩

Keys and values must be objects, so a map of numbers uses a wrapper class: HashMap<String, Integer>, not HashMap<String, int> (Wrapper classes). Autoboxing and unboxing work as in a list (Autoboxing and unboxing), so you can add up the values as ints:

و دەبێت بن، بۆیە ژمارە بەکار دەهێنێت: HashMap<String, Integer>، نەک HashMap<String, int> (کلاسە پێچەرەوەکان). و کردنەوە وەک لە کار دەکەن (پێچانەوەی خۆکار و کردنەوە)، بۆیە دەتوانیت وەک int کۆ بکەیتەوە:

MarksBook.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class MarksBook {
    public static void main(String[] args) {
        HashMap<String, Integer> marks = new HashMap<>();
        marks.put("Aram", 85);
        marks.put("Shilan", 92);
        marks.put("Karwan", 78);
        marks.put("Shilan", 95);              // a corrected mark replaces the old one
        int total = 0;
        for (int mark : marks.values()) {     // each Integer is unboxed into an int
            total += mark;
        }
        System.out.println(marks);
        System.out.println("Average: " + (double) total / marks.size());
        int aram = marks.get("Aram") + 5;     // unboxing, then int arithmetic
        System.out.println("Aram with a bonus: " + aram);
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 9

Shilan already has a mark: the new one replaces it, so there are still 3 pairs.

Shilan پێشتر نمرەی هەیە: نوێیەکە شوێنی دەگرێتەوە، بۆیە هێشتا 3 جووت هەن.

With HashMap<String, int>, javac stops with unexpected type ... required: reference, found: int, the same message as ArrayList<int>.

بە HashMap<String, int>، javac بە unexpected type ... required: reference, found: int دەوەستێت، هەمان پەیامی ArrayList<int>.

Counting with a mapژماردن بە ڕیزەکێکی پەیوەندیدار

A map is the classic tool for counting: the thing you count is the key and its count is the value. For each vote, read the old count (0 if the name is new) and store it plus 1:

ئامرازی ناسراوی ژماردنە: ئەوەی دەیژمێریت و ژمارەکەی . بۆ هەر دەنگێک، ژمارە کۆنەکە بخوێنەوە (⁦0⁩ ئەگەر ناوەکە نوێ بێت) و زائیدی 1 هەڵیبگرە:

VoteCount.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class VoteCount {
    public static void main(String[] args) {
        String votes = "Aram Shilan Aram Dilan Shilan Aram";
        HashMap<String, Integer> count = new HashMap<>();
        for (String name : votes.split(" ")) {
            count.put(name, count.getOrDefault(name, 0) + 1);
        }
        System.out.println(count);
        System.out.println("Aram has " + count.get("Aram") + " votes");
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 8

The heart of counting: old count (or 0) plus 1, stored under the same key.

دڵی ژماردن: ژمارەی کۆن (یان ⁦0⁩) زائیدی 1، لە ژێر هەمان هەڵدەگیرێت.

Six vote chips, Aram, Shilan, Aram, Dilan, Shilan, Aram, flow into a map: "Aram" 3, "Shilan" 2, "Dilan" 1. A box shows the rule count.put(name, count.getOrDefault(name, 0) + 1); and three steps for Aram: getOrDefault gives 0 and 0 + 1 = 1; then 1 and 1 + 1 = 2; then 2 and 2 + 1 = 3. Note: a new name starts at 0; a known name goes up by 1.شەش دەنگ، Aram، Shilan، Aram، Dilan، Shilan، Aram، دەچنە ناو ڕیزەکێکی پەیوەندیدار: "Aram" 3، "Shilan" 2، "Dilan" 1. سندووقێک یاساکە پیشان دەدات (count.put(name, count.getOrDefault(name, 0) + 1);) و سێ هەنگاو بۆ Aram: getOrDefault 0 دەدات و 0 + 1 = 1؛ پاشان 1 و 1 + 1 = 2؛ پاشان 2 و 2 + 1 = 3. تێبینی: ناوێکی نوێ لە 0ـەوە دەست پێ دەکات؛ ناوێکی ناسراو 1 زیاد دەکات.
Each vote adds 1 to its nameهەر دەنگێک 1 بۆ ناوەکەی زیاد دەکاتCêIT

Counting with a mapژماردن بە ڕیزەکێکی پەیوەندیدار

get gives null: the unboxing trapget null دەدات: تەڵەی کردنەوە

For a missing key get returns null. In an Integer variable that is harmless, but when Java must turn it into an int, the program stops, as with any unboxed null (null and ==):

بۆ نەبوو get null دەگەڕێنێتەوە. لە Integerـدا ئەمە زیانی نییە، بەڵام کاتێک Java دەبێت بیکات بە int، دەوەستێت، وەک هەر nullـێکی تر کە دەکرێتەوە (null و ==):

NullMark.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class NullMark {
    public static void main(String[] args) {
        HashMap<String, Integer> marks = new HashMap<>();
        marks.put("Aram", 85);
        Integer m = marks.get("Rebin");
        System.out.println("Rebin's mark: " + m);
        int bonus = marks.get("Rebin") + 5;
        System.out.println(bonus);
    }
}
Two rows. Top: marks.get("Rebin") gives null; null plus 5 needs an int; a stop sign and NullPointerException: unboxing null, there is no number to add to. Bottom: marks.getOrDefault("Rebin", 0) gives 0; 0 plus 5 gives 5, with a tick. Note: or ask first with containsKey("Rebin").دوو ڕیز. سەرەوە: marks.get("Rebin") null دەدات؛ null زائیدی 5 پێویستی بە intـێکە؛ نیشانەی وەستان و NullPointerException: کردنەوەی null، هیچ ژمارەیەک نییە بۆ کۆکردنەوە. خوارەوە: marks.getOrDefault("Rebin", 0) 0 دەدات؛ 0 زائیدی 5 دەکاتە 5، بە نیشانەی ڕاست. تێبینی: یان سەرەتا بە containsKey("Rebin") بپرسە.
null has no int inside; a default doesnull هیچ intـێکی تێدا نییە؛ هەیەتیCêIT

The message names the cause: the return value of HashMap.get(Object) is null. Use getOrDefault(key, 0), or ask containsKey(key) first.

پەیامەکە هۆکارەکە دەڵێت: ئەوەی HashMap.get(Object) گەڕاندوویەتییەوە null بووە. getOrDefault(key, 0) بەکار بهێنە، یان سەرەتا containsKey(key) بپرسە.

HashSet: every element onceHashSet: هەر ئەندامێک یەک جار

A holds each element only once and has no positions. Java's HashSet is like the keys of a HashMap without values (inside, it really uses a HashMap). add returns true for a new element and false when the element is already there; contains checks quickly; remove tells you whether it removed something:

هەر تەنیا یەک جار هەڵدەگرێت و هیچ شوێنێکی ژمارەداری نییە. HashSetـی Java وەک HashMapـێکە بەبێ (لە ناوەوە بەڕاستی HashMapـێک بەکار دەهێنێت). add بۆ نوێ true دەگەڕێنێتەوە و ئەگەر پێشتر هەبێت false؛ contains بە خێرایی دەپشکنێت؛ remove پێت دەڵێت ئایا شتێکی لابرد:

Visitors.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashSet;

public class Visitors {
    public static void main(String[] args) {
        HashSet<String> visitors = new HashSet<>();
        System.out.println(visitors.add("Aram"));
        System.out.println(visitors.add("Shilan"));
        System.out.println(visitors.add("Aram"));       // Aram is already in the set
        System.out.println(visitors + " size " + visitors.size());
        System.out.println(visitors.contains("Shilan"));
        System.out.println(visitors.remove("Karwan"));  // Karwan is not in the set
        System.out.println(visitors.remove("Shilan"));
        System.out.println(visitors);
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 8

Aram is already in the set: nothing is added and add returns false.

Aram پێشتر لە : هیچ زیاد ناکرێت و add false دەگەڕێنێتەوە.

A set drawn as an oval named visitors, holding Aram, Shilan and Karwan. visitors.add("Aram") hits the edge and bounces back with false: Aram is already inside. visitors.add("Karwan") goes in and returns true. Note: contains("Shilan") gives true, a quick check.کۆمەڵەیەک وەک بازنەیەکی هێلکەیی بە ناوی visitors، کە Aram، Shilan و Karwanـی تێدایە. visitors.add("Aram") بەر لێوارەکە دەکەوێت و بە false دەگەڕێتەوە: Aram پێشتر لە ناویدایە. visitors.add("Karwan") دەچێتە ناوەوە و true دەگەڕێنێتەوە. تێبینی: contains("Shilan") true دەدات، پشکنینێکی خێرا.
A duplicate bounces off the setدووپاتە بەر دەکەوێت و دەگەڕێتەوەCêIT

The false from add is useful: it tells you that you have seen this element before (one of the exercises uses it). Python's sets work the same way (Sets).

ئەو falseـەی add دەیگەڕێنێتەوە بەسوودە: پێت دەڵێت پێشتر ئەم بینیوە (یەکێک لە ڕاهێنانەکان بەکاری دەهێنێت). Pythonیش بە هەمان شێوە کار دەکەن (کۆمەڵەکان).

HashSet: every element onceHashSet: هەر ئەندامێک یەک جار

Intersection, union and differenceیەکتربڕین، یەکگرتن و جیاوازیی کۆمەڵە

Sets answer questions about two groups. retainAll keeps only the elements that are also in the other set (the intersection), addAll adds the other set's elements (the union) and removeAll takes them away (the difference). Each one changes the set it is called on, so work on a copy made with new HashSet<>(…):

وەڵامی پرسیار لەبارەی دوو گرووپ دەدەنەوە. retainAll تەنیا ئەوانە دەهێڵێتەوە کە لە تریشدا هەن ()، addAll ئەوی تر زیاد دەکات () و removeAll لایان دەبات (). هەر یەکەیان ئەو دەگۆڕێت کە لەسەری بانگ دەکرێت، بۆیە لەسەر کۆپییەک کار بکە کە بە new HashSet<>(…) دروست کراوە:

TwoClubs.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashSet;
import java.util.List;

public class TwoClubs {
    public static void main(String[] args) {
        HashSet<String> football = new HashSet<>(List.of("Aram", "Karwan", "Rebin", "Soran"));
        HashSet<String> chess = new HashSet<>(List.of("Shilan", "Karwan", "Hana", "Soran"));

        HashSet<String> both = new HashSet<>(football);   // a copy, so football stays unchanged
        both.retainAll(chess);                            // keep only the names that are in chess too
        HashSet<String> either = new HashSet<>(football);
        either.addAll(chess);                             // add every chess name
        HashSet<String> onlyFootball = new HashSet<>(football);
        onlyFootball.removeAll(chess);                    // take away the chess names

        System.out.println("Both clubs:    " + both);
        System.out.println("Either club:   " + either);
        System.out.println("Only football: " + onlyFootball);
        System.out.println("Football:      " + football);
    }
}
Three Venn diagrams of the football club (Aram, Rebin, Karwan, Soran) and the chess club (Shilan, Hana, Karwan, Soran). retainAll(chess) shades the overlap, Karwan and Soran: in both clubs, the intersection. addAll(chess) shades both circles: in at least one club, the union. removeAll(chess) shades only the football part outside the overlap, Aram and Rebin: football only, the difference.سێ هێڵکاریی ڤێن بۆ یانەی تۆپی پێ (Aram، Rebin، Karwan، Soran) و یانەی شەتڕەنج (Shilan، Hana، Karwan، Soran). retainAll(chess) بەشی هاوبەش ڕەنگ دەکات، Karwan و Soran: لە هەردوو یانەکەدا، یەکتربڕین. addAll(chess) هەردوو بازنەکە ڕەنگ دەکات: لانیکەم لە یەکێکیاندا، یەکگرتن. removeAll(chess) تەنیا بەشی تۆپی پێ لە دەرەوەی بەشی هاوبەش ڕەنگ دەکات، Aram و Rebin: تەنیا تۆپی پێ، جیاوازیی کۆمەڵە.
retainAll, addAll and removeAllretainAll، addAll و removeAllCêIT

The same ideas with Python's &, | and -: Set operations.

هەمان بیرۆکەکان بە &، | و -ـی Python: کارەکانی کۆمەڵە.

HashSet: every element onceHashSet: هەر ئەندامێک یەک جار

Removing duplicates, and set ordersلابردنی دووپاتەکان و ڕیزبەندیی کۆمەڵەکان

new HashSet<>(list) keeps one copy of each element: a quick way to remove duplicates from a list. As with the maps, a LinkedHashSet keeps the order in which elements first came and a TreeSet sorts them:

new HashSet<>(list) لە هەر یەک دانە دەهێڵێتەوە: ڕێگەیەکی خێرا بۆ لابردنی دووپاتەکان لە . وەک ، LinkedHashSet ئەو ڕیزە دەپارێزێت کە یەکەم جار پێی هاتن و TreeSet ڕیزیان دەکات:

UniqueNames.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.TreeSet;

public class UniqueNames {
    public static void main(String[] args) {
        List<String> signUps = new ArrayList<>(List.of("Hana", "Aram", "Hana", "Soran", "Aram", "Lana"));
        HashSet<String> unique = new HashSet<>(signUps);
        LinkedHashSet<String> inOrder = new LinkedHashSet<>(signUps);
        TreeSet<String> sorted = new TreeSet<>(signUps);
        System.out.println(signUps.size() + " sign-ups: " + signUps);
        System.out.println(unique.size() + " people:   " + unique);
        System.out.println("LinkedHashSet: " + inOrder);
        System.out.println("TreeSet:       " + sorted);
    }
}

How a HashMap finds a key so fastHashMap چۆن کلیلێک بەو خێراییە دەدۆزێتەوە

Why is get fast even with a million pairs? A HashMap is a : an array of numbered places called buckets. To store a pair, it asks the key for its hashCode(), a whole number, and turns that number into a bucket number. To find the key again, it computes the same number and looks only in that bucket. The idea is taught step by step in Hashing; here are Java's real numbers:

بۆچی get خێرایە تەنانەت بە ملیۆنێک جووتیش؟ HashMap : لە شوێنی ژمارەدار کە بە ئینگلیزی پێیان دەوترێت buckets. بۆ هەڵگرتنی جووتێک، داوای hashCode() لە دەکات، کە . پاشان ئەو ژمارەیە دەکات بە ژمارەی شوێنێک. بۆ دۆزینەوەی جارێکی تر، هەمان ژمارە دەژمێرێت و تەنیا لەو شوێنەدا دەگەڕێت. بیرۆکەکە هەنگاو بە هەنگاو لە هاشکردن فێر دەکرێت؛ ئەمەش ژمارە ڕاستەقینەکانی Javaـن:

HashCodes.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
public class HashCodes {
    public static void main(String[] args) {
        String[] names = {"Aram", "Shilan", "Karwan", "Dilan"};
        for (String name : names) {
            int h = name.hashCode();
            int bucket = Math.floorMod(h, 16);       // a simple rule: the remainder after dividing by 16
            System.out.println(name + ": hashCode " + h + ", bucket " + bucket);
        }
        System.out.println("Shilan".hashCode() == "Shilan".hashCode());
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 6

A simple rule: the remainder after dividing by 16. floorMod is never negative, even for Shilan's negative hash code.

یاسایەکی سادە: دابەشکردن بەسەر ⁦16⁩دا. floorMod هەرگیز سالب نییە، تەنانەت بۆ ژمارە سالبەکەی Shilanیش.

An animation with 16 buckets, numbered 0 to 15. marks.put("Shilan", 92): hashCode() turns "Shilan" into -1819466619, floorMod(h, 16) gives 5, and the pair Shilan=92 is stored in bucket 5. marks.put("Aram", 85): 2049085 gives bucket 13. Dilan (66034388) and Rebin (78835156) both give bucket 4, a collision, and the bucket keeps both pairs. marks.get("Rebin") computes 4 again, opens only bucket 4, compares its keys with equals(), Dilan no, Rebin yes, and finds 64. Last frame: same key, same number, same bucket, so get() never searches the other buckets.
An animation with 16 buckets, numbered 0 to 15. marks.put("Shilan", 92): hashCode() turns "Shilan" into -1819466619, floorMod(h, 16) gives 5, and the pair Shilan=92 is stored in bucket 5. marks.put("Aram", 85): 2049085 gives bucket 13. Dilan (66034388) and Rebin (78835156) both give bucket 4, a collision, and the bucket keeps both pairs. marks.get("Rebin") computes 4 again, opens only bucket 4, compares its keys with equals(), Dilan no, Rebin yes, and finds 64. Last frame: same key, same number, same bucket, so get() never searches the other buckets.
put and get go straight to one bucketput و get ڕاستەوخۆ دەچنە یەک شوێنCêIT

The animation uses the simple rule. HashMap itself mixes the bits of the number first, so its own bucket numbers differ, but the idea is the same. Two keys in one bucket are a : the bucket keeps both pairs, and equals tells the keys apart (Collisions).

ئەنیمەیشنەکە یاسا سادەکە بەکار دەهێنێت. خودی HashMap سەرەتا ژمارەکە تێکەڵ دەکات، بۆیە ژمارەی شوێنەکانی خۆی جیاوازن، بەڵام بیرۆکەکە هەمانە. دوو لە یەک شوێندا پێک دەهێنن: شوێنەکە هەردوو جووتەکە هەڵدەگرێت و equals لە یەک جیا دەکاتەوە (پێکدادانی هاش).

How a HashMap finds a key so fastHashMap چۆن کلیلێک بەو خێراییە دەدۆزێتەوە

The word hash, and why a hash code is not an IDوشەی hash و بۆچی نرخی هاش ناسنامە نییە

Hash is an old kitchen word for food chopped into small pieces and mixed (from the French hacher, "to chop"). A treats a key the same way: it chops it into characters and mixes them into one number that looks random. The class names tell you how they work: a HashMap keeps its pairs by the hash codes of their keys, and a HashSet keeps its elements the same way.

hash وشەیەکی کۆنی چێشتلێنانە بۆ خواردنێک کە ورد کراوە و تێکەڵ کراوە (لە وشەی فەڕەنسیی hacherـەوە، واتە «ورد کردن»). هەمان شت بە دەکات: وردی دەکات بۆ و تێکەڵیان دەکات بۆ یەک ژمارە کە هەڕەمەکی دیارە. ناوی پێت دەڵێن چۆن کار دەکەن: HashMap جووتەکانی بەپێی هەڵدەگرێت و HashSetـیش بە هەمان شێوە هەڵدەگرێت.

Top: the key "Shilan" is chopped into its six characters S, h, i, l, a, n, which are mixed (times 31, plus) into one number, -1819466619. Bottom: two different keys, "Aa" (65 × 31 + 97) and "BB" (66 × 31 + 66), both give 2112. An arrow from 2112 leads to one bucket that keeps both pairs, Aa=1 and BB=2; equals() tells the keys apart.سەرەوە: کلیلی "Shilan" بۆ شەش نووسەکەی S، h، i، l، a، n ورد دەکرێت و تێکەڵ دەکرێن (جارانی 31، کۆ) بۆ یەک ژمارە، -1819466619. خوارەوە: دوو کلیلی جیاواز، "Aa" (65 × 31 + 97) و "BB" (66 × 31 + 66)، هەردووکیان دەدەن 2112. تیرێک لە 2112ـەوە دەچێتە یەک شوێن کە هەردوو جووتەکە هەڵدەگرێت، Aa=1 و BB=2؛ equals() کلیلەکان لە یەک جیا دەکاتەوە.
A hash code is a mixed-up number, not a unique ID ژمارەیەکی تێکەڵکراوە، نەک ناسنامەیەکی تاکCêIT

Mixing cannot give every key a number of its own: there are endless possible strings, but only about 4.3 billion int values. So a hash code is not a unique ID. Java works out a String's hash code from its character codes as s0⋅31n−1+s1⋅31n−2+⋯+sn−1s_0 \cdot 31^{n-1} + s_1 \cdot 31^{n-2} + \dots + s_{n-1}, and even two short words share one:

تێکەڵکردن ناتوانێت ژمارەیەکی تایبەت بە هەر بدات: بێکۆتان، بەڵام int تەنیا نزیکەی ⁦4.3⁩ ملیارن. بۆیە ناسنامەیەکی تاک نییە. Java لە کۆدی بەم شێوەیە دەژمێرێت: s0⋅31n−1+s1⋅31n−2+⋯+sn−1s_0 \cdot 31^{n-1} + s_1 \cdot 31^{n-2} + \dots + s_{n-1}، تەنانەت دوو وشەی کورتیش هەمان ژمارەیان هەیە:

SameHash.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;

public class SameHash {
    public static void main(String[] args) {
        System.out.println("Aa".hashCode());     // 65 * 31 + 97
        System.out.println("BB".hashCode());     // 66 * 31 + 66
        System.out.println("Aa".equals("BB"));

        HashMap<String, Integer> codes = new HashMap<>();
        codes.put("Aa", 1);
        codes.put("BB", 2);
        System.out.println(codes.get("Aa") + " " + codes.get("BB") + ", size " + codes.size());
    }
}

Both pairs stay in the map: a HashMap uses the hash code only to choose the bucket, then compares the keys with equals (Your own class as a key).

هەردوو جووتەکە لە HashMapـەکەدا دەمێننەوە: تەنیا بۆ هەڵبژاردنی شوێنەکە بەکار دێت، پاشان equals بەراورد دەکات (کلاسی خۆت وەک کلیل).

Your own class as a key: equals and hashCodeکلاسی خۆت وەک کلیل: equals و hashCode

String and the wrapper classes such as Integer already override equals and hashCode, so they work as keys. A class of your own inherits both from Object, where every object is equal only to itself and has its own hash code. Then two seats with the same row and number are two different keys. Override both methods from the same fields; how to write equals is shown in equals():

String و وەک Integer پێشتر equals و hashCodeیان پێناسە کردۆتەوە، بۆیە وەک کار دەکەن. خۆت هەردووکیان لە Objectـەوە بە وەردەگرێت، کە تێیدا هەر تەنیا یەکسانە بە خۆی و ژمارەی hashCode()ـی خۆی هەیە. ئەوکاتە دوو کورسی بە هەمان ڕیز و ژمارە دوو جیاوازن. هەردوو لە هەمان پێناسە بکەرەوە؛ چۆنیەتیی نووسینی equals لە ⁦equals()⁩ نیشان دراوە:

SeatGood.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;
import java.util.Objects;

class Seat {
    int row;
    int number;

    Seat(int row, int number) {
        this.row = row;
        this.number = number;
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof Seat)) {
            return false;
        }
        Seat s = (Seat) other;
        return row == s.row && number == s.number;
    }

    @Override
    public int hashCode() {
        return Objects.hash(row, number);
    }
}

public class SeatGood {
    public static void main(String[] args) {
        HashMap<Seat, String> booked = new HashMap<>();
        booked.put(new Seat(5, 12), "Aram");
        System.out.println(booked.get(new Seat(5, 12)));
        booked.put(new Seat(5, 12), "Shilan");
        System.out.println(booked.size() + " booking for one seat: " + booked.get(new Seat(5, 12)));
    }
}
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 13-20

Two seats are equal when row and number are equal.

دوو کورسی یەکسانن کاتێک ڕیز و ژمارەیان یەکسانە.

Lineدێڕی 22-25

Equal seats must give the same hash code: build it from the same two fields. Objects.hash (from java.util.Objects) turns them into one number.

کورسییە یەکسانەکان دەبێت هەمان ژمارەی hashCode() بدەن: لە هەمان دوو دروستی بکە. Objects.hash (لە java.util.Objects) ئەو دووانە دەکات بە یەک ژمارە.

The same program without equals and hashCodeهەمان بەرنامە بەبێ equals و hashCode
$ java SeatBad
null
2 bookings for one seat
Two panels. Without equals and hashCode: new Seat(5, 12) used for put (Aram) and another new Seat(5, 12) used for get have two different hash codes, A and B, so they land in two buckets; get looks in the wrong, empty bucket and gives null. With equals and hashCode: both give hashCode() 1128, the same bucket; equals() says true, and get finds "Aram".دوو بەش. بەبێ equals و hashCode: new Seat(5, 12) بۆ put (Aram) و new Seat(5, 12)ـێکی تر بۆ get دوو ژمارەی hashCode()ـی جیاوازیان هەیە، A و B، بۆیە دەچنە دوو شوێنی جیاواز؛ get لە شوێنە هەڵە چۆڵەکەدا دەگەڕێت و null دەدات. بە equals و hashCode: هەردووکیان hashCode() 1128 دەدەن، هەمان شوێن؛ equals() دەڵێت true و get "Aram" دەدۆزێتەوە.
Equal keys must give equal hash codes یەکسان دەبێت هەمان ژمارەی ⁦hashCode()⁩ بدەنCêIT

Removing while looping: ConcurrentModificationExceptionلابردن لە کاتی سووڕانەوەدا: ConcurrentModificationException

As with a list (Removing inside a loop), a set or a map must not be changed by a for-each loop that is walking over it. The loop's hidden iterator notices the change and stops the program:

وەک (لابردن لە ناو خولێکدا)، یان نابێت لە ناو بگۆڕدرێت کە بەسەریدا دەڕوات. لە پشتەوە بەکار دەهێنێت؛ ئەو گۆڕانەکە هەست پێ دەکات و دەوەستێنێت:

RemoveWhileLooping.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashSet;
import java.util.List;

public class RemoveWhileLooping {
    public static void main(String[] args) {
        HashSet<String> names = new HashSet<>(List.of("Aram", "Kawa", "Shilan", "Karwan", "Dilan"));
        for (String name : names) {
            if (name.startsWith("K")) {
                names.remove(name);
            }
        }
        System.out.println(names);
    }
}
The set in its loop order: Aram, Kawa, Shilan, Dilan, Karwan. Step 1 visits Aram; step 2 visits Kawa, and names.remove("Kawa") takes it out (dashed, crossed); step 3, next(), meets a stop sign: ConcurrentModificationException, next() sees that the set changed behind the loop. Below, two safe ways: it.remove(), remove through the iterator; names.removeIf(n -> n.startsWith("K")), one call removes every match.کۆمەڵەکە بە ڕیزی خولەکەی: Aram، Kawa، Shilan، Dilan، Karwan. هەنگاوی 1 سەردانی Aram دەکات؛ هەنگاوی 2 سەردانی Kawa دەکات و names.remove("Kawa") لای دەبات (پچڕپچڕ و خەتلێدراو)؛ هەنگاوی 3، next()، دەگاتە نیشانەی وەستان: ConcurrentModificationException، next() دەبینێت کە کۆمەڵەکە لە پشتی خولەوە گۆڕاوە. لە خوارەوە دوو ڕێگەی سەلامەت: it.remove()، لابردن لە ڕێگەی خولپێکەرەوە؛ names.removeIf(n -> n.startsWith("K"))، یەک بانگکردن هەموو گونجاوەکان لادەبات.
The loop notices the change at its next step لە هەنگاوی داهاتوویدا گۆڕانەکە دەبینێتCêIT

Remove through the iterator itself (Iterator.remove()), or let removeIf run the loop (removeIf). For a map, call it on keySet(), values() or entrySet(): marks.values().removeIf(m -> m < 50) removes those pairs:

لە ڕێگەی خودی لایببە (⁦Iterator.remove()⁩)، یان با removeIf بەڕێوە ببات (removeIf). بۆ ، لەسەر keySet()، values() یان entrySet() بانگی بکە: marks.values().removeIf(m -> m < 50) ئەو جووتانە لادەبات:

RemoveSafely.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

public class RemoveSafely {
    public static void main(String[] args) {
        HashSet<String> names = new HashSet<>(List.of("Aram", "Kawa", "Shilan", "Karwan", "Dilan"));
        Iterator<String> it = names.iterator();
        while (it.hasNext()) {
            if (it.next().startsWith("K")) {
                it.remove();                     // remove through the iterator: allowed
            }
        }
        System.out.println(names);

        HashSet<String> again = new HashSet<>(List.of("Aram", "Kawa", "Shilan", "Karwan", "Dilan"));
        again.removeIf(name -> name.startsWith("K"));   // the same in one line
        System.out.println(again);
    }
}

ArrayList, HashMap or HashSet?ArrayList، HashMap یان HashSet؟

All three live in java.util and grow by themselves. Choose by the question your program asks most often:

هەر سێکیان لە java.utilـدان و خۆیان گەورە دەبن. بەپێی ئەو پرسیارەی زۆرترین جار دەیکات هەڵبژێرە:

Three collections side by sideسێ کۆکراوە لە تەنیشت یەکەوە
QuestionپرسیارArrayListHashMapHashSet
Finds byدۆزینەوە بەindex: get(0): get(0)key: get("Aram"): get("Aram")only "is it there?": containsتەنیا «ئایا هەیە؟»: contains
Duplicatesدووپاتەallowedڕێگەپێدراوkeys no, values yes نا، بەڵێneverهەرگیز
Orderڕیزبەندیkeptدەپارێزرێتnot promisedبەڵێن نادرێتnot promisedبەڵێن نادرێت
Typical useبەکارهێنانی باوa class list in orderلیستی پۆلێک بە ڕیزmarks by name, word lists, countsنمرە بە ناو، لیستی وشە، ژماردنvisitors, unique wordsسەردانکەران، وشەی بێ دووپاتە
Three cards. ArrayList: Aram, Aram, Shilan on numbered places 0, 1, 2; keeps the order, duplicates allowed, find by index with get(0). HashMap: "Aram" to 85 and "Shilan" to 92; find by key with get("Aram"), keys are unique, values may repeat, order not promised. HashSet: Aram and Shilan in an oval; each element once, quick contains(), no index, order not promised.سێ کارت. ArrayList: Aram، Aram، Shilan لە شوێنە ژمارەدارەکانی 0، 1، 2؛ ڕیزبەندی دەپارێزێت، دووپاتە ڕێگەپێدراوە، دۆزینەوە بە ئیندێکس بە get(0). HashMap: "Aram" بۆ 85 و "Shilan" بۆ 92؛ دۆزینەوە بە کلیل بە get("Aram")، کلیلەکان دووپاتە نابنەوە، نرخەکان دووپاتە دەبنەوە، ڕیزبەندی بەڵێن نادرێت. HashSet: Aram و Shilan لە بازنەیەکی هێلکەییدا؛ هەر ئەندامێک یەک جار، contains()ـی خێرا، ئیندێکس نییە، ڕیزبەندی بەڵێن نادرێت.
Choose by the question you askبەپێی ئەو پرسیارەی دەیکەیت هەڵبژێرەCêIT

Common mistakesهەڵە باوەکان

Mistakes with maps and sets, with the real messagesهەڵەکان لەگەڵ و ، بە پەیامە ڕاستەقینەکانەوە
You wroteنووسیتWhat happensچی ڕوو دەداتFixچارەسەر
HashMap<String, int>error: unexpected type required: reference found: intHashMap<String, Integer>.HashMap<String, Integer>.
int m = marks.get("Rebin"); for a missing keyint m = marks.get("Rebin"); بۆ نەبووNullPointerException: ... the return value of "java.util.HashMap.get(Object)" is nullgetOrDefault("Rebin", 0) or containsKey first.getOrDefault("Rebin", 0) یان سەرەتا containsKey.
marks.get(1) on a map with String keysmarks.get(1) لەسەر بە Stringcompiles, gives nullکۆمپایل دەبێت، null دەداتUse the key type: marks.get("Aram").جۆری بەکار بهێنە: marks.get("Aram").
marks.get("aram") for the key "Aram"marks.get("aram") بۆ "Aram"null: keys are case-sensitivenull: Use the exact key, or store keys in one case. وەک خۆی بنووسە، یان بە یەک جۆر پیت هەڵبگرە.
Expecting a HashMap to keep the put orderچاوەڕوانی ئەوەی HashMap ڕیزی put بپارێزێتa different order, which can changeڕیزێکی جیاواز کە دەتوانێت بگۆڕێتLinkedHashMap (put order) or TreeMap (sorted).LinkedHashMap (ڕیزی put) یان TreeMap (ڕیزکراو).
names.remove(n) inside a for-each loop over namesnames.remove(n) لە ناو بەسەر namesـداConcurrentModificationExceptionremoveIf or iterator.remove().removeIf یان iterator.remove().
Your own key class without equals and hashCode خۆت بەبێ equals و hashCodeget gives null, duplicates appearget null دەدات، دووپاتە دەردەکەوێتOverride both, from the same fields (or use a record).هەردووکیان پێناسە بکەرەوە، لە هەمان (یان recordـێک بەکار بهێنە).
a.retainAll(b) when you still need aa.retainAll(b) کاتێک هێشتا aـت پێویستەa itself is changedخودی a دەگۆڕێتWork on new HashSet<>(a).لەسەر new HashSet<>(a) کار بکە.

The first mistake in full, as javac prints it:

یەکەم هەڵە بە تەواوی، وەک javac چاپی دەکات:

Outputدەرئەنجام
$ javac IntMap.java
IntMap.java:5: error: unexpected type
        HashMap<String, int> marks = new HashMap<>();
                        ^
  required: reference
  found:    int
1 error

Practiceڕاهێنان

ExerciseڕاهێنانFrom Kurdish–English to English–Kurdishلە کوردی ـ ئینگلیزییەوە بۆ ئینگلیزی ـ کوردی

Start with the word list کتێب → book, قوتابخانە → school, مامۆستا → teacher. Build a second map that goes the other way, then print the Kurdish words for teacher and book.

بە لیستی وشەکانی کتێب ← book، قوتابخانە ← school و مامۆستا ← teacher دەست پێ بکە. دووەم دروست بکە کە بە پێچەوانەوە دەڕوات، پاشان وشە کوردییەکانی teacher و book چاپ بکە.

Hintئاماژە

Each Map.Entry gives you both parts.

هەر ⁦Map.Entry⁩ـێک هەردوو بەشت دەداتێ.

Show answerوەڵامەکە پیشان بدە
InvertWords.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;
import java.util.Map;

public class InvertWords {
    public static void main(String[] args) {
        HashMap<String, String> kurdishToEnglish = new HashMap<>();
        kurdishToEnglish.put("کتێب", "book");
        kurdishToEnglish.put("قوتابخانە", "school");
        kurdishToEnglish.put("مامۆستا", "teacher");

        HashMap<String, String> englishToKurdish = new HashMap<>();
        for (Map.Entry<String, String> pair : kurdishToEnglish.entrySet()) {
            englishToKurdish.put(pair.getValue(), pair.getKey());   // the value becomes the key
        }
        System.out.println(englishToKurdish.get("teacher"));
        System.out.println(englishToKurdish.get("book"));
    }
}

Loop over entrySet() and put(value, key). It works because the values are different; with a repeated value, the later pair would replace the earlier one.

بەسەر entrySet()ـدا بسووڕێوە و put(value, key) بکە. کار دەکات چونکە جیاوازن؛ ئەگەر دووپاتە بێتەوە، جووتی دواتر شوێنی جووتی پێشتر دەگرێتەوە.

ExerciseڕاهێنانLetter counterژمێرەری پیت

Count how many times each letter appears in the word programming and print the counts in alphabetical order.

بژمێرە هەر پیتێک چەند جار لە وشەی programmingـدا هاتووە و ژمارەکان بە ڕیزی ئەلفوبێ چاپ بکە.

Show answerوەڵامەکە پیشان بدە
LetterCount.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;
import java.util.TreeMap;

public class LetterCount {
    public static void main(String[] args) {
        String word = "programming";
        HashMap<Character, Integer> count = new HashMap<>();
        for (char c : word.toCharArray()) {
            count.put(c, count.getOrDefault(c, 0) + 1);
        }
        System.out.println(new TreeMap<>(count));    // the same pairs, sorted by letter
    }
}

toCharArray() gives the letters of the word as a char[], and each char key is boxed into a Character. HashMap<Character, Integer> counts as the votes did; new TreeMap<>(count) copies the pairs into a map sorted by key.

toCharArray() پیتەکانی وشەکە وەک char[]ـێک دەدات و هەر char دەکرێتە Character. HashMap<Character, Integer> وەک دەنگەکان دەژمێرێت؛ new TreeMap<>(count) جووتەکان کۆپی دەکات بۆ کە بە ڕیزکراوە.

ExerciseڕاهێنانThe first name that comes twiceیەکەم ناو کە دوو جار دێت

Read names separated by spaces and print the first name that appears for the second time, or No name came twice.

ناوەکان بخوێنەوە کە بە لە یەک جیا کراونەتەوە و یەکەم ناو چاپ بکە کە بۆ جاری دووەم دێت، یان No name came twice.

Hintئاماژە

Use the boolean that add returns.

ئەو booleanـە بەکار بهێنە کە add دەیگەڕێنێتەوە.

Show answerوەڵامەکە پیشان بدە
FirstRepeat.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashSet;
import java.util.Scanner;

public class FirstRepeat {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        HashSet<String> seen = new HashSet<>();
        System.out.println("Names, separated by spaces:");
        while (input.hasNext()) {
            String name = input.next();
            if (!seen.add(name)) {                  // add returns false: we saw it before
                System.out.println(name + " came twice");
                return;
            }
        }
        System.out.println("No name came twice");
    }
}

if (!seen.add(name)) adds and checks in one step: add returns false for a name already seen.

if (!seen.add(name)) لە یەک هەنگاودا زیاد دەکات و دەپشکنێت: add بۆ ناوێک کە پێشتر بینراوە false دەگەڕێنێتەوە.

ExerciseڕاهێنانWho has not handed in the homework?کێ ئەرکی ماڵەوەی نەداوە؟

The class is Aram, Shilan, Karwan, Dilan, Hana and Soran. Shilan, Dilan, Aram and Shilan again handed in their homework. Print how many handed in, and the missing names from A to Z.

پۆلەکە Aram، Shilan، Karwan، Dilan، Hana و Soranـە. Shilan، Dilan، Aram و جارێکی تر Shilan ئەرکی ماڵەوەیان دا. چاپ بکە چەند کەس دایان و ناوی ئەوانەی نەیاندا لە A تا Z.

Show answerوەڵامەکە پیشان بدە
Homework.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashSet;
import java.util.List;
import java.util.TreeSet;

public class Homework {
    public static void main(String[] args) {
        HashSet<String> everyone = new HashSet<>(List.of("Aram", "Shilan", "Karwan", "Dilan", "Hana", "Soran"));
        HashSet<String> handedIn = new HashSet<>(List.of("Shilan", "Dilan", "Aram", "Shilan"));
        HashSet<String> missing = new HashSet<>(everyone);
        missing.removeAll(handedIn);
        System.out.println(handedIn.size() + " handed in, " + missing.size() + " did not");
        System.out.println("Still missing: " + new TreeSet<>(missing));
    }
}

The repeated Shilan counts once, so 3 handed in. removeAll on a copy gives the difference, and a TreeSet prints it sorted.

Shilanـی دووپاتە یەک جار دەژمێردرێت، بۆیە 3 کەس دایان. removeAll لەسەر کۆپییەک دەدات و TreeSet بە ڕیزکراوی چاپی دەکات.

ExerciseڕاهێنانThe pass listلیستی دەرچووان

A HashMap<String, Integer> holds Karwan 48, Aram 85, Lana 67, Dilan 39 and Hana 91. Print the students with 50 or more, in alphabetical order, and how many they are.

HashMap<String, Integer>ـێک ئەمانەی تێدایە: ⁦Karwan 48⁩، ⁦Aram 85⁩، ⁦Lana 67⁩، ⁦Dilan 39⁩ و ⁦Hana 91⁩. ئەو قوتابییانە چاپ بکە کە ⁦50⁩ یان زیاتریان هەیە، بە ڕیزی ئەلفوبێ و ژمارەیان.

Show answerوەڵامەکە پیشان بدە
PassList.javaJAVAType in a terminalلە تێرمیناڵدا بینووسە
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class PassList {
    public static void main(String[] args) {
        HashMap<String, Integer> marks = new HashMap<>();
        marks.put("Karwan", 48);
        marks.put("Aram", 85);
        marks.put("Lana", 67);
        marks.put("Dilan", 39);
        marks.put("Hana", 91);
        TreeMap<String, Integer> passed = new TreeMap<>();
        for (Map.Entry<String, Integer> e : marks.entrySet()) {
            if (e.getValue() >= 50) {
                passed.put(e.getKey(), e.getValue());
            }
        }
        System.out.println(passed.size() + " passed: " + passed);
    }
}

Summaryکورتە

  • A HashMap<K, V> stores key–value pairs: put, get, getOrDefault, containsKey, remove, size, clear. Each key appears once; put on an old key replaces its value.
  • get gives null for a missing key, and unboxing that null into an int throws NullPointerException.
  • Loop with keySet(), values() or entrySet(). A HashMap promises no order; TreeMap sorts the keys and LinkedHashMap keeps the put order.
  • Counting: count.put(x, count.getOrDefault(x, 0) + 1).
  • A HashSet keeps each element once: add returns false for a duplicate, contains is quick, and retainAll, addAll and removeAll give intersection, union and difference.
  • Hashing: hashCode() picks a bucket, so get looks in one place. Your own key class needs equals and hashCode; do not remove inside a for-each loop (use removeIf).
  • A hash code is a mixed-up number, not a unique ID: "Aa" and "BB" both give 2112, so equals makes the final check.
  • HashMap<K, V> هەڵدەگرێت: put، get، getOrDefault، containsKey، remove، size، clear. هەر یەک جار دێت؛ put لەسەر کۆن دەگۆڕێتەوە.
  • get بۆ نەبوو null دەدات و کردنەوەی ئەو nullـە بۆ int NullPointerException فڕێ دەدات.
  • بە keySet()، values() یان entrySet() بسووڕێوە. HashMap بەڵێنی هیچ ڕیزبەندییەک نادات؛ TreeMap ڕیز دەکات و LinkedHashMap ڕیزی put دەپارێزێت.
  • ژماردن: count.put(x, count.getOrDefault(x, 0) + 1).
  • HashSet هەر یەک جار هەڵدەگرێت: add بۆ دووپاتە false دەگەڕێنێتەوە، contains خێرایە و retainAll، addAll و removeAll ، و دەدەن.
  • هاشکردن: hashCode() شوێنێک هەڵدەبژێرێت، بۆیە get لە یەک شوێندا دەگەڕێت. خۆت پێویستی بە equals و hashCode هەیە؛ لە ناو لامەبە (removeIf بەکار بهێنە).
  • ژمارەیەکی تێکەڵکراوە، نەک ناسنامەیەکی تاک: "Aa" و "BB" هەردووکیان ⁦2112⁩ دەدەن، بۆیە equals پشکنینی کۆتایی دەکات.
Review questionsپرسیارەکانی پێداچوونەوە
What does put return when the key is already in the map?put چی دەگەڕێنێتەوە کاتێک کلیلەکە پێشتر لە ڕیزەکە پەیوەندیدارەکەدایە؟

The old value, which it has just replaced. For a new key it returns null.

کۆن کە تازە گۆڕیویەتییەوە. بۆ نوێ null دەگەڕێنێتەوە.

Why is HashMap<String, int> refused?بۆچی HashMap<String, int> ڕەت دەکرێتەوە؟

Keys and values must be objects. Use the wrapper class: HashMap<String, Integer>.

و دەبێت بن. بەکار بهێنە: HashMap<String, Integer>.

How do you know that add met a duplicate?چۆن دەزانیت add بەر دووپاتەیەک کەوتووە؟

It returns false, and the set does not change.

false دەگەڕێنێتەوە و ناگۆڕێت.

Lesson complete!وانەکە تەواو بوو!

Well done. Review the key terms, then go on to the next lesson.دەستخۆش. سەیرێکی زاراوە سەرەکییەکان بکەرەوە، پاشان بڕۆ بۆ وانەی داهاتوو.

Key termsزاراوە سەرەکییەکان

Next lessonوانەی داهاتوو

Exceptions: try, catch and finallyهەڵاوێردەکان: try، catch و finally

References and further readingسەرچاوەکان و خوێندنەوەی زیاتر

This lecture is a first edition. The Kurdish text and terminology are waiting for review by Kurdish IT teachers.ئەم وانەیە چاپی یەکەمە. دەقە کوردییەکە و زاراوەکانی چاوەڕێی پێداچوونەوەی مامۆستایانی کوردی بواری IT ن.

Appearanceڕووکار

Modeدۆخ
Styleشێواز
Coloursڕەنگەکان

Saved on this device only.تەنیا لەسەر ئەم ئامێرە پاشەکەوت دەکرێت.