Việc thêm khóa hoặc giá trị null vào HashMap trong Java là gì?


91

HashMap cho phép một khóa null và bất kỳ số giá trị null nào. Công dụng của nó là gì?


11
"Có lẽ vấn đề không phải là không có gì làm phiền chúng ta, mà là chúng ta đang làm phiền nó."
bmargulies

3
Trong Guava, google collection, nhiều lớp không cho phép null và lý do đằng sau đó là 95% trường hợp không cần null và chúng có thể đại diện cho lỗi, có khả năng khó tìm.
stivlo

Điều kỳ lạ là, ConcurrentHashMapnó không hỗ trợ phím null, trong khi HashMapđó.
codepleb

2
Chỉ HashMap cho phép null :)
subhashis

Câu trả lời:


126

Tôi không khẳng định những gì bạn đang hỏi, nhưng nếu bạn đang tìm kiếm một ví dụ về thời điểm một người muốn sử dụng khóa null, tôi thường sử dụng chúng trong bản đồ để thể hiện trường hợp mặc định (tức là giá trị nên được sử dụng nếu không có khóa nhất định):

Map<A, B> foo;
A search;
B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);

HashMapxử lý đặc biệt các khóa null (vì nó không thể gọi .hashCode()trên một đối tượng null), nhưng các giá trị null không phải là bất kỳ điều gì đặc biệt, chúng được lưu trữ trong bản đồ giống như bất kỳ thứ gì khác


4
Vì vậy, nếu .hashCode () không thể thực hiện được trên null, ai sẽ quyết định dòng nào mà khóa null sẽ nhập?
Pacerier

26
@Pacerier Có một phương thức đặc biệt trong HashMap( putForNullKey) xử lý nó; nó sẽ lưu nó trong bảng 0
Michael Mrozek

1
@MichaelMrozek dòng cuối cùng của bạn B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);Tôi nghĩ chúng ta có thể đơn giản gọi phương thức get trên phím tìm kiếm sẽ có cùng kết quả. B val = foo.get(search);bạn có thể vui lòng sửa cho tôi nếu tôi đang làm gì đó sai?
dheerajraaj

6
@ dheeraj92 Mã của bạn sẽ được đặt valthành nullnếu khóa không tồn tại; của tôi đặt nó thành bất kỳ nullbản đồ nào trong bản đồ. Đó là vấn đề, tôi lưu trữ một giá trị không null mặc định tại nullquan trọng trong bản đồ và sử dụng nó nếu phím thực tế không tồn tại
Michael Mrozek

28

Một ví dụ sẽ là mô hình cây. Nếu bạn đang sử dụng HashMap để biểu diễn cấu trúc cây, trong đó khóa là cha và giá trị là danh sách con, thì các giá trị cho nullkhóa sẽ là các nút gốc.


6

Một ví dụ về việc sử dụng cho null các giá trị là khi sử dụng HashMaplàm bộ nhớ cache cho các kết quả của một hoạt động tốn kém (chẳng hạn như cuộc gọi đến một dịch vụ web bên ngoài) có thể trả về null.

Việc đưa một nullgiá trị vào bản đồ sau đó cho phép bạn phân biệt giữa trường hợp thao tác không được thực hiện cho một khóa nhất định ( cache.containsKey(someKey)trả về false) và trường hợp hoạt động đã được thực hiện nhưng trả về nullgiá trị ( cache.containsKey(someKey)trả về true, cache.get(someKey)trả về null).

Nếu không có nullgiá trị, bạn sẽ phải đặt một số giá trị đặc biệt vào bộ nhớ cache để chỉ ra nullphản hồi hoặc đơn giản là không lưu vào bộ nhớ cache phản hồi đó và thực hiện thao tác mọi lúc.


3

Các câu trả lời cho đến nay chỉ xem xét giá trị của có một nullchìa khóa, nhưng câu hỏi cũng hỏi về any number of null values.

Lợi ích của việc lưu trữ giá trị nullso với một khóa trong HashMap cũng giống như trong cơ sở dữ liệu, v.v. - bạn có thể ghi lại sự khác biệt giữa việc có giá trị trống (ví dụ: chuỗi "") và không có giá trị nào (null) .


2

Đây là ví dụ duy nhất của tôi về trường hợp nullkhóa có thể hữu ích:

public class Timer {
    private static final Logger LOG = Logger.getLogger(Timer.class);
    private static final Map<String, Long> START_TIMES = new HashMap<String, Long>();

    public static synchronized void start() {
        long now = System.currentTimeMillis();
        if (START_TIMES.containsKey(null)) {
            LOG.warn("Anonymous timer was started twice without being stopped; previous timer has run for " + (now - START_TIMES.get(null).longValue()) +"ms"); 
        }
        START_TIMES.put(null, now);
    }

    public static synchronized long stop() {
        if (! START_TIMES.containsKey(null)) {
            return 0;
        }

        return printTimer("Anonymous", START_TIMES.remove(null), System.currentTimeMillis());
    }

    public static synchronized void start(String name) {
        long now = System.currentTimeMillis();
        if (START_TIMES.containsKey(name)) {
            LOG.warn(name + " timer was started twice without being stopped; previous timer has run for " + (now - START_TIMES.get(name).longValue()) +"ms"); 
        }
        START_TIMES.put(name, now);
    }

    public static synchronized long stop(String name) {
        if (! START_TIMES.containsKey(name)) {
            return 0;
        }

        return printTimer(name, START_TIMES.remove(name), System.currentTimeMillis());
    }

    private static long printTimer(String name, long start, long end) {
        LOG.info(name + " timer ran for " + (end - start) + "ms");
        return end - start;
    }
}

Nếu bạn đang cố gắng dừng một bộ đếm thời gian không tồn tại hoặc một bộ hẹn giờ đã bị dừng, đó sẽ là một lỗi, không được bỏ qua.
Vụ kiện của Fund Monica

@QPaysTaxes - Phụ thuộc vào ý định của bạn. Nếu bạn muốn một tiện ích nhẹ có thể dễ dàng sử dụng, bạn thường không muốn có throw Exceptionnó. Bên cạnh đó, việc cố gắng dừng một bộ đếm thời gian không tồn tại hoặc đã dừng là điều mà người gọi thường có thể khôi phục.
aroth

1

Một ví dụ khác: Tôi sử dụng nó để nhóm Dữ liệu theo ngày. Nhưng một số dữ liệu không có ngày tháng. Tôi có thể nhóm nó với tiêu đề "NoDate"


0

Khóa null cũng có thể hữu ích khi bản đồ lưu trữ dữ liệu cho các lựa chọn giao diện người dùng trong đó khóa bản đồ đại diện cho một trường đậu.

Ví dụ, giá trị trường rỗng tương ứng sẽ được biểu thị là "(vui lòng chọn)" trong lựa chọn giao diện người dùng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.