HashMap ในภาษา Java

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับการใช้งาน HashMap สำหรับเก็บข้อมูลในรูปแบบของ Key/Value ในภาษา Java

HashMap เป็นออบเจ็คของคลาส HashMap ที่ถูก Implement มาจากอินเตอร์เฟซ Map<K,V> มันใช้สำหรับเก็บข้อมูลในรูปแบบของ Key/Value โดยที่ทั้ง Key และ Value ของ Map นั้นสามารถเป็นออบเจ็คประเภทใดก็ได้ในภาษา Java นี่เป็นรูปแบบการประกาศ HashMap ในภาษา Java

HashMap<K, V> map = new HashMap<K, V>();

คลาส HashMap นั้นเป็นคลาสแบบ Generic ดังนั้นในการประกาศออบเจ็คเราต้องกำหนดประเภทของ Key และ Value ผ่าน Generic template <K, V> โดยที่ K เป็นคลาสของข้อมูลที่จะใช้เป็น Key และ V เป็นคลาสของข้อมูลจะเก็บใน Map

เนื่องจาก HashMap นั้นเป็นคลาสที่ Implement มาจากอินเตอร์เฟซ Map<K,V> ดังนั้นในการประกาศออบเจ็ค เราสามารถใช้อินเตอร์เฟซ Map<K,V> เป็นประเภทของออบเจ็คได้ ยกตัวอย่างเช่น

Map<K, V> map = new HashMap<K, V>();

แต่ในบทนี้เราจะใช้ HashMap<K, V> สำหรับการกำหนดประเภทของออบเจ็คในตอนประกาศตัวแปร

การใช้งาน HashMap

สำหรับตัวอย่างแรกในบทนี้เราจะใช้ HashMap ในการเก็บข้อมูลเกี่ยวกับผลไม้โดยใช้ชื่อผลไม้เป็น Key ของ Map และใช้จำนวนของผลไม้เป็น Value ของ Map และแนะนำการใช้งานเมธอดพื้นฐานของ Map สำหรับเพิ่มและเรียกดูข้อมูลภายใน Map นี่เป็นตัวอย่าง

HashMapEx1.java
package com.marcuscode.hashmap;

import java.util.HashMap;

public class HashMapEx1 {

    public static void main(String[] args) {

        // Creating map object
        HashMap<String, Integer> map = 
                new HashMap<String, Integer>();

        // Adding data to map
        map.put("apple", 1);
        map.put("banana", 2);
        map.put("orange", 3);

        // Determine map's size
        System.out.println("Size: " + map.size());

        // Retrieving data from map
        System.out.println("apple: " + map.get("apple"));
        System.out.println("banana: " + map.get("banana"));
        System.out.println("something: " + map.get("something"));

    }
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Size: 3
apple: 1
banana: 2
something: null

ในตัวอย่างนี้ แสดงการใช้งาน HashMap สำหรับเก็บข้อมูลในภาษา Java โดยใช้ชื่อของผลไม้เป็น Key และจำนวนของผลไม้เป็นค่าที่เก็บใน Map

HashMap นั้นเป็นคลาสจากไลบรารี่มาตรฐานของภาษา Java ที่อยู่ภายในแพ็คเกจ java.util.* ดังนั้นเราได้นำเข้าคลาสมาใช้งานในโปรแกรมด้วยคำสั่ง import ดังนี้

import java.util.HashMap;

จากนั้นเป็นการสร้างออบเจ็คของ HashMap สำหรับเก็บข้อมูลด้วยคำสั่ง

HashMap<String, Integer> map = new HashMap<String, Integer>();

นี่เป็นการสร้างออบเจ็ค HashMap สำหรับเก็บข้อมูลที่มี Key เป็น String ที่เป็นชื่อของผลไม้ และ Value เป็น Integer เป็นจำนวนของผลไม้ที่มี

map.put("apple", 1);
map.put("banana", 2);
map.put("orange", 3);

จากนั้นเป็นการเพิ่มข้อมูลเข้าไปยัง HashMap โดยเมธอด put() นั้นใช้สำหรับเพิ่มข้อมูลเข้าไปยัง Map โดยมีพารามิเตอร์แรกเป็น Key และพารามิเตอร์ที่สองเป็น Value ตามลำดับ ในตัวอย่าง เราได้เพิ่มสามค่าเข้าไปยัง Map โดย Key นั้นจะเป็นชื่อของผลไม้ และค่าของมันเป็นจำนวนของผลไม้ที่มีอยู่สำหรับ Key ดังกล่าว

System.out.println("Size: " + map.size());

เมธอด size() ส่งค่ากลับเป็นจำนวนข้อมูลทั้งหมดที่ถูกเก็บใน HashMap ดังนั้นในคำสั่งนี้ส่งค่ากลับเป็น 3 เนื่องจากเราได้เพิ่มค่าเข้าไปยัง Map ก่อนหน้านี้สามค่าด้วยเมธอด put()

System.out.println("apple: " + map.get("apple"));
System.out.println("banana: " + map.get("banana"));
System.out.println("something: " + map.get("something"));

และสุดท้ายเมธอด get() ใช้สำหรับรับข้อมูลใน HashMap จาก Key ที่ระบุ ถ้าหาก Key นั้นไม่มีอยู่เมธอดนี้ส่งค่ากลับเป็น null

เมธอดของ HashMap

ในตัวอย่างก่อนหน้า คุณได้เรียนรู้การทำงานพื้นฐานเกี่่ยวกับ HashMap เช่น การเพิ่มข้อมูล การอ่านข้อมูล และการหาขนาดของ Map ในตัวอย่างนี้ คุณจะได้เรียนรู้เมธอดเพิ่มเติมของ HashMap เราจะใช้ Map สำหรับเก็บคะแนนของนักเรียนโดยใช้ชื่อของนักเรียนเป็น Key และคะแนนเป็น Value นี่เป็นตัวอย่าง

HashMapEx2.java
package com.marcuscode.hashmap;

import java.util.HashMap;

public class HashMapEx2 {

    public static void main(String[] args) {

        // Creating map object
        HashMap<String, Integer> scores = new HashMap<String, Integer>();

        // Adding data to map
        scores.put("metin", 80);
        scores.put("jacob", 70);
        System.out.println("metin's score: " + scores.get("metin"));
        System.out.println("jacob's score: " + scores.get("jacob"));
        System.out.println("chris' score: " + scores.getOrDefault("chris", 50));

        // Replace to new value
        scores.replace("metin", 100);
        System.out.println("metin's new score: " + scores.get("metin"));

        // Remove value by key
        scores.remove("metin");     
        System.out.println("metin's score: " + scores.get("metin"));
        System.out.println("Size: " + scores.size());

        // Check for key existence
        System.out.println("Is metin exist: " + scores.containsKey("metin"));
        System.out.println("Is jacob exist: " + scores.containsKey("jacob"));

        // Remove all values in map
        scores.clear();
        System.out.println("Is empty?: " + scores.isEmpty());
        System.out.println("Size: " + scores.size());     
    }

}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

metin's score: 80
jacob's score: 70
chris' score: 50
metin's new score: 100
metin's score: null
Size: 1
Is metin exist: false
Is jacob exist: true
Is empty?: true
Size: 0

ในตัวอย่างนี้ เป็นการแนะนำการใช้งานเมธอดอื่นๆ ของ HashMap ที่นอกเหนือจากการเพิ่มข้อมูล การอ่านข้อมูล และการหาขนาด ก่อนเริ่มเราได้สร้างออบเจ็ค scores มันเป็น HashMap ที่จะใช้สำหรับเก็บคะแนนโดยใช้ชื่อของนักเรียนเป็น Key และคะแนนของนักเรียนเป็น Value ของ Map

scores.put("metin", 80);
scores.put("jacob", 70);
System.out.println("metin's score: " + scores.get("metin"));
System.out.println("jacob's score: " + scores.get("jacob"));

ในตอนแรกเราได้เพิ่มสองข้อมูลเข้าไปใน HashMap ด้วยเมธอด put() และแสดงค่าที่เพิ่งเพิ่มเข้าไปโดยรับเอาคะแนนจากเมธอด get() ด้วย Key ที่เป็นชื่อของนักเรียน

System.out.println("chris' score: " + scores.getOrDefault("chris", 50));

เมธอด get() ส่งค่ากลับเป็น null ถ้าหาก Key ที่ระบุไม่มีอยู่ใน HashMap ในกรณีที่ไม่มี Key ใน Map เราสามารถใช้เมธอด getOrDefault() เพื่อกำหนดค่าเริ่มต้นในการรับข้อมูลได้ โดยค่าเริ่มต้นที่ส่งเป็นอาร์กิวเมนต์ที่สองจะถูกส่งกลับมาแทนในกรณีที่ไม่พบ Key ที่ระบุ

scores.replace("metin", 100);

เมธอด replace() ใช้สำหรับแทนท่ี่ค่าของ Key ที่กำหนดภายใน HashMap ให้เป็นค่าใหม่ ถ้าหาก Key ดังกล่าวยังไม่ถูกเก็บใน Map เมธอดจะทำการเพิ่มค่าดังกล่าวเข้าไปใน Map ซึ่งเป็นการทำงานที่เหมือนกับเมธอด put()

scores.remove("metin"); 

เมธอด remove() ใช้สำหรับลบค่าจาก Key ที่กำหนดออกจาก HashMap

System.out.println("Is metin exist: " + scores.containsKey("metin"));
System.out.println("Is jacob exist: " + scores.containsKey("jacob"));

หลังจากที่ลบค่าออกจาก HashMap แล้วเราสามารถตรวจสอบว่ามี Key ดังกล่าวภายใน Map หรือไม่โดยการใช้เมธอด containsKey() เมธอดส่งค่ากลับเป็น Boolean ว่ามี Key ดังกล่าวอยู่ใน Map หรือไม่

scores.clear();
System.out.println("Is empty?: " + scores.isEmpty());
System.out.println("Size: " + scores.size()); 

และสุดท้ายเมธอด clear() ใช้สำหรับลบข้อมูลทั้งหมดออกจาก HashMap เราสามารถใช้เมธอด isEmpty() เพื่อตรวจสอบว่า Map ว่างอยู่หรือไม่ และมันส่งค่ากลับเป็น true เนื่องจากเราเพิ่งจะลบค่าทั้งหมดออกไป

การวนค่า Key และ Value ใน HashMap

ในการเขียนโปรแกรมเพื่อทำงานกับ HashMap เราอาจต้องการวนค่าทั้งหมดภายใน Map สำหรับวัตถุประสงค์บางอย่าง เช่น ต้องการดู Key หรือ Value ทั้งหมดที่เก็บภายใน Map เป็นต้น ซึ่งในภาษา Java นั้นเราสามารถวนรอบค่าภายใน Map ได้ด้วยออบเจ็ค Iterator ที่ได้รับจากการเรียกใช้เมธอดบนออบเจ็ค HashMap

ในตัวอย่างนี้แสดงการวนรอบค่า Key และ Value จากในออบเจ็คของ HashMap ด้วยวิธีต่างๆ และแสดงค่าเหล่านั้นออกทางหน้าจอ

HashMapEx3.java
package com.marcuscode.hashmap;

import java.util.HashMap;
import java.util.Map.Entry;
import java.util.function.BiConsumer;

public class HashMapEx3 {

    public static void main(String[] args) {

        // Creating map object
        HashMap<String, String> countries = 
                new HashMap<String, String>();

        // Adding data to map
        countries.put("th", "Thailand");
        countries.put("uk", "United Kingdom");
        countries.put("sg", "Singapore");
        countries.put("tr", "Turkey");

        System.out.println("Method 1");
        for (Entry<String, String> entry : countries.entrySet()) {
            System.out.print("Key: " + entry.getKey() + ", ");
            System.out.println("Value: " + entry.getValue());
        }

        System.out.println("Method 2");
        countries.forEach(new BiConsumer<String, String>() {
            @Override
            public void accept(String key, String value) {
                System.out.print("Key: " + key + ", ");
                System.out.println("Value: " + value);
            }
        });

    }

}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Method 1
Key: th, Value: Thailand
Key: sg, Value: Singapore
Key: uk, Value: United Kingdom
Key: tr, Value: Turkey
Method 2
Key: th, Value: Thailand
Key: sg, Value: Singapore
Key: uk, Value: United Kingdom
Key: tr, Value: Turkey

ในตัวอย่าง เราได้แสดงสองวิธีสำหรับการวนค่า Key และ Value จาก HashMap โดยการใช้เมธอด entrySet() ร่วมกับคำสั่ง for loop และการใช้เมธอด forEach() ของ Map เอง ซึ่งทั้งสองวิธีนั้นให้ผลลัพธ์ที่เหมือนกัน

for (Entry<String, String> entry : countries.entrySet()) {
    System.out.print("Key: " + entry.getKey() + ", ");
    System.out.println("Value: " + entry.getValue());
}

วิธีแรกเป็นการใช้งานเมธอด entrySet() บนออบเจ็คของ HashMap เมธอดนี้ส่งค่ากลับเป็นออบเจ็ค Iterator ที่สามารถวนรอบได้โดยคำสั่ง for loop ในการวนแต่ละรอบออบเจ็ค Iterator ส่งค่ากลับเป็นออบเจ็ค entry ที่เราสามารถใช้เมธอด getKey() และ getValue() เพื่อรับค่า Key และ Value ได้ตามลำดับ

countries.forEach(new BiConsumer<String, String>() {
    @Override
    public void accept(String key, String value) {
        System.out.print("Key: " + key + ", ");
        System.out.println("Value: " + value);
    }
});

วิธีที่สองคือการใช้เมธอด forEach() ในการใช้งานเมธอดนี้เราจะต้องส่งออบเจ็คของคลาสที่ทำการ Implement อินเตอร์เฟซ BiConsumer สำหรับเมธอดเพื่อทำงาน โดยทำการ Override เมธอด accept() เพื่อรับค่าของ Key และ Value ที่จะส่งเป็นพารามิเตอร์ของเมธอด คุณสามารถทำอะไรก็ได้กับค่าที่วนได้ภายในเมธอดนี้

ในการวนค่าใน Map ทั้งสองวิธีนั้นให้ผลลัพธ์การทำงานที่เหมือนกัน แต่ในทางปฏิบัติแล้วเรามักใช้วิธีแรกมากกว่า

ในตัวอย่างก่อนหน้านั้นเป็นการวนทั้ง Key และ Value จาก Map พร้อมกันในครั้งเดียว อย่างไรก็ตาม คุณอาจต้องการวนเพียงอย่างใดอย่างหนึ่งก็ได้ เช่น Key หรือ Value เพียงอย่างเดียว ในตัวอย่างนี้ เราจะมาดูการใช้งานเมธอดสำหรับวนเพียง Key หรือ Value เพียงอย่างเดียว

HashMapEx4.java
package com.marcuscode.hashmap;

import java.util.Collection;
import java.util.HashMap;
import java.util.Set;

public class HashMapEx4 {

    public static void main(String[] args) {

        // Creating map object
        HashMap<String, String> favoriteLang = 
                new HashMap<String, String>();

        // Adding data to map
        favoriteLang.put("metin", "Java");
        favoriteLang.put("jacob", "Scala");
        favoriteLang.put("chris", "Python");
        favoriteLang.put("mateo", "C++");

        System.out.println("Iterate over keys");
        Set<String> keySet = favoriteLang.keySet();
        for (String key :keySet) {
            System.out.println(key + ": " + favoriteLang.get(key));  
        }

        System.out.println("Iterate over values");
        Collection<String> valuesCol = favoriteLang.values();
        for (String value: valuesCol) {
            System.out.println(value); 
        }

    }

}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Iterate over keys
chris: Python
mateo: C++
jacob: Scala
metin: Java
Iterate over values
Python
C++
Scala
Java

ในตัวอย่างนี้ จะเป็นการวนรอบค่าภายใน HashMap ด้วย Key หรือ Value เพียงอย่างเดียว โดยการใช้เมธอด keySet() สำหรับวนรอบ Key และเมธอด values() สำหรับวนรอบ Value ตามลำดับ

Set<String> keySet = favoriteLang.keySet();
for (String key :keySet) {
    System.out.println(key + ": " + favoriteLang.get(key));  
}

เพื่อวนรอบ Key ทั้งหมดภายใน HasMap เมธอด keySet() ส่งค่ากลับเป็น Iterator ออบเจ็คของคลาส Set ที่เราสามารถใช้คำสั่ง for loop วนอ่านค่า Key ได้ มันเป็นวิธีที่เรียบง่ายในการวนค่า Key ใน Map นอกจากนี้ค่าของ Key ที่วนออกมาได้แล้วนั้นยังสามารถเข้าถึงค่าภายใน Map ด้วยเมธอด get() ได้หากต้องการ

Collection<String> valuesCol = favoriteLang.values();
for (String value: valuesCol) {
    System.out.println(value); 
}

ในกรณีที่ต้องการวนเพียง Value เราสามารถใช้เมธอด values() มันส่งค่ากลับเป็น Iterator ออบเจ็คเช่นกัน แต่จากคลาส Collection แทน จากนั้นเราใช้คำสั่ง for loop สำหรับวนค่าและแสดงออกทางหน้าจอ

ลำดับของการวน: การวนรอบ HashMap นั้นลำดับที่ได้จากการวนจะไม่แน่นอน หรืออาจไม่เหมือนกับตอนที่เพิ่มเข้าไปใน Map นั่นเป็นเพราะว่า Map ไม่ได้เก็บข้อมูลในรูปแบบลำดับ นี่ก็เพื่อประสิทธิภาพและความเร็วในการเพิ่ม การอ่าน และการวนรอบนั่นเอง ดังนั้นคุณไม่ควรยึดติดกับลำดับที่วนได้จาก Map ในการทำงาน

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับการใช้งาน HashMap ในภาษา Java เราได้พูดถึงการเพิ่ม การลบ และการอ่านข้อมูลภายใน Map และการใช้งานเมธอดต่างๆ เพื่ออำนวยความสะดวกในการเขียนโปรแกรม และในตอนท้ายคุณได้เรียนรู้การวนอ่านค่า Key และ Value ใน Map ในการใช้เมธอดต่างๆ