2010-07-22 55 views
7

Tôi có một hàm trả về giá trị int cho một khóa nhất định (từ HashMap<String, Integer>). Nếu khóa không tồn tại, tôi muốn trả lại thứ mà người gọi có thể kiểm tra. Có vẻ như, phổ biến nhất, đây sẽ là một "trả về -1 nếu khóa không tồn tại" loại điều. Tuy nhiên, tôi không thể dự trữ -1 cho mục đích đó trong trường hợp của tôi, bởi vì số âm là các giá trị khả thi cho các khóa mà làm tồn tại.Trả về "null" trên hàm trả về nguyên thủy?

duy nhất lựa chọn khác tôi đã có thể đưa ra như sau:

  1. chuyển đổi loại hình trở lại Integer lớp wrapper và kiểm tra null
  2. Return cái gì đó rất khó xảy ra, chẳng hạn như Integer.MIN_VALUE
  3. Thực hiện chức năng boolean keyExists(String key) bổ sung cần được gọi trước tiên
  4. Chuyển sang float và sử dụng NaN thay vì

Tôi viết bài này bằng Java, nhưng những người có nguồn gốc ngôn ngữ tương tự được hoan nghênh đăng. Cảm ơn!

+1

# 4 là thú vị . Làm thế nào để bạn kiểm tra NaN? NaN! = NaN là đúng. –

+1

Float.isNaN (float);) IMHO float gần như không bao giờ là một ý tưởng hay. hãy thử dài hoặc gấp đôi. –

Trả lời

14

Tùy chọn đầu tiên, theo ý kiến ​​của tôi, trong sạch nhất. Các số ma thuật như -1 và Integer.MIN_VALUE là loại lộn xộn, đặc biệt khi các giá trị không trực quan. Đó là một giải pháp C thành ngữ, mà các nhà phát triển Java sẽ ghét bạn. Tùy thuộc vào những gì bạn đang thực sự sử dụng này cho bạn cũng có thể ném một "KeyNotFoundException" nếu điều này chỉ xảy ra trong trường hợp "đặc biệt".

+2

+1 cho đề nghị dòng chảy đặc biệt –

+0

Tôi đã đi với một trở về một int, nhưng ném một ngoại lệ thời gian chạy nếu không tìm thấy chìa khóa (sau đó có một keyExists (key) chức năng). Bạn có nghĩ rằng việc sử dụng Integer sẽ là một giải pháp tốt hơn? Nó có lẽ sẽ hiệu quả hơn, bởi vì HashMap của tôi đã lưu trữ các giá trị như Số nguyên ... – idolize

+1

Đừng ném một ngoại lệ thời gian chạy (một cái gì đó bắt nguồn từ RuntimeException). Sử dụng ngoại lệ được kiểm tra thường xuyên. Nếu bạn muốn làm cho chương trình của bạn đa luồng, hãy nhớ rằng phải gọi hàm keyExists trước khi tra cứu giá trị bằng hai cuộc gọi chức năng riêng biệt sẽ tạo ra điều kiện chủng tộc trừ khi bạn khóa một số đối tượng trước khi bạn gọi nó mỗi lần hoặc đơn giản bỏ phần keyExists và kết thúc cuộc gọi trong khối try/catch cho KeyNotFoundException. – Hut8

1

Mặc dù nó phụ thuộc rất nhiều vào ứng dụng và biết các ràng buộc, tôi muốn # 1 ở trên. Lý do là bởi vì sau đó nó là rõ ràng - nó luôn luôn là tốt hơn để có một tình hình rõ ràng hơn là một tiềm ẩn - chẳng hạn như MIN_VALUE - theo kinh nghiệm của tôi.

Một tùy chọn khác là có đối tượng bao bọc chứa giá trị kết quả dưới dạng int nguyên thủy, nhưng cũng có giá trị trạng thái hoặc giá trị tương tự. Vì vậy, nó có thể là một cái gì đó như:

public class Wrapper { 
    private int value = Integer.MIN_VALUE; 
    private boolean isValid; 
    // appropriate getters and setters etc. 
} 

Bạn cũng có thể bao gồm một enum thay vì một boolean để có một nhà nước để thay thế, tùy thuộc vào sự phức tạp của vấn đề. Nếu bạn thấy phần tử này chứa thông tin tổng hợp - tập hợp thông tin được khóa bằng các khóa đơn hoặc một thứ tương tự - đối tượng chứa hoặc đối tượng trạng thái có thể rất có giá trị trong những trường hợp đó.

3

Tôi bỏ phiếu cho ném ngoại lệ đã kiểm tra tại đây. Nói chung tôi không thích ngoại lệ đã kiểm tra nhưng có vẻ như một điều hợp lý để làm trong trường hợp này. Trường hợp giá trị không có mặt sẽ cần phải được xử lý riêng biệt với trường hợp giá trị hiện diện, sử dụng một ngoại lệ sẽ làm rõ điều đó.

Thực tế ý tưởng của bạn là thêm một khóa Phương pháp hiện có là tốt nhất trong những ý tưởng bạn liệt kê, bởi vì nó không dựa vào người dùng biết tìm kiếm một giá trị đặc biệt. Nếu bạn đi theo cách đó thì bạn có thể ném một ngoại lệ như là một kế hoạch sao lưu trong trường hợp nội dung bản đồ thay đổi giữa các cuộc gọi đến keyExists và truy xuất.

+1

Tôi nghĩ rằng đây sẽ là một giải pháp thực sự tốt, bằng cách nào đó, không bao giờ vượt qua tâm trí của tôi. Nhưng, trong trường hợp cụ thể của tôi, hiệu suất sẽ là một chút của một vấn đề vì vậy tôi nghĩ rằng tôi sẽ tránh ngoại lệ. – idolize

+0

@mxrider: Hiệu suất là vấn đề nên bạn muốn tránh ngoại lệ? Umm, cái gì? Nghe có vẻ như "tối ưu hóa/sai lầm" sớm/sai lầm với tôi. Tôi muốn nói viết mã sạch nhất có thể, sau đó kiểm tra với một hồ sơ nếu có vấn đề hiệu suất thực tế với nó. – Jonik

+0

Tôi đoán tôi nên nói lại. Dựa vào thử/nắm bắt trong các tình huống mà hiệu suất là quan trọng (chẳng hạn như trong một vòng lặp hoặc trên một bộ đếm thời gian) có thể gây ra một nút cổ chai. Tôi thực sự đã kết thúc yêu cầu một hàm keyExists() để sử dụng và hàm getValue() của tôi ném một RuntimeException đặc biệt nếu khóa không được tìm thấy - theo cách này tôi không cần try/catch, nhưng tôi vẫn đang theo dõi tốt nhất thực hành. – idolize

0

Tùy chọn 5: Ném ngoại lệ

Mặc dù, trong trường hợp này, tôi sẽ bỏ phiếu cho việc sử dụng lớp Integer.

0

Tôi nghĩ bạn nên kết hợp các tùy chọn # 1 và # 3, vì điều đó phù hợp với hành vi của HashMap bên dưới. Từ số get method documentation của HashMap:

Trả về giá trị mà khóa được chỉ định được ánh xạ trong bản đồ băm nhận dạng này hoặc null nếu bản đồ không chứa ánh xạ cho khóa này. Giá trị trả về của null không nhất thiết cho biết rằng bản đồ không chứa ánh xạ cho khóa; nó cũng có thể là bản đồ một cách rõ ràng ánh xạ các khóa để null. Phương thức containsKey có thể được sử dụng để phân biệt hai trường hợp này.

0
  1. Thay đổi kiểu trả về đến lớp wrapper Integer và kiểm tra null.

Đây là tùy chọn phổ biến hơn.

1

float không an toàn vì không phải tất cả giá trị int đều có thể được biểu diễn chính xác dưới dạng giá trị int. dài là một lựa chọn tốt hơn vì tất cả các giá trị int có thể được lưu trữ an toàn lâu và bạn sẽ có nhiều giá trị hơn cho việc không tìm thấy.

Nếu bạn đang sử dụng một bản đồ bạn có một Integer đối tượng nào vậy tại sao không trở lại đó (hoặc null)

Nếu bạn thực sự muốn sử dụng nguyên thủy (cho hiệu quả ??) Tôi đề nghị bạn nhìn vào TObjectIntHashMap để thay thế. Điều này sử dụng các giá trị int nguyên thủy. Để kiểm tra sự vắng mặt, bạn phải kiểm tra hàm containsKey() một cách riêng biệt.

1

Hai tình huống điển hình:

  1. Bạn có một kỳ vọng cao của tìm một giá trị cho một chìa khóa riêng.
  2. Bạn không chắc chắn liệu một khóa cụ thể có một giá trị được lưu trữ hay không.

Nếu giả định 1 sai, thì có thể là lỗi, vì vậy hãy bảo vệ giả định của bạn trong phương thức truy cập bằng xác nhận.

Nếu 2 được áp dụng, bạn sẽ chắc chắn về những gì được trả về? do đó cung cấp phương pháp thử nghiệm như "keyExists" và biết rõ trước khi truy cập bản đồ.

Trong trường hợp 1, không yêu cầu kiểm tra, sẽ sạch hơn nhiều, nhưng quyền truy cập sẽ thất bại nếu bạn sai. Với các trường hợp đặc biệt như -1 hoặc Integer.MIN_VALUE, rất khó để đảm bảo rằng chúng sẽ không được sử dụng.

Ngôn ngữ như Haskell, Scala và C# có các loại đặc biệt để truyền đạt sự hiện diện/vắng mặt của một giá trị mà là tốt hơn nhiều so sử dụng null (nếu bạn quên để kiểm tra bạn có thể sẽ nhận được một NullPointerException)