Ένα Map είναι μια δομή δεδομένων για την αποθήκευση ζευγών κλειδιού-τιμής. Μοιάζει με τα λεξικά σε άλλες γλώσσες προγραμματισμού. Η διεπαφή Map ορίζει τις πράξεις που μπορείς να κάνεις με ένα Map.
Η Java έχει αρκετές διαφορετικές υλοποιήσεις του Map. Το HashMap είναι μία από τις πιο συνηθισμένες.
// Make an instance
Map<String, Integer> fruitPrices = new HashMap<>();
Όταν ορίζεις μια μεταβλητή Map, συνιστάται να την ορίζεις ως τύπο Map και όχι ως τον συγκεκριμένο τύπο, όπως στο παραπάνω παράδειγμα.
Αυτή η πρακτική κάνει εύκολη την αλλαγή της υλοποίησης του Map αργότερα.
Το HashMap έχει επίσης έναν κατασκευαστή αντιγραφής.
// Make a copy of a map
Map<String, Integer> copy = new HashMap<>(fruitPrices);
Πρόσθεσε καταχωρήσεις στο Map χρησιμοποιώντας το put.
fruitPrices.put("apple", 100);
fruitPrices.put("pear", 80);
// => { "apple" => 100, "pear" => 80 }
Μόνο μία τιμή μπορεί να συσχετιστεί με κάθε κλειδί.
Αν καλέσεις το put με το ίδιο κλειδί, θα ενημερωθεί η τιμή του κλειδιού.
fruitPrices.put("pear", 40);
// => { "apple" => 100, "pear" => 40 }
Χρησιμοποίησε το get για να πάρεις την τιμή για ένα κλειδί.
fruitPrices.get("apple"); // => 100
Χρησιμοποίησε το containsKey για να δεις αν το Map περιέχει ένα συγκεκριμένο κλειδί.
fruitPrices.containsKey("apple"); // => true
fruitPrices.containsKey("orange"); // => false
Αφαίρεσε καταχωρήσεις με το remove.
fruitPrices.put("plum", 90); // Add plum to map
fruitPrices.remove("plum"); // Removes plum from map
Η μέθοδος size επιστρέφει τον αριθμό των καταχωρήσεων.
fruitPrices.size(); // Returns 2
Μπορείς να χρησιμοποιήσεις τις μεθόδους keySet ή values για να πάρεις τα κλειδιά ή τις τιμές ενός Map ως Set ή ως συλλογή αντίστοιχα.
fruitPrices.keySet(); // Returns "apple" and "pear" in a set
fruitPrices.values(); // Returns 100 and 80, in a Collection
HashMap χρησιμοποιεί hashCode και equals
Τα HashMap χρησιμοποιούν τις μεθόδους hashCode και equals του αντικειμένου για να καθορίσουν πού θα αποθηκεύσουν και πώς θα ανακτήσουν τις τιμές για ένα κλειδί. Για αυτόν τον λόγο, είναι σημαντικό οι τιμές επιστροφής τους να μην αλλάζουν ανάμεσα στην αποθήκευση και την ανάκτησή τους, αλλιώς το HashMap μπορεί να μην μπορεί να βρει την τιμή.
Για παράδειγμα, ας πούμε ότι έχουμε την παρακάτω κλάση που θα χρησιμοποιηθεί ως κλειδί σε ένα Map:
public class Stock {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (Objects.equals(Stock.class, obj.getClass()) && obj instanceof Stock other) {
return Objects.equals(name, other.name);
}
return false;
}
}
Τα hashCode και equals εξαρτώνται από το πεδίο name, το οποίο μπορεί να αλλάξει μέσω της setName.
Η αλλαγή του hashCode μπορεί να έχει απροσδόκητα αποτελέσματα:
Stock stock = new Stock();
stock.setName("Beanies");
Map<Stock, Integer> stockCount = new HashMap<>();
stockCount.put(stock, 80);
stockCount.get(stock); // Returns 80
Stock other = new Stock();
other.setName("Beanies");
stockCount.get(other); // Returns 80 because "other" and "stock" are equal
stock.setName("Choccies");
stockCount.get(stock); // Returns null because hashCode value has changed
stockCount.get(other); // Also returns null because "other" and "stock" are not equal
stock.setName("Beanies");
stockCount.get(stock); // HashCode restored, so returns 80 again
stockCount.get(other); // Also returns 80 again because "other" and "stock" are back to equal
Ένας άλλος συνηθισμένος τρόπος για να δημιουργήσεις Map είναι να χρησιμοποιήσεις το Map.of ή το Map.ofEntries.
// Using Map.of
Map<String, Integer> temperatures = Map.of("Mon", 30, "Tue", 28, "Wed", 32);
// or using Map.ofEntries
Map<String, Integer> temperatures2 = Map.ofEntries(
Map.entry("Mon", 30),
Map.entry("Tue", 28),
Map.entry("Wed", 32)
);
Σε αντίθεση με το HashMap, γεμίζουν το Map εκ των προτέρων και γίνονται μόνο για ανάγνωση μόλις δημιουργηθούν.
Το Map.copyOf δημιουργεί ένα αντίγραφο ενός Map μόνο για ανάγνωση.
Map<String, Integer> readOnlyFruitPrices = Map.copyOf(fruitPrices);
Η κλήση μεθόδων όπως put, remove ή clear έχει ως αποτέλεσμα μια UnsupportedOperationException.