Enums là gì và tại sao chúng hữu ích?


488

Hôm nay tôi đã duyệt qua một số câu hỏi trên trang web này và tôi thấy một đề cập đến việc enum được sử dụng trong mô hình đơn lẻ về lợi ích an toàn của chủ đề có mục đích đối với giải pháp đó.

Tôi chưa bao giờ sử dụng enums và tôi đã lập trình trong Java hơn một vài năm nay. Và rõ ràng họ đã thay đổi rất nhiều. Bây giờ họ thậm chí còn hỗ trợ đầy đủ cho OOP trong chính họ.

Bây giờ tại sao và những gì tôi nên sử dụng enum trong lập trình hàng ngày?


6
Trong cuốn sách Java hiệu quả, Ấn bản thứ hai , Joshua Bloch đã trình bày về cách tiếp cận này trong Mục 3: Thi hành tài sản Singleton với một Nhà xây dựng tư nhân hoặc một loại enum , được in lại trong Tiến sĩ Dobb .
thùng rác

có thể trùng lặp Enum trong Java. Ưu điểm?
vây

Bạn không thể khởi tạo enums vì nó có hàm tạo riêng, chúng được khởi tạo ngay khi khởi động jvm, vì vậy singleton, Enums không phải là chủ đề an toàn.
Arnav Joshi

Câu trả lời:


633

Bạn nên luôn luôn sử dụng enums khi một biến (đặc biệt là tham số phương thức) chỉ có thể lấy một trong số một tập hợp nhỏ các giá trị có thể. Ví dụ sẽ là những thứ như hằng số loại (trạng thái hợp đồng: "vĩnh viễn", "tạm thời", "người học việc") hoặc cờ ("thực thi ngay", "thực thi hoãn").

Nếu bạn sử dụng enum thay vì số nguyên (hoặc mã String), bạn tăng kiểm tra thời gian biên dịch và tránh lỗi truyền vào các hằng không hợp lệ và bạn ghi lại giá trị nào là hợp pháp để sử dụng.

BTW, lạm dụng enum có thể có nghĩa là các phương thức của bạn làm quá nhiều (tốt hơn là nên có một vài phương thức riêng biệt, thay vì một phương thức có nhiều cờ sửa đổi những gì nó làm), nhưng nếu bạn phải sử dụng cờ hoặc mã loại, enums là con đường để đi

Ví dụ, cái nào tốt hơn?

/** Counts number of foobangs.
 * @param type Type of foobangs to count. Can be 1=green foobangs,
 * 2=wrinkled foobangs, 3=sweet foobangs, 0=all types.
 * @return number of foobangs of type
 */
public int countFoobangs(int type)

đấu với

/** Types of foobangs. */
public enum FB_TYPE {
 GREEN, WRINKLED, SWEET, 
 /** special type for all types combined */
 ALL;
}

/** Counts number of foobangs.
 * @param type Type of foobangs to count
 * @return number of foobangs of type
 */
public int countFoobangs(FB_TYPE type)

Một phương thức gọi như:

int sweetFoobangCount = countFoobangs(3);

sau đó trở thành:

int sweetFoobangCount = countFoobangs(FB_TYPE.SWEET);

Trong ví dụ thứ hai, ngay lập tức rõ ràng loại nào được cho phép, tài liệu và cách triển khai không thể không đồng bộ và trình biên dịch có thể thực thi điều này. Ngoài ra, một cuộc gọi không hợp lệ như

int sweetFoobangCount = countFoobangs(99);

không còn có thể.


41
Nếu bạn sử dụng enums và muốn cho phép kết hợp các giá trị, hãy sử dụng Enumset. Điều này đi kèm với tất cả các loại trình trợ giúp gọn gàng, như Enumset tĩnh công khai <FB_TYPE> ALL = EnumSet.allOf (FB_TYPE. Class);
RobAu

20
Những câu trả lời này là những câu tôi thực sự muốn thấy ở SO bởi vì ai đó đã nỗ lực thực sự trong đó, công việc tốt tôi hiểu enums ngay bây giờ!
Dediqated

1
Tôi không nghĩ nó đúng với điều đó you should *always* use enums when a variable can only take one out of a small set of possible values. Sử dụng các giá trị không đổi dưới dạng 'cờ nhị phân' (có logic logic or) có thể hữu ích cho các ứng dụng thời gian thực khi bạn thiếu bộ nhớ.
Elist

@Elist sử dụng enums làm tăng khả năng đọc mã của bạn, Nếu bạn sử dụng hằng số tại một số thời điểm bạn hoặc người kế nhiệm của bạn không biết tại sao nó được sử dụng ... :)
theRoot 19/215

136

Tại sao sử dụng bất kỳ tính năng ngôn ngữ lập trình? Lý do chúng tôi có ngôn ngữ là vì

  1. Các lập trình viên để thể hiện các thuật toán một cách hiệu quả và chính xác trong một dạng máy tính có thể sử dụng.
  2. Các nhà bảo trì để hiểu các thuật toán mà người khác đã viết và thực hiện các thay đổi chính xác .

Enums cải thiện cả khả năng chính xác và dễ đọc mà không cần viết nhiều bản tóm tắt. Nếu bạn sẵn sàng viết bản soạn sẵn, thì bạn có thể "mô phỏng" enums:

public class Color {
    private Color() {} // Prevent others from making colors.
    public static final Color RED = new Color();
    public static final Color AMBER = new Color();
    public static final Color GREEN = new Color();
}

Bây giờ bạn có thể viết:

Color trafficLightColor = Color.RED;

Các nồi hơi ở trên có nhiều tác dụng tương tự như

public enum Color { RED, AMBER, GREEN };

Cả hai đều cung cấp cùng một mức độ kiểm tra trợ giúp từ trình biên dịch. Nồi hơi chỉ là gõ nhiều hơn. Nhưng tiết kiệm rất nhiều thao tác gõ giúp lập trình viên hiệu quả hơn (xem 1), vì vậy đây là một tính năng đáng giá.

Nó cũng đáng giá cho ít nhất một lý do nữa:

Chuyển báo cáo

Một điều mà static finalmô phỏng enum ở trên không cung cấp cho bạn là switchtrường hợp tốt đẹp . Đối với các loại enum, trình chuyển đổi Java sử dụng loại biến của nó để suy ra phạm vi của các trường hợp enum, vì vậy đối với các trường hợp enum Colortrên, bạn chỉ cần nói:

Color color = ... ;
switch (color) {
    case RED:
        ...
        break;
}

Lưu ý rằng nó không có Color.REDtrong các trường hợp. Nếu bạn không sử dụng enum, cách duy nhất để sử dụng số lượng được đặt tên switchlà:

public Class Color {
    public static final int RED = 0;
    public static final int AMBER = 1;
    public static final int GREEN = 2;
}

Nhưng bây giờ một biến để giữ một màu phải có loại int . Trình biên dịch đẹp kiểm tra enum và static finalmô phỏng đã biến mất. Không vui.

Một thỏa hiệp là sử dụng một thành viên có giá trị vô hướng trong mô phỏng:

public class Color {
    public static final int RED_TAG = 1;
    public static final int AMBER_TAG = 2;
    public static final int GREEN_TAG = 3;

    public final int tag;

    private Color(int tag) { this.tag = tag; } 
    public static final Color RED = new Color(RED_TAG);
    public static final Color AMBER = new Color(AMBER_TAG);
    public static final Color GREEN = new Color(GREEN_TAG);
}

Hiện nay:

Color color = ... ;
switch (color.tag) {
    case Color.RED_TAG:
        ...
        break;
}

Nhưng lưu ý, thậm chí nhiều hơn nồi hơi!

Sử dụng enum như một singleton

Từ bản tóm tắt ở trên, bạn có thể thấy tại sao một enum cung cấp một cách để thực hiện một singleton. Thay vì viết:

public class SingletonClass {
    public static final void INSTANCE = new SingletonClass();
    private SingletonClass() {}

    // all the methods and instance data for the class here
}

và sau đó truy cập nó với

SingletonClass.INSTANCE

chúng ta chỉ có thể nói

public enum SingletonClass {
    INSTANCE;

    // all the methods and instance data for the class here
}

Điều này cho chúng ta điều tương tự. Chúng ta có thể thoát khỏi điều này bởi vì các enum Java được triển khai dưới dạng các lớp đầy đủ chỉ với một ít đường cú pháp được rắc lên trên cùng. Đây là một lần nữa ít nồi hơi, nhưng nó không rõ ràng trừ khi thành ngữ quen thuộc với bạn. Tôi cũng không thích thực tế rằng bạn sẽ có được các chức năng enum khác nhau mặc dù họ không có ý nghĩa nhiều đối với singleton: ordvalues, vv (Có thực sự là một mô phỏng phức tạp hơn nơi Color extends Integermà sẽ làm việc với switch, nhưng nó quá phức tạp mà nó thậm chí nhiều hơn cho thấy rõ tại saoenum là một ý tưởng tốt hơn.)

Chủ đề an toàn

An toàn chủ đề là một vấn đề tiềm năng chỉ khi các singletons được tạo ra một cách lười biếng mà không có khóa.

public class SingletonClass {
    private static SingletonClass INSTANCE;
    private SingletonClass() {}
    public SingletonClass getInstance() {
        if (INSTANCE == null) INSTANCE = new SingletonClass();
        return INSTANCE;
    }

    // all the methods and instance data for the class here
}

Nếu nhiều luồng gọi getInstanceđồng thời trong khi INSTANCEvẫn là null, bất kỳ số lượng phiên bản nào cũng có thể được tạo. Thật tệ. Giải pháp duy nhất là thêm synchronizedquyền truy cập để bảo vệ biến INSTANCE.

Tuy nhiên, static finalđoạn mã trên không có vấn đề này. Nó tạo ra cá thể háo hức vào thời gian tải lớp. Tải lớp được đồng bộ hóa.

Các enumsingleton rất lười biếng vì nó không được khởi tạo cho đến khi sử dụng lần đầu tiên. Khởi tạo Java cũng được đồng bộ hóa, vì vậy nhiều luồng không thể khởi tạo nhiều hơn một thể hiện của INSTANCE. Bạn đang nhận được một singleton khởi tạo lười biếng với rất ít mã. Điểm trừ duy nhất là cú pháp khá tối nghĩa. Bạn cần biết thành ngữ hoặc hiểu kỹ về cách hoạt động của lớp tải và khởi tạo để biết điều gì đang xảy ra.


15
Đoạn cuối đó thực sự làm rõ tình huống đơn lẻ cho tôi. Cảm ơn! Bất kỳ độc giả nào đang đọc lướt nên đọc lại.
Basil Bourque

Tôi đã đọc cái này, stackoverflow.com/questions/16771373/ . Bây giờ tôi đang bối rối với para cuối cùng của bạn. Làm thế nào enum không cung cấp tính năng khởi tạo lay?
Deepankar Singh

static finalcác trường được khởi tạo tại thời gian khởi tạo lớp , không tải thời gian. Nó chính xác giống như với enumkhởi tạo liên tục (trên thực tế, chúng giống hệt nhau dưới mui xe). Đó là lý do tại sao việc cố gắng thực hiện mã khởi tạo lười thông minh, thông minh cho các singletons luôn là vô nghĩa, ngay cả trong phiên bản Java đầu tiên.
Holger

42

Bên cạnh các trường hợp sử dụng đã được đề cập, tôi thường thấy các enum hữu ích để triển khai mẫu chiến lược, tuân theo một số nguyên tắc OOP cơ bản:

  1. Có mã nơi chứa dữ liệu (nghĩa là trong chính enum - hoặc thường nằm trong các hằng số enum, có thể ghi đè các phương thức).
  2. Triển khai một giao diện (hoặc nhiều hơn) để không liên kết mã máy khách với enum (chỉ nên cung cấp một tập hợp các cài đặt mặc định).

Ví dụ đơn giản nhất sẽ là một tập hợp các Comparatortriển khai:

enum StringComparator implements Comparator<String> {
    NATURAL {
        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    },
    REVERSE {
        @Override
        public int compare(String s1, String s2) {
            return NATURAL.compare(s2, s1);
        }
    },
    LENGTH {
        @Override
        public int compare(String s1, String s2) {
            return new Integer(s1.length()).compareTo(s2.length());
        }
    };
}

"Mẫu" này có thể được sử dụng trong các tình huống phức tạp hơn nhiều, sử dụng rộng rãi tất cả các tính năng đi kèm với enum: lặp lại các trường hợp, dựa vào thứ tự ngầm định của chúng, lấy ra một thể hiện bằng tên của nó, các phương thức tĩnh cung cấp đúng thể hiện cho các bối cảnh cụ thể, v.v. Và bạn vẫn có tất cả điều này ẩn sau giao diện để mã của bạn sẽ hoạt động với các triển khai tùy chỉnh mà không cần sửa đổi trong trường hợp bạn muốn một cái gì đó không có sẵn trong số "tùy chọn mặc định".

Tôi đã thấy điều này được áp dụng thành công để mô hình hóa khái niệm độ chi tiết thời gian (hàng ngày, hàng tuần, v.v.) trong đó tất cả logic được gói gọn trong một enum (chọn độ chi tiết phù hợp cho một khoảng thời gian nhất định, hành vi cụ thể được liên kết với từng mức độ chi tiết là hằng số phương pháp v.v.). Tuy nhiên, Granularitylớp dịch vụ nhìn thấy chỉ đơn giản là một giao diện.


2
Bạn cũng có thể thêm CASE_INSENSITIVE { @Override public int compare(String s1, String s2) { return s1.compareToIgnoreCase(s2); }. Một lợi thế chưa được đề cập là bạn có được sự hỗ trợ Nối tiếp mạnh mẽ; biểu mẫu liên tục chỉ chứa tên lớp và tên hằng, không phụ thuộc vào bất kỳ chi tiết triển khai nào của bộ so sánh của bạn.
Holger

32

Một cái gì đó không có câu trả lời nào khác đưa ra làm cho enums đặc biệt mạnh mẽ là khả năng có các phương thức mẫu . Các phương thức có thể là một phần của enum cơ sở và được ghi đè theo từng loại. Và, với hành vi được đính kèm với enum, nó thường loại bỏ sự cần thiết của các cấu trúc if-other hoặc các câu lệnh chuyển đổi như bài đăng trên blog này chứng minh - nơi mà enum.method()những gì ban đầu sẽ được thực hiện bên trong điều kiện. Ví dụ tương tự cũng cho thấy việc sử dụng nhập khẩu tĩnh với enums cũng tạo ra DSL như mã sạch hơn nhiều.

Một số phẩm chất thú vị khác bao gồm thực tế là sự đếm cung cấp thực hiện cho equals(), toString()hashCode()và thực hiện SerializableComparable.

Để có một danh sách đầy đủ tất cả những điều mà enum đưa ra, tôi đánh giá cao Tư duy của Bruce Eckel trong phiên bản Java thứ 4 dành trọn một chương cho chủ đề này. Đặc biệt chiếu sáng là các ví dụ liên quan đến một trò chơi Rock, Paper, Kéo (tức là RoShamBo) dưới dạng enums.


23

Từ các tài liệu Java -

Bạn nên sử dụng các loại enum bất cứ lúc nào bạn cần để biểu diễn một bộ hằng cố định. Điều đó bao gồm các loại enum tự nhiên như các hành tinh trong hệ mặt trời và các bộ dữ liệu của chúng tôi, nơi bạn biết tất cả các giá trị có thể tại thời gian biên dịch ví dụ, các lựa chọn trên menu, cờ dòng lệnh, v.v.

Một ví dụ phổ biến là thay thế một lớp bằng một tập các hằng số int cuối cùng tĩnh riêng (trong số lượng hằng số hợp lý) bằng một kiểu enum. Về cơ bản nếu bạn nghĩ rằng bạn biết tất cả các giá trị có thể có của "một cái gì đó" tại thời điểm biên dịch, bạn có thể biểu thị đó là một loại enum. Enums cung cấp khả năng đọc và linh hoạt trên một lớp với hằng số.

Vài lợi thế khác mà tôi có thể nghĩ về các loại enum. Chúng luôn là một thể hiện của một lớp enum cụ thể (do đó khái niệm sử dụng enum khi singleton xuất hiện). Một lợi thế khác là bạn có thể sử dụng enums như một kiểu trong câu lệnh switch-case. Ngoài ra, bạn có thể sử dụng toString () trên enum để in chúng dưới dạng các chuỗi có thể đọc được.


8
Bạn sẽ sử dụng một enum cho tất cả 365 ngày trong năm? Đó là một tập hợp cố định (366) hằng số (ngày không thay đổi). Vì vậy, điều này gợi ý bạn nên. : - / Tôi giới hạn kích thước của bộ cố định.
moinudin

2
@marcog Với một chút suy nghĩ thông minh, có thể tóm tắt các ngày trong tuần và các ngày trong mỗi tháng trong một enum nhỏ gọn.
James P.

1
Nói về những ngày trong tuần, DayOfWeeken enum hiện được xác định trước, được tích hợp vào Java 8 và sau đó là một phần của khung java.time (và được chuyển ngược lại sang Java 6 & 7cho Android ).
Basil Bourque

19

Bây giờ tại sao và những gì tôi nên sử dụng enum trong lập trình hàng ngày?

Bạn có thể sử dụng Enum để biểu diễn một bộ hằng số cố định nhỏ hoặc chế độ lớp bên trong trong khi tăng khả năng đọc. Ngoài ra, Enums có thể thực thi một độ cứng nhất định khi được sử dụng trong các tham số phương thức. Chúng cung cấp khả năng thú vị là truyền thông tin đến một nhà xây dựng như trong ví dụ về các hành tinh trên trang web của Oracle và, như bạn đã khám phá, cũng cho phép một cách đơn giản để tạo một mẫu đơn.

ví dụ: Locale.setDefault(Locale.US)đọc tốt hơn Locale.setDefault(1)và thực thi việc sử dụng bộ giá trị cố định được hiển thị trong IDE khi bạn thêm .dấu phân cách thay vì tất cả các số nguyên.


@arnt Tôi cũng đã sửa lỗi ngữ pháp trong câu hỏi. Cảm ơn.
James P.

13

Enums liệt kê một tập hợp các giá trị cố định, theo cách tự ghi lại.
Chúng làm cho mã của bạn rõ ràng hơn và cũng ít bị lỗi hơn.

Tại sao không sử dụng String, hoặc int, thay vì Enum, cho hằng số?

  1. Trình biên dịch sẽ không cho phép lỗi chính tả , không có giá trị nào trong tập hợp cố định, vì enums là kiểu chính chúng. Kết quả:
    • Bạn sẽ không phải viết một điều kiện tiên quyết (hoặc hướng dẫn sử dụng if) để đảm bảo đối số của bạn nằm trong phạm vi hợp lệ.
    • Các loại bất biến đi kèm miễn phí.
  2. Enums có thể có hành vi, giống như bất kỳ lớp nào khác.
  3. Bạn có thể sẽ cần một lượng bộ nhớ tương tự để sử dụng String s (điều này phụ thuộc vào độ phức tạp của Enum).

Hơn nữa, mỗi Enum trường hợp là một lớp mà bạn có thể xác định hành vi riêng của nó.

Thêm vào đó, họ đảm bảo an toàn luồng khi tạo các thể hiện (khi enum được tải), đã thấy ứng dụng tuyệt vời trong việc đơn giản hóa Mẫu Singleton .

Blog này minh họa một số ứng dụng của nó, chẳng hạn như Máy trạng thái cho trình phân tích cú pháp.


13

Thật hữu ích khi biết rằng enumscũng giống như các lớp khác với Constantcác trường và mộtprivate constructor .

Ví dụ,

public enum Weekday
{
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
} 

Trình biên dịch biên dịch nó như sau;

class Weekday extends Enum
{
  public static final Weekday MONDAY  = new Weekday( "MONDAY",   0 );
  public static final Weekday TUESDAY = new Weekday( "TUESDAY ", 1 );
  public static final Weekday WEDNESDAY= new Weekday( "WEDNESDAY", 2 );
  public static final Weekday THURSDAY= new Weekday( "THURSDAY", 3 );
  public static final Weekday FRIDAY= new Weekday( "FRIDAY", 4 );
  public static final Weekday SATURDAY= new Weekday( "SATURDAY", 5 );
  public static final Weekday SUNDAY= new Weekday( "SUNDAY", 6 );

  private Weekday( String s, int i )
  {
    super( s, i );
  }

  // other methods...
}

12

enumcó nghĩa là enum eration tức là đề cập (một số điều) từng cái một.

Một enum là một kiểu dữ liệu chứa các hằng số cố định.

HOẶC LÀ

An enumgiống như một class, với một tập hợp các thể hiện cố định được biết tại thời điểm biên dịch.

Ví dụ:

public class EnumExample {
    interface SeasonInt {
        String seasonDuration();
    }

    private enum Season implements SeasonInt {
        // except the enum constants remaining code looks same as class
        // enum constants are implicitly public static final we have used all caps to specify them like Constants in Java
        WINTER(88, "DEC - FEB"), SPRING(92, "MAR - JUN"), SUMMER(91, "JUN - AUG"), FALL(90, "SEP - NOV");

        private int days;
        private String months;

        Season(int days, String months) { // note: constructor is by default private 
            this.days = days;
            this.months = months;
        }

        @Override
        public String seasonDuration() {
            return this+" -> "+this.days + "days,   " + this.months+" months";
        }

    }
    public static void main(String[] args) {
        System.out.println(Season.SPRING.seasonDuration());
        for (Season season : Season.values()){
            System.out.println(season.seasonDuration());
        }

    }
}

Ưu điểm của enum:

  • enum cải thiện an toàn kiểu khi kiểm tra thời gian biên dịch để tránh lỗi trong thời gian chạy.
  • enum có thể dễ dàng sử dụng trong chuyển đổi
  • enum có thể đi qua
  • enum có thể có các trường, hàm tạo và phương thức
  • enum có thể thực hiện nhiều giao diện nhưng không thể mở rộng bất kỳ lớp nào vì bên trong nó mở rộng lớp Enum

để biết thêm


9

Một enum là gì

  • enum là một từ khóa được xác định để liệt kê một kiểu dữ liệu mới. Bảng liệt kê an toàn nên được sử dụng tự do. Cụ thể, chúng là một sự thay thế mạnh mẽ cho các chuỗi đơn giản hoặc các hằng số int được sử dụng trong các API cũ hơn nhiều để thể hiện các bộ các mục liên quan.

Tại sao nên dùng enum

  • enums là lớp con cuối cùng của java.lang.Enum
  • nếu một enum là thành viên của một lớp, thì nó hoàn toàn tĩnh
  • mới không bao giờ có thể được sử dụng với một enum, ngay cả trong chính loại enum
  • Tên và valueOf chỉ cần sử dụng văn bản của các hằng số enum, trong khi toString có thể được ghi đè để cung cấp bất kỳ nội dung nào, nếu muốn
  • đối với hằng số enum, bằng và == số tiền cho cùng một thứ và có thể được sử dụng thay thế cho nhau
  • hằng enum là ngầm tĩnh công khai cuối cùng

Ghi chú

  • enums không thể mở rộng bất kỳ lớp học.
  • Một enum không thể là một siêu lớp.
  • thứ tự xuất hiện của hằng số enum được gọi là "thứ tự tự nhiên" của chúng và cũng xác định thứ tự được sử dụng bởi các mục khác: so sánh, thứ tự lặp của các giá trị, Enumset, EnumSet.range.
  • Một phép liệt kê có thể có các hàm tạo, các khối tĩnh và thể hiện, các biến và các phương thức nhưng không thể có các phương thức trừu tượng.

4
Bạn không giải thích tại sao nên sử dụng enums. Bạn chỉ cần liệt kê một số thuộc tính của enums dưới các tiêu đề không liên quan.
Duncan Jones

@DuncanJones không các điều khoản cuối cùng, tĩnh cho mục đích sử dụng enums?
tinker_ferry

8

Ngoài tất cả những gì người khác nói .. Trong một dự án cũ mà tôi từng làm việc, rất nhiều giao tiếp giữa các thực thể (ứng dụng độc lập) đã sử dụng các số nguyên đại diện cho một tập hợp nhỏ. Thật hữu ích khi khai báo tập hợp như enumvới các phương thức tĩnh để lấy enumđối tượng valuevà ngược lại. Các mã trông sạch hơn, chuyển đổi khả năng sử dụng trường hợp và viết dễ dàng hơn để ghi nhật ký.

enum ProtocolType {
    TCP_IP (1, "Transmission Control Protocol"), 
    IP (2, "Internet Protocol"), 
    UDP (3, "User Datagram Protocol");

    public int code;
    public String name;

    private ProtocolType(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public static ProtocolType fromInt(int code) {
    switch(code) {
    case 1:
        return TCP_IP;
    case 2:
        return IP;
    case 3:
        return UDP;
    }

    // we had some exception handling for this
    // as the contract for these was between 2 independent applications
    // liable to change between versions (mostly adding new stuff)
    // but keeping it simple here.
    return null;
    }
}

Tạo enumđối tượng từ các giá trị nhận được (ví dụ 1,2) bằng cách sử dụngProtocolType.fromInt(2) ghi vào nhật ký bằng cách sử dụngmyEnumObj.name

Hi vọng điêu nay co ich.


6

Enum kế thừa tất cả các phương thức của Objectlớp và lớp trừu tượng Enum. Vì vậy, bạn có thể sử dụng các phương thức của nó để phản chiếu, đa luồng, serilization, so sánh, v.v. Nếu bạn chỉ khai báo một hằng số tĩnh thay vì Enum, bạn không thể. Ngoài ra, giá trị của Enum cũng có thể được chuyển sang lớp DAO.

Đây là một chương trình ví dụ để chứng minh.

public enum State {

    Start("1"),
    Wait("1"),
    Notify("2"),
    NotifyAll("3"),
    Run("4"),
    SystemInatilize("5"),
    VendorInatilize("6"),
    test,
    FrameworkInatilize("7");

    public static State getState(String value) {
        return State.Wait;
    }

    private String value;
    State test;

    private State(String value) {
        this.value = value;
    }

    private State() {
    }

    public String getValue() {
        return value;
    }

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public boolean isNotify() {
        return this.equals(Notify);
    }
}

public class EnumTest {

    State test;

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public State getCurrentState() {
        return test;
    }

    public static void main(String[] args) {
        System.out.println(State.test);
        System.out.println(State.FrameworkInatilize);
        EnumTest test=new EnumTest();
        test.setCurrentState(State.Notify);
        test. stateSwitch();
    }

    public void stateSwitch() {
        switch (getCurrentState()) {
        case Notify:
            System.out.println("Notify");
            System.out.println(test.isNotify());
            break;
        default:
            break;
        }
    }
}

4

ENum là viết tắt của "Loại liệt kê". Đây là kiểu dữ liệu có một bộ hằng số cố định mà bạn tự xác định.


Bạn chưa giải thích tại sao nên sử dụng enum.
Duncan Jones

4
Có tôi đã làm. Bạn sử dụng nó để lưu trữ một bộ hằng số cố định mà bạn tự xác định. Các ứng dụng cụ thể của nó là tùy thuộc vào bạn. Không có những điều như nói khi nào, tại sao, hoặc làm thế nào để sử dụng một cái gì đó. Đó là tùy thuộc vào nhu cầu của nhà phát triển. Tất cả những gì bạn cần hiểu là nó là gì và nó hoạt động như thế nào.
Steve

4

Theo tôi, tất cả các câu trả lời bạn nhận được cho đến bây giờ đều hợp lệ, nhưng theo kinh nghiệm của tôi, tôi sẽ diễn đạt nó bằng một vài từ:

Sử dụng enums nếu bạn muốn trình biên dịch kiểm tra tính hợp lệ của giá trị của một định danh.

Mặt khác, bạn có thể sử dụng các chuỗi như bạn vẫn thường làm (có thể bạn đã xác định một số "quy ước" cho ứng dụng của mình) và bạn sẽ rất linh hoạt ... nhưng bạn sẽ không nhận được bảo mật 100% trước các lỗi chính tả trên chuỗi của mình và bạn sẽ chỉ nhận ra chúng trong thời gian chạy


3

Sử dụng enum cho TYPE AN TOÀN, đây là một tính năng ngôn ngữ nên bạn thường sẽ nhận được:

  • Hỗ trợ trình biên dịch (xem ngay các vấn đề về loại)
  • Hỗ trợ công cụ trong IDE (tự động hoàn thành trong trường hợp chuyển đổi, trường hợp thiếu, mặc định bắt buộc, ...)
  • Trong một số trường hợp, hiệu năng của enum cũng rất tốt ( Enumset , loại an toàn thay thế cho "cờ bit" dựa trên int truyền thống . )

Enums có thể có các phương thức, constructor, thậm chí bạn có thể sử dụng enums bên trong enums và kết hợp enum với giao diện.

Hãy nghĩ về enum như các kiểu để thay thế một tập hợp các hằng số int được xác định rõ (mà Java 'được thừa hưởng' từ C / C ++) và trong một số trường hợp để thay thế các cờ bit.

Cuốn sách Java hiệu quả phiên bản 2 có cả một chương về chúng và đi sâu vào chi tiết hơn. Cũng xem bài viết Stack Overflow này .


2

Java cho phép bạn hạn chế biến chỉ có một trong một vài giá trị được xác định trước - nói cách khác, một giá trị từ danh sách liệt kê. Sử dụng enumscó thể giúp giảm lỗi trong mã của bạn. Đây là một ví dụ về enumsbên ngoài một lớp:

enums coffeesize{BIG , HUGE , OVERWHELMING }; 
//This semicolon is optional.

Điều này hạn chế coffeesizeđể có một trong hai: BIG, HUGE, hoặc OVERWHELMINGnhư là một biến.


2

Enum? Tại sao nó nên được sử dụng? Tôi nghĩ nó sẽ được hiểu nhiều hơn khi bạn sẽ sử dụng nó. Tôi có cùng kinh nghiệm.

Giả sử bạn có thao tác tạo, xóa, chỉnh sửa và đọc cơ sở dữ liệu.

Bây giờ nếu bạn tạo một enum như một hoạt động:

public enum operation {
    create("1")
    delete("2")
    edit("3")
    read("4")

    // You may have is methods here
    public boolean isCreate() {
        return this.equals(create);
    }
    // More methods like the above can be written

}

Bây giờ, bạn có thể tuyên bố một cái gì đó như:

private operation currentOperation;

// And assign the value for it 
currentOperation = operation.create

Vì vậy, bạn có thể sử dụng nó theo nhiều cách. Luôn luôn tốt khi có enum cho những thứ cụ thể vì hoạt động cơ sở dữ liệu trong ví dụ trên có thể được kiểm soát bằng cách kiểm tra currentOperation . Có lẽ người ta có thể nói điều này có thể được thực hiện với các biến và giá trị nguyên. Nhưng tôi tin Enum là một cách an toàn hơn và là một lập trình viên.

Một điều nữa: Tôi nghĩ mọi lập trình viên đều thích boolean , phải không? Bởi vì nó chỉ có thể lưu trữ hai giá trị, hai giá trị cụ thể. Vì vậy, Enum có thể được coi là có cùng loại phương tiện mà người dùng sẽ xác định số lượng và loại giá trị mà nó sẽ lưu trữ, chỉ theo một cách hơi khác. :)


1

Cho đến nay, tôi chưa bao giờ cần phải sử dụng enums. Tôi đã đọc về chúng kể từ khi chúng được giới thiệu trong 1.5 hoặc phiên bản hổ khi nó được gọi lại trong ngày. Họ không bao giờ thực sự giải quyết được một "vấn đề" cho tôi. Đối với những người sử dụng nó (và tôi thấy rất nhiều người trong số họ làm), chắc chắn rằng nó chắc chắn phục vụ một số mục đích. Chỉ cần 2 câu đố của tôi.


1

Có nhiều câu trả lời ở đây, chỉ muốn chỉ ra hai câu trả lời cụ thể:

1) Sử dụng như hằng số trong Switch-casecâu lệnh. Trường hợp chuyển đổi sẽ không cho phép bạn sử dụng các đối tượng String cho trường hợp. Enums có ích. Thêm: http://www.javabeat.net/2009/02/how-to-use-enum-in-switch/

2) Thực hiện Singleton Design Pattern- Enum một lần nữa, đến để giải cứu. Cách sử dụng, ở đây: Cách tiếp cận tốt nhất để sử dụng Enum như một singleton trong Java là gì?


1

Điều cho tôi khoảnh khắc Ah-Ha là nhận thức này: Enum có một nhà xây dựng riêng chỉ có thể truy cập thông qua bảng liệt kê công khai:

enum RGB {
    RED("Red"), GREEN("Green"), BLUE("Blue");

    public static final String PREFIX = "color ";

    public String getRGBString() {
        return PREFIX + color;
    }

    String color;

    RGB(String color) {
        this.color = color;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        String c = RGB.RED.getRGBString();
        System.out.print("Hello " + c);
    }
}

1

Đối với tôi để làm cho mã có thể đọc được trong tương lai, trường hợp liệt kê hữu ích nhất được trình bày trong đoạn tiếp theo:

public enum Items {
    MESSAGES, CHATS, CITY_ONLINE, FRIENDS, PROFILE, SETTINGS, PEOPLE_SEARCH, CREATE_CHAT
}

@Override
public boolean onCreateOptionsMenu(Menu menuPrm) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menuPrm);
    View itemChooserLcl;
    for (int i = 0; i < menuPrm.size(); i++) {
        MenuItem itemLcl  = menuPrm.getItem(i);
            itemChooserLcl = itemLcl.getActionView();
            if (itemChooserLcl != null) {
                 //here Im marking each View' tag by enume values:
                itemChooserLcl.setTag(Items.values()[i]);
                itemChooserLcl.setOnClickListener(drawerMenuListener);
            }
        }
    return true;
}
private View.OnClickListener drawerMenuListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Items tagLcl= (Items) v.getTag();
        switch (tagLcl){
            case MESSAGES: ;
            break;
            case CHATS : ;
            break;
            case CITY_ONLINE : ;
            break;
            case FRIENDS : ;
            break;
            case  PROFILE: ;
            break;
            case  SETTINGS: ;
            break;
            case  PEOPLE_SEARCH: ;
            break;
            case  CREATE_CHAT: ;
            break;
        }
    }
};

1

Theo kinh nghiệm của tôi, tôi đã thấy việc sử dụng Enum đôi khi khiến các hệ thống rất khó thay đổi. Nếu bạn đang sử dụng Enum cho một tập hợp các giá trị dành riêng cho miền thay đổi thường xuyên và nó có rất nhiều lớp và thành phần khác phụ thuộc vào nó, bạn có thể muốn xem xét không sử dụng Enum.

Ví dụ: hệ thống giao dịch sử dụng Enum cho thị trường / sàn giao dịch. Có rất nhiều thị trường ngoài kia và gần như chắc chắn rằng sẽ có rất nhiều hệ thống phụ cần truy cập vào danh sách thị trường này. Mỗi khi bạn muốn thêm một thị trường mới vào hệ thống của mình hoặc nếu bạn muốn loại bỏ một thị trường, có thể mọi thứ dưới ánh mặt trời sẽ phải được xây dựng lại và phát hành.

Một ví dụ tốt hơn sẽ là một cái gì đó giống như một loại danh mục sản phẩm. Giả sử phần mềm của bạn quản lý hàng tồn kho cho một cửa hàng bách hóa. Có rất nhiều danh mục sản phẩm, và nhiều lý do tại sao danh sách danh mục này có thể thay đổi. Các nhà quản lý có thể muốn dự trữ một dòng sản phẩm mới, loại bỏ các dòng sản phẩm khác và có thể sắp xếp lại các danh mục theo thời gian. Nếu bạn phải xây dựng lại và triển khai lại tất cả các hệ thống của mình chỉ vì người dùng muốn thêm danh mục sản phẩm, thì bạn đã lấy một thứ gì đó đơn giản và nhanh chóng (thêm một danh mục) và làm cho nó rất khó khăn và chậm chạp.

Tóm lại, Enums là tốt nếu dữ liệu bạn đang đại diện rất tĩnh theo thời gian và có số lượng phụ thuộc hạn chế. Nhưng nếu dữ liệu thay đổi nhiều và có nhiều phụ thuộc, thì bạn cần một thứ động không được kiểm tra tại thời điểm biên dịch (như bảng cơ sở dữ liệu).


1

Đơn vị dựa trên enum

một cái nhìn hiện đại tại một vấn đề cũ

Cách tiếp cận này thực hiện đơn lẻ bằng cách tận dụng sự đảm bảo của Java rằng mọi giá trị enum chỉ được khởi tạo một lần trong chương trình Java và enum cung cấp hỗ trợ ngầm cho an toàn luồng. Do các giá trị enum của Java có thể truy cập được trên toàn cầu, do đó, nó có thể được sử dụng như là đơn.

public enum Singleton {
    SINGLETON; 
    public void method() { }
}

Cái này hoạt động ra sao? Chà, dòng hai của mã có thể được coi là một cái gì đó như thế này:

public final static Singleton SINGLETON = new Singleton(); 

Và chúng tôi có được singleton khởi tạo sớm tốt.

Hãy nhớ rằng vì đây là enum nên bạn luôn có thể truy cập qua thể hiện thông qua Singleton.INSTANCE :

Singleton s = Singleton.INSTANCE;
Ưu điểm
  • Để ngăn việc tạo một cá thể khác của singleton trong quá trình khử lưu huỳnh, hãy sử dụng enleton dựa trên enum vì việc tuần tự hóa enum được JVM chăm sóc. Enum serialization và deserialization hoạt động khác với các đối tượng java bình thường. Điều duy nhất được tuần tự hóa là tên của giá trị enum. Trong quá trình khử muốivalueOf phương thức được sử dụng với tên khử lưu huỳnh để lấy thể hiện mong muốn.
  • Đơn độc dựa trên Enum cho phép tự bảo vệ mình khỏi cuộc tấn công phản xạ. Kiểu enum thực sự mở rộng Enumlớp java . Lý do mà sự phản chiếu không thể được sử dụng để khởi tạo các đối tượng của kiểu enum là do đặc tả java không tuân theo và quy tắc đó được mã hóa trong việc thực hiện newInstancephương thức của Constructorlớp, thường được sử dụng để tạo các đối tượng thông qua sự phản chiếu:
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
  • Enum không được cho là nhân bản vì phải có chính xác một thể hiện của mỗi giá trị.
  • Các mã laconic nhất trong số tất cả các thực hiện singleton.
Nhược điểm
  • Singleton dựa trên enum không cho phép khởi tạo lười biếng.
  • Nếu bạn thay đổi thiết kế của mình và muốn chuyển đổi singleton thành multiton, enum sẽ không cho phép điều này. Mẫu multiton được sử dụng để tạo ra nhiều trường hợp được kiểm soát mà nó quản lý thông qua việc sử dụng a map. Thay vì có một thể hiện duy nhất cho mỗi ứng dụng (ví dụ java.lang.Runtime) mẫu đa hình thay vào đó đảm bảo một thể hiện duy nhất cho mỗi khóa .
  • Enum chỉ xuất hiện trong Java 5 nên bạn không thể sử dụng nó trong phiên bản trước.

Có một số nhận thức về mẫu singleton mỗi cái có ưu điểm và nhược điểm.

  • Háo hức tải đơn
  • Kiểm tra khóa đơn
  • Thành ngữ chủ sở hữu khởi tạo theo yêu cầu
  • Đơn vị dựa trên enum

Mô tả chi tiết mỗi bài trong số chúng quá dài dòng nên tôi chỉ cần đặt một liên kết đến một bài viết hay - Tất cả những gì bạn muốn biết về Singleton


0

Tôi sẽ sử dụng enums như một công cụ ánh xạ hữu ích, tránh nhiều if-else điều kiện miễn là một số phương thức được thực hiện.

public enum Mapping {

    ONE("1"),
    TWO("2");

    private String label;

    private Mapping(String label){
        this.label = label;
    }

    public static Mapping by(String label) {

        for(Mapping m: values() {
            if(m.label.equals(label)) return m;
        }

        return null;
    }

}

Vì vậy, phương pháp by(String label)cho phép bạn có được giá trị liệt kê bằng cách không liệt kê. Hơn nữa, người ta có thể phát minh ra ánh xạ giữa 2 enum. Cũng có thể thử '1 đến nhiều' hoặc 'nhiều đến nhiều' ngoài mối quan hệ mặc định 'một với một'

Cuối cùng, enumlà một lớp Java. Vì vậy, bạn có thể có mainphương thức bên trong nó, có thể hữu ích khi cần thực hiện một số thao tác ánh xạ argsngay lập tức.


0

Thay vì thực hiện một loạt các tuyên bố const int

Bạn có thể nhóm tất cả trong 1 enum

Vì vậy, tất cả được tổ chức bởi nhóm chung mà họ thuộc về


0

Enums giống như các lớp học. Giống như lớp, nó cũng có các phương thức và thuộc tính.

Sự khác biệt với lớp là: 1. hằng số enum là công khai, tĩnh, cuối cùng. 2. một enum không thể được sử dụng để tạo một đối tượng và nó không thể mở rộng các lớp khác. Nhưng nó có thể thực hiện các giao diện.


0

Ngoài @BradB Trả lời:

Điều đó rất đúng ... Thật kỳ lạ khi đó là câu trả lời duy nhất đề cập đến điều đó. Khi người mới bắt đầu khám phá ra enums, họ nhanh chóng coi đó là một trò ảo thuật để kiểm tra định danh hợp lệ cho trình biên dịch. Và khi mã được dự định sử dụng trên các hệ thống phân tán, họ sẽ khóc ... vài tháng sau. Duy trì khả năng tương thích ngược với các enum chứa danh sách giá trị không tĩnh là mối quan tâm thực sự và là nỗi đau. Điều này là do khi bạn thêm một giá trị vào một enum hiện có, kiểu của nó sẽ thay đổi (mặc dù tên không có).

"Ho, đợi đã, nó có thể trông giống như vậy, phải không? Rốt cuộc, chúng là những enum có cùng tên - và không phải enum chỉ là số nguyên dưới mui xe?" Và vì những lý do này, trình biên dịch của bạn có thể sẽ không gắn cờ cho việc sử dụng một định nghĩa của chính loại mà nó đang mong đợi. Nhưng trên thực tế, chúng là (theo những cách quan trọng nhất) các loại khác nhau. Quan trọng nhất, chúng có các miền dữ liệu khác nhau - các giá trị được chấp nhận theo loại. Bằng cách thêm một giá trị, chúng tôi đã thay đổi một cách hiệu quả loại enum và do đó phá vỡ tính tương thích ngược.

Tóm lại: Sử dụng nó khi bạn muốn, nhưng, xin vui lòng, kiểm tra xem miền dữ liệu được sử dụng có phải là một tập hợp hữu hạn, đã biết, cố định khô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.