2011-08-23 37 views
7

Bạn sẽ cân nhắc điều gì hiệu quả hơn?Giá trị Java Enum Hiệu quả của sản phẩm

Việc sử dụng 'các ngày trong tuần' chỉ là một ví dụ:

public enum WeekDay { 
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY; 
} 

Vòng qua và xác minh chuỗi ngày đầu tiên:

public void parseString(String line) { 
    String[] tokens = line.split(); 
    String day = tokens[1]; // day 'should' always be a weekday 
    if (isValidWeekDay(day)) { 
     WeekDay weekDay = WeekDay.valueOf(day); // won't throw exception 
     ... 
    } else { 
     throw new InvalidWeekDayException(day); // subclass of RuntimeException 
    } 
} 
private boolean isValidWeekDay(String day) { 
    for (WeekDay weekDay : WeekDay.values()) { 
     if(weekDay.toString().equals(day)) 
      return true; 
    } 
    return false; 
} 

Hoặc vì trong 99,99% các trường hợp, ngày sẽ được chính xác:

public void parseString(String line) { 
    String[] tokens = line.split(); 
    String day = tokens[1]; // day 'should' always be a weekday 
    try { 
     WeekDay weekDay = WeekDay.valueOf(day); // might throw exception 
     ... 
    } catch (IllegalArgumentException e) { 
     throw new InvalidWeekDayException(day, e); 
    } 
} 

Cập nhật:

Để làm rõ, chuỗi đầu vào sẽ đến từ ứng dụng khách chứ không phải người dùng. Nói cách khác, nó sẽ là một lỗi để nhận được một ngày làm việc không trong ví dụ này.

+7

Nghe có vẻ giống như một câu trả lời khéo léo, nhưng tôi sẽ xem xét câu trả lời nhanh nhất khi tôi định dạng nó là hiệu quả nhất. –

+0

Chuỗi có xuất phát từ thứ gì đó mà người dùng nhập vào hay tất cả đều đến từ nội bộ? – DHall

+0

Tôi sẽ sử dụng thay vào đó, nếu bạn thực sự đang thực hiện một số ngày trong tuần: http://joda-time.sourceforge.net/field.html#dayOfWeek – NimChimpsky

Trả lời

4

Tôi biết đó là một bài đăng cũ, nhưng tôi tin rằng kết quả sau sẽ vẫn thú vị. Tôi chạy 10000000 kiểm tra để tìm một phần tử trong enum ENUM {FIRST, SECOND, THIRD, FOURTH, LAST} bằng JDK 1.8. Bảng dưới đây cho thấy thời gian được yêu cầu bởi vòng lặp đơn giản và valueOf().

 
text  loop valueOf ratio 
------------------------------ 
"FIRST" 121 65  186% 
"LAST" 188 57  330% 
"foo" 155 8958  1.7% 

Kết luận - Tôi sẽ không sử dụng valueOf() nếu tôi mong đợi các giá trị không khớp với enum.

+0

Thử nghiệm của bạn có tập trung vào việc đạt hiệu quả sử dụng ngoại lệ không? Hoặc là sự khác biệt b/c của một số chi tiết thực hiện trong phương thức valueOf()? Bạn đã chạy điều này trong một JVM bình thường đang chạy (tức là không ở chế độ gỡ lỗi) với JIT đã được bật chưa? Và bạn đã làm nóng lên JIT bằng cách cranking thông qua một loạt các lần lặp trước khi bạn bắt đầu hẹn giờ của bạn?Khi tôi đã thử nghiệm với zxing, tôi thấy loại sự khác biệt mà bạn đang hiển thị khi chạy thử nghiệm ở chế độ gỡ lỗi - nhưng khi trình gỡ lỗi đã hết, hiệu suất khá giống nhau. –

+0

Xin chào @Kevin. Có nhiều thông số có thể ảnh hưởng đến các số liệu cụ thể trong bảng. Tôi chỉ tò mò về "chi phí ngoại lệ" trong môi trường _my_ (Oracle JVM 1.6 + 64-bit Win7 + Chế độ gỡ lỗi). Tôi đã rất ngạc nhiên bởi kết quả mà tôi quyết định xuất bản nó. Tôi dự kiến ​​tỷ lệ 10-20% trong trường hợp xấu nhất dựa trên trải nghiệm C++ của tôi. – aknopov

2

Lưu các chuỗi hợp lệ trong một số HashSet và quyết định xem chuỗi có phải là ngày hợp lệ hay không dựa trên Set.contains(...).

Tập thể là một static final Set, và bạn có thể bọc trong một unmodifiable cho biện pháp tốt:

private static final Map<String> WEEKDAY_STRINGS; 
static { 
    HashSet<String> set = new HashSet(); 
    for (WeekDay d : WeekDay.values()) { 
    set.add(d.toString()); 
    } 
    WEEKDAY_STRINGS = Collections.unmodifiableSet(set); 
} 
+1

điều này là quá phức tạp vấn đề imho – NimChimpsky

2

Vòng lặp không làm bất cứ điều gì mà gọi điện thoại valueOf không, họ có cùng chức năng: kiểm tra cho dù chuỗi của bạn là enum hợp lệ. Bạn nghĩ gì bạn đạt được từ tùy chọn đầu tiên?

Lựa chọn thứ hai là tốt nhất:

try { 
    WeekDay weekDay = WeekDay.valueOf(day); // might throw exception 
     ... 
    } catch (IllegalArgumentException e) { 
     throw new InvalidWeekDayException(day); 
    } 
+0

Tôi đoán tất cả của nó xuống như thế nào phổ biến ngày không hợp lệ được. Nếu 50% số ngày không hợp lệ, thì một số người cho rằng nó rất không hiệu quả để ném/bắt một ngoại lệ. Tuy nhiên nếu nó chỉ là lỗi ứng dụng khách hiếm, thì đây chắc chắn là con đường để đi. – toolkit

2

Hoặc bạn có thể tạo một tra cứu các giá trị enum trong enum của bạn khi tải hạng nhất (xem modifier tĩnh) và xác nhận sử dụng get() như hình dưới đây:

private String dayName; 
private static final Map<String,Weekday> lookup = new HashMap<String, Weekday>(); 
static{ 
    for (Weekday day: values()){ 
     lookup.put(day.dayName, d); 
    } 
} 
public static Weekday get(String _name){ 
    return lookup.get(_name); 
} 

Hãy cho tôi biết nếu bạn cần biết thêm chi tiết

5

Như đã nhận xét, bạn sẽ phải cấu để tìm hiểu cho chắc chắn. Ngay cả trong cách tiếp cận phân tích cú pháp của riêng bạn, bạn có thể làm cho nó nhanh hơn bằng cách trả về enum khi bạn phân tích cú pháp danh sách.

private WeekDay getValidWeekDay(String day) { 
    for (WeekDay weekDay : WeekDay.values()) { 
     if(weekDay.toString().equals(day)) 
      return weekDay; 
    } 
    return null; 
} 

Trừ khi đây là thời điểm thành phần quan trọng của một ứng dụng, tôi sẽ không phải lo lắng về nó trong cả hai trường hợp và chỉ cần có những phương pháp có thể đọc được hầu hết. Tôi nghĩ rằng sẽ sử dụng phương thức WeekDay.valueOf().

Nếu bạn không muốn xử lý ngoại lệ, hãy tạo Bản đồ giá trị của bạn trong enum và thực hiện tương đương với valueOf() từ tra cứu trả về null nếu không tìm thấy.

public enum WeekDay { 
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY; 

    private static Map<String, WeekDay> valueMap; 

    public static WeekDay getValue(String possibleName) 
    { 
     if (valueMap == null) 
     { 
      valueMap = new HashMap<String, WeekDay>(); 
      for(WeedDay day: values()) 
       valueMap.put(day.toString(), day); 
     } 
     return valueMap.get(possibleName); 

    } 
} 

Đây là phương pháp hiệu quả của phương thức valueOf(), ngoại trừ trường hợp không tìm thấy IllegalArgumentException. Cách tiếp cận này sẽ đơn giản trả về null, do đó không tạo ra stacktrace.

8

Mối quan tâm hiệu suất về phương pháp tiếp cận thứ 2 là gì? Nắm bắt một ngoại lệ như thế có giá gần như không có gì. Việc sử dụng các ngoại lệ cho luồng điều khiển thông thường thường là một ý tưởng tồi từ quan điểm thiết kế, những ngày mà đây là một sự xem xét hiệu suất đã biến mất lâu rồi.Trong một trình gỡ lỗi, sử dụng các ngoại lệ như các hoạt động kiểm soát quan trọng sẽ làm chậm mọi thứ xuống khoảng 10 lần nhưng điều này được tối ưu hóa bởi JIT và không có tác động đo lường được trong sản xuất.

Những con số này dựa trên kinh nghiệm với đánh giá tôi đã làm trong dự án zxing, sử dụng các ngoại lệ cho tất cả các loại điều khiển luồng. Khi tôi lần đầu tiên nhìn thấy nó, tôi đã kinh hoàng. Tôi vẫn nghĩ đó không phải là thiết kế tốt nhất, nhưng tôi đã làm khá nhiều thử nghiệm và có thể nói với một chút tự tin rằng nó không có tác động thực sự đến hiệu suất. Và đây là một thuật toán sử dụng các ngoại lệ trên khắp nơi để kiểm soát luồng. Tình huống của bạn, nơi ngoại lệ sẽ chỉ bị ném vào những trường hợp đặc biệt cao, là một vấn đề không phải.

Chỉnh sửa: Tôi đã có một hoặc hai câu trả lời cho câu trả lời của mình và tôi muốn đảm bảo rằng tôi siêu rõ ràng về những gì tôi đang nói: Tôi không nghĩ rằng nên sử dụng ngoại lệ cho dòng điều khiển bình thường. Chỉ vì hiệu suất không phải là một đối số tốt cho việc không sử dụng ngoại lệ theo cách này không có nghĩa là không có lý do chính đáng nào khác (như khả năng đọc, khả năng kiểm tra, khả năng mở rộng). Trong trường hợp của OP, việc sử dụng một ngoại lệ hoàn toàn được gọi là, và chắc chắn sẽ không gây ra bất kỳ loại vấn đề hiệu suất.

+1

Cảm ơn lời khuyên của Kevin. – toolkit

3

Nếu câu hỏi của bạn thực sự là về hiệu quả tìm kiếm trong số 7 mục bạn đã lãng phí quá nhiều thời gian vào nó. Ngay cả các thuật toán tìm kiếm nhanh nhất cũng mang lại lợi ích không hoặc lợi ích tiêu cực cho đến khi N> 15 hoặc hơn, ngoài lợi ích của O (1).

Các vấn đề liên quan