จับคู่ระหว่าง enum และ int / String ได้อย่างสะดวกสบาย


108

เมื่อทำงานกับตัวแปร / พารามิเตอร์ที่รับค่าได้เพียงจำนวน จำกัด ฉันพยายามใช้ Java เสมอenumเช่นเดียวกับใน

public enum BonusType {
  MONTHLY, YEARLY, ONE_OFF
}

ตราบเท่าที่ฉันอยู่ในรหัสของฉันมันก็ใช้ได้ดี อย่างไรก็ตามฉันมักจะต้องเชื่อมต่อกับโค้ดอื่น ๆ ที่ใช้ค่าธรรมดาint(หรือString) เพื่อจุดประสงค์เดียวกันหรือฉันต้องการอ่าน / เขียนจาก / ไปยังฐานข้อมูลที่เก็บข้อมูลเป็นตัวเลขหรือสตริง

ในกรณีนี้ฉันต้องการวิธีที่สะดวกในการเชื่อมโยงค่า enum แต่ละค่ากับจำนวนเต็มเพื่อให้ฉันสามารถแปลงทั้งสองวิธีได้ (หรืออีกนัยหนึ่งคือฉันต้องการ "enum ย้อนกลับได้")

การเปลี่ยนจาก enum เป็น int นั้นง่ายมาก:

public enum BonusType {
  public final int id;

  BonusType(int id) {
    this.id = id;
  }
  MONTHLY(1), YEARLY(2), ONE_OFF(3);
}

จากนั้นฉันสามารถเข้าถึงค่า int เป็นBonusType x = MONTHLY; int id = x.id;.

อย่างไรก็ตามฉันไม่เห็นวิธีที่ดีสำหรับการย้อนกลับนั่นคือการเปลี่ยนจาก int ไป enum ตามหลักการแล้วสิ่งที่ต้องการ

BonusType bt = BonusType.getById(2); 

วิธีแก้ปัญหาเดียวที่ฉันสามารถทำได้คือ:

  • ใส่วิธีการค้นหาลงใน enum ซึ่งใช้BonusType.values()เพื่อเติมแผนที่ "int -> enum" จากนั้นแคชและใช้เพื่อค้นหา จะได้ผล แต่ฉันต้องคัดลอกวิธีนี้เหมือนกันในแต่ละ enum ที่ฉันใช้ :-(
  • ใส่วิธีการค้นหาลงในคลาสยูทิลิตี้แบบคงที่ จากนั้นฉันต้องการเพียงวิธีการ "ค้นหา" เพียงวิธีเดียว แต่ฉันต้องใช้การไตร่ตรองเพื่อให้มันใช้งานได้ตามอำเภอใจ

ทั้งสองวิธีดูเหมือนจะอึดอัดมากสำหรับปัญหาง่ายๆ (?)

ความคิด / ข้อมูลเชิงลึกอื่น ๆ ?


1
ฉัน <3 java enums แต่เกลียดมันด้วยเหตุผลนี้เป๊ะ! ดูเหมือนว่าพวกเขาจะสมบูรณ์แบบอยู่เสมอนอกเหนือจากข้อบกพร่องที่น่าเกลียดจริงๆ ...
Chris Thompson

8
สำหรับ enum-> int คุณสามารถใช้ได้ordinal()
davin

1
คุณสามารถ.ordinal()ตัดสินค่ารหัสประจำตัวของคุณได้หรือไม่ (หมายความว่าคุณใช้ไม่ได้) หรือถูกกำหนดโดยกองกำลังภายนอก?
Paŭlo Ebermann

2
@davin: ใช่และให้รหัสของคุณทำลายทันทีที่มีคนจัดเรียงการประกาศ enum ใหม่หรือลบค่าที่อยู่ตรงกลาง ฉันเกรงว่าจะไม่ใช่วิธีแก้ปัญหาที่มีประสิทธิภาพ: - /.
sleske

1
@davin โดยใช้ "ordinal ()" ควรหลีกเลี่ยงทุกครั้งที่ทำได้ซึ่งอยู่ในข้อกำหนดของภาษา
DPM

คำตอบ:


37

http://www.javaspecialists.co.za/archive/Issue113.html

การแก้ปัญหาเริ่มต้นคล้ายกับของคุณโดยมีค่า int เป็นส่วนหนึ่งของนิยาม enum จากนั้นเขาก็สร้างยูทิลิตี้การค้นหาตามชื่อสามัญ:

public class ReverseEnumMap<V extends Enum<V> & EnumConverter> {
    private Map<Byte, V> map = new HashMap<Byte, V>();
    public ReverseEnumMap(Class<V> valueType) {
        for (V v : valueType.getEnumConstants()) {
            map.put(v.convert(), v);
        }
    }

    public V get(byte num) {
        return map.get(num);
    }
}

โซลูชันนี้ดีและไม่ต้องการ 'การเล่นซอกับการสะท้อน' เพราะมันขึ้นอยู่กับความจริงที่ว่า enum ทุกประเภทสืบทอดอินเทอร์เฟซ Enum โดยปริยาย


สิ่งนี้ไม่ใช้ลำดับ? Sleske ใช้ id เพียงเพราะลำดับการเปลี่ยนแปลงเมื่อค่า enum ถูกเรียงลำดับใหม่
ภายนอก

ไม่มันไม่ใช้ลำดับ มันขึ้นอยู่กับค่า int ที่กำหนดไว้อย่างชัดเจน ค่า int นั้นถูกใช้เป็นคีย์แผนที่ (ส่งคืนโดย v.convert ())
Jeff

2
ฉันชอบวิธีนี้มาก ดูเหมือนว่านี่เป็นเรื่องทั่วไปที่สุดที่คุณจะได้รับ
sleske

+1. หมายเหตุเดียวของฉันคือฉันจะใช้NumberแทนByteเนื่องจากค่าสำรองของฉันอาจมีขนาดใหญ่กว่า
Ivaylo Slavov

3
อ่านคำถามจริงๆและอย่างแท้จริง หากคุณกำลังจัดการกับฐานข้อมูลเดิมหรือระบบภายนอกที่กำหนดจำนวนเต็มที่คุณไม่ต้องการเผยแพร่ผ่านรหัสของคุณเองนี่เป็นหนึ่งในกรณีเหล่านั้น ลำดับเป็นวิธีที่เปราะบางอย่างยิ่งในการคงคุณค่าของ enum และนอกเหนือจากนั้นก็ไม่มีประโยชน์ในกรณีเฉพาะที่กล่าวถึงในคำถาม
Jeff

327

enum → int

yourEnum.ordinal()

int → enum

EnumType.values()[someInt]

สตริง→ enum

EnumType.valueOf(yourString)

enum →สตริง

yourEnum.name()

หมายเหตุด้านข้าง:
ตามที่คุณระบุอย่างถูกต้องสิ่งที่ordinal()อาจ "ไม่เสถียร" จากเวอร์ชันหนึ่งไปยังอีกเวอร์ชันหนึ่ง นี่คือเหตุผลที่แท้จริงว่าทำไมฉันจึงเก็บค่าคงที่เป็นสตริงในฐานข้อมูลของฉัน (จริงๆแล้วเมื่อใช้ MySql ฉันจะเก็บไว้เป็นMySql enums !)


2
+1 นี่คือคำตอบที่ถูกต้องชัดเจน โปรดทราบว่ามีวิธีการอาร์กิวเมนต์เดียวสำหรับ valueOf ซึ่งใช้เวลาเพียง String และมีอยู่ตราบเท่าที่คุณใช้ประเภทคอนกรีต enum (เช่นBonusType.valueOf("MONTHLY"))
Tim Bender

18
การใช้ordinal()ขีดฆ่าฉันเป็นวิธีแก้ปัญหาเพราะมันจะพังเมื่อรายการของค่า enum ถูกจัดเรียงใหม่หรือค่าถูกลบ นอกจากนี้ยังใช้ได้จริงก็ต่อเมื่อค่า int เป็น 0 ... n (ซึ่งฉันมักพบว่าไม่เป็นเช่นนั้น)
sleske

4
@sleske หากคุณเริ่มลบค่าคงที่คุณจะมีปัญหากับข้อมูลที่ยังคงมีอยู่อยู่ดี (อัปเดตคำตอบของฉันในเรื่องนี้)
aioobe

3
การใช้values()อาร์เรย์จะใช้ได้ก็ต่อเมื่อค่าทั้งหมดของคุณเป็น 0 ดัชนีสำหรับ id และมีการประกาศตามลำดับ (ผมทดสอบนี้เพื่อตรวจสอบว่าถ้าคุณประกาศFOO(0), BAR(2), BAZ(1);ว่าvalues[1] == BARและvalues[2] == BAZแม้จะมีรหัสผ่านใน.)
corsiKa

2
@glowcoder แน่นอนว่าอาร์กิวเมนต์จำนวนเต็มเป็นเพียงฟิลด์ใน enum-object มันไม่มีอะไรเกี่ยวข้องกับค่าคงที่ลำดับที่เกี่ยวข้องกับอ็อบเจ็กต์ enum (อาจเป็น a ได้เช่นกันdouble)
aioobe

30

ฉันพบสิ่งนี้บนเว็บมันมีประโยชน์มากและใช้งานง่าย ฉันไม่ได้ทำวิธีแก้ปัญหานี้

http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks

public enum Status {
 WAITING(0),
 READY(1),
 SKIPPED(-1),
 COMPLETED(5);

 private static final Map<Integer,Status> lookup 
      = new HashMap<Integer,Status>();

 static {
      for(Status s : EnumSet.allOf(Status.class))
           lookup.put(s.getCode(), s);
 }

 private int code;

 private Status(int code) {
      this.code = code;
 }

 public int getCode() { return code; }

 public static Status get(int code) { 
      return lookup.get(code); 
 }

}


s / EnumSet.allOf (Status.class) /Status.values ​​()
jelinson

8

ดูเหมือนว่าคำตอบสำหรับคำถามนี้จะล้าสมัยไปแล้วกับการเปิดตัว Java 8

  1. อย่าใช้ลำดับเนื่องจากลำดับไม่เสถียรหากยังคงอยู่ภายนอก JVM เช่นฐานข้อมูล
  2. การสร้างแผนที่แบบคงที่ด้วยค่าคีย์นั้นค่อนข้างง่าย

public enum AccessLevel {
  PRIVATE("private", 0),
  PUBLIC("public", 1),
  DEFAULT("default", 2);

  AccessLevel(final String name, final int value) {
    this.name = name;
    this.value = value;
  }

  private final String name;
  private final int value;

  public String getName() {
    return name;
  }

  public int getValue() {
    return value;
  }

  static final Map<String, AccessLevel> names = Arrays.stream(AccessLevel.values())
      .collect(Collectors.toMap(AccessLevel::getName, Function.identity()));
  static final Map<Integer, AccessLevel> values = Arrays.stream(AccessLevel.values())
      .collect(Collectors.toMap(AccessLevel::getValue, Function.identity()));

  public static AccessLevel fromName(final String name) {
    return names.get(name);
  }

  public static AccessLevel fromValue(final int value) {
    return values.get(value);
  }
}

พารามิเตอร์ที่สองไม่ควรCollectors.toMap()เป็นFunctions.identity()แทนที่จะเป็นnull?
Adam Michalik

ใช่ฉันนำสิ่งนี้มาจากคลาสตัวช่วยที่ฉันใช้กับฝรั่งที่แปลงโมฆะเป็นตัวตน
John Meyer

นั่นเป็นการใช้คุณสมบัติใหม่ของ Java 8 อย่างเรียบร้อย อย่างไรก็ตามก็ยังคงหมายความว่ารหัสจะต้องมีการทำซ้ำในทุก enum - และคำถามของฉันคือการหลีกเลี่ยงการทำซ้ำสำเร็จรูปนี้ (เชิงโครงสร้าง)
sleske

5

org.apache.commons.lang.enums.ValuedEnum;

เพื่อช่วยฉันเขียนโค้ดสำเร็จรูปหรือโค้ดซ้ำสำหรับแต่ละ Enum ฉันใช้ Apache Commons Lang ValuedEnumแทน

คำจำกัดความ :

public class NRPEPacketType extends ValuedEnum {    
    public static final NRPEPacketType TYPE_QUERY = new NRPEPacketType( "TYPE_QUERY", 1);
    public static final NRPEPacketType TYPE_RESPONSE = new NRPEPacketType( "TYPE_RESPONSE", 2);

    protected NRPEPacketType(String name, int value) {
        super(name, value);
    }
}

การใช้งาน:

int -> ValuedEnum:

NRPEPacketType packetType = 
 (NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);

ความคิดที่ดีฉันไม่รู้ว่าสิ่งนี้มีอยู่จริง ขอบคุณสำหรับการแบ่งปัน!
Keith P

3

คุณอาจใช้บางอย่างเช่น

interface EnumWithId {
    public int getId();

}


enum Foo implements EnumWithId {

   ...
}

ซึ่งจะช่วยลดความจำเป็นในการไตร่ตรองในคลาสยูทิลิตี้ของคุณ


คุณสามารถยกตัวอย่างวิธีใช้ข้อมูลโค้ดนี้ได้หรือไม่?
IgorGanapolsky

3

ในรหัสนี้สำหรับการค้นหาแบบถาวรและเข้มข้นมีหน่วยความจำหรือกระบวนการสำหรับใช้งานและฉันเลือกหน่วยความจำโดยมีอาร์เรย์ตัวแปลงเป็นดัชนี ฉันหวังว่ามันจะเป็นประโยชน์

public enum Test{ 
VALUE_ONE(101, "Im value one"),
VALUE_TWO(215, "Im value two");
private final int number;
private final byte[] desc;

private final static int[] converter = new int[216];
static{
    Test[] st = values();
    for(int i=0;i<st.length;i++){
        cv[st[i].number]=i;
    }
}

Test(int value, byte[] description) {
    this.number = value;
    this.desc = description;
}   
public int value() {
    return this.number;
}
public byte[] description(){
    return this.desc;
}

public static String description(int value) {
    return values()[converter[rps]].desc;
}

public static Test fromValue(int value){
return values()[converter[rps]];
}
}

2

ใช้อินเทอร์เฟซเพื่อแสดงให้เห็นว่าใครเป็นหัวหน้า

public interface SleskeEnum {
    int id();

    SleskeEnum[] getValues();

}

public enum BonusType implements SleskeEnum {


  MONTHLY(1), YEARLY(2), ONE_OFF(3);

  public final int id;

  BonusType(int id) {
    this.id = id;
  }

  public SleskeEnum[] getValues() {
    return values();
  }

  public int id() { return id; }


}

public class Utils {

  public static SleskeEnum getById(SleskeEnum type, int id) {
      for(SleskeEnum t : type.getValues())
          if(t.id() == id) return t;
      throw new IllegalArgumentException("BonusType does not accept id " + id);
  }

  public static void main(String[] args) {

      BonusType shouldBeMonthly = (BonusType)getById(BonusType.MONTHLY,1);
      System.out.println(shouldBeMonthly == BonusType.MONTHLY);

      BonusType shouldBeMonthly2 = (BonusType)getById(BonusType.MONTHLY,1);
      System.out.println(shouldBeMonthly2 == BonusType.YEARLY);

      BonusType shouldBeYearly = (BonusType)getById(BonusType.MONTHLY,2);
      System.out.println(shouldBeYearly  == BonusType.YEARLY);

      BonusType shouldBeOneOff = (BonusType)getById(BonusType.MONTHLY,3);
      System.out.println(shouldBeOneOff == BonusType.ONE_OFF);

      BonusType shouldException = (BonusType)getById(BonusType.MONTHLY,4);
  }
}

และผลลัพธ์:

C:\Documents and Settings\user\My Documents>java Utils
true
false
true
true
Exception in thread "main" java.lang.IllegalArgumentException: BonusType does not accept id 4
        at Utils.getById(Utils.java:6)
        at Utils.main(Utils.java:23)

C:\Documents and Settings\user\My Documents>

1
เช่นเดียวกับคำตอบของ Turd Ferguson นั่นเป็นวิธีแก้ปัญหาที่ไม่สง่างามที่ฉันต้องการหลีกเลี่ยง / ปรับปรุง ...
sleske

ฉันมักจะสร้างการแมปย้อนกลับในบล็อก {} แบบคงที่เพื่อไม่ต้องวนซ้ำค่า () ทุกครั้งที่ฉันขอค่าด้วยรหัส ฉันมักจะเรียก method valueOf (int) เพื่อให้มันดูเหมือนวิธี valueOf (String) ที่มีอยู่แล้วสำหรับ Strings (ซึ่งเป็นส่วนหนึ่งของคำถามของ OP) ค่อนข้างเหมือนรายการ 33 ใน Effective Java: tinyurl.com/4ffvc38
Fredrik

@Sleske อัปเดตด้วยโซลูชันที่ละเอียดยิ่งขึ้น @ Fredrik น่าสนใจแม้ว่าฉันจะสงสัยว่าการทำซ้ำจะเป็นปัญหาสำคัญ
corsiKa

@glowcoder ดีไม่ต้องวนซ้ำมากกว่าหนึ่งครั้งหมายความว่าไม่สำคัญว่าคุณจะทำมันเป็นพันครั้งต่อวินาทีซึ่งอาจเป็นปัญหาที่สำคัญมากหรือเรียกว่าสอง
เฟรดริก

@ เฟรดริกฉันจะยอมรับว่ามีหลายครั้งที่อาจจำเป็นต้องปรับให้เหมาะสม ฉันยังบอกด้วยว่าจนกว่าจะเป็นปัญหาด้านประสิทธิภาพที่ระบุอย่าปรับให้เหมาะสม
corsiKa

2

ทั้ง.ordinal()และvalues()[i]ไม่เสถียรเนื่องจากขึ้นอยู่กับลำดับของ enums ดังนั้นหากคุณเปลี่ยนลำดับของ enums หรือเพิ่ม / ลบโปรแกรมบางโปรแกรมของคุณจะพัง

นี่คือวิธีง่ายๆ แต่มีประสิทธิภาพในการแมประหว่าง enum และ int

public enum Action {
    ROTATE_RIGHT(0), ROTATE_LEFT(1), RIGHT(2), LEFT(3), UP(4), DOWN(5);

    public final int id;
    Action(int id) {
        this.id = id;
    }

    public static Action get(int id){
        for (Action a: Action.values()) {
            if (a.id == id)
                return a;
        }
        throw new IllegalArgumentException("Invalid id");
    }
}

การนำไปใช้กับสตริงไม่น่าจะยาก


ใช่ฉันรู้ว่าฉันทำได้ - หรือดีกว่านั้นให้ใช้แผนที่สำหรับการค้นหาแบบย้อนกลับแทนที่จะวนซ้ำตามค่าทั้งหมด ฉันพูดถึงสิ่งนี้ในคำถามของฉันและฉันยังพูดถึงว่าฉันกำลังมองหาวิธีแก้ไขที่ดีกว่าเพื่อหลีกเลี่ยงการมีรหัสสำเร็จรูปในแต่ละ enum
sleske

2

ตัวอย่างการใช้งาน reverse Enum ที่สะอาดมาก

ขั้นตอนที่ 1 กำหนดinterfaceEnumConverter

public interface EnumConverter <E extends Enum<E> & EnumConverter<E>> {
    public String convert();
    E convert(String pKey);
}

ขั้นตอนที่ 2

สร้างชื่อคลาส ReverseEnumMap

import java.util.HashMap;
import java.util.Map;

public class ReverseEnumMap<V extends Enum<V> & EnumConverter<V>> {
    private Map<String, V> map = new HashMap<String, V>();

    public ReverseEnumMap(Class<V> valueType) {
        for (V v : valueType.getEnumConstants()) {
            map.put(v.convert(), v);
        }
    }

    public V get(String pKey) {
        return map.get(pKey);
    }
}

ขั้นตอนที่ 3

ไปที่Enumชั้นเรียนของคุณและimplementมันด้วยEnumConverter<ContentType>และแน่นอนว่าจะลบล้างวิธีการอินเตอร์เฟส คุณต้องเริ่มต้น ReverseEnumMap แบบคงที่

public enum ContentType implements EnumConverter<ContentType> {
    VIDEO("Video"), GAME("Game"), TEST("Test"), IMAGE("Image");

    private static ReverseEnumMap<ContentType> map = new ReverseEnumMap<ContentType>(ContentType.class);

    private final String mName;

    ContentType(String pName) {
        this.mName = pName;
    }

    String value() {
        return this.mName;
    }

    @Override
    public String convert() {
        return this.mName;
    }

    @Override
    public ContentType convert(String pKey) {
        return map.get(pKey);
    }
}

ขั้นตอนที่ 4

ตอนนี้สร้างCommunicationไฟล์ระดับและเรียกว่าเป็นวิธีการใหม่ในการแปลงEnumไปStringและจะString Enumฉันเพิ่งวางวิธีการหลักเพื่อวัตถุประสงค์ในการอธิบาย

public class Communication<E extends Enum<E> & EnumConverter<E>> {
    private final E enumSample;

    public Communication(E enumSample) {
        this.enumSample = enumSample;
    }

    public String resolveEnumToStringValue(E e) {
        return e.convert();
    }

    public E resolveStringEnumConstant(String pName) {
        return enumSample.convert(pName);
    }

//Should not put main method here... just for explanation purpose. 
    public static void main(String... are) {
        Communication<ContentType> comm = new Communication<ContentType>(ContentType.GAME);
        comm.resolveEnumToStringValue(ContentType.GAME); //return Game
        comm.resolveStringEnumConstant("Game"); //return GAME (Enum)
    }
}

คลิกเพื่อดูคำอธิบายทั้งหมด


1
สิ่งนี้ฉันชอบมาก - ฉันได้ค้นหาวิธีแก้ปัญหาที่มั่นคงสำหรับปัญหานี้มาระยะหนึ่งแล้ว การเปลี่ยนแปลงเพียงอย่างเดียวที่ฉันทำคือการสร้างContentType convert(String pKey)แบบคงที่ซึ่งขจัดความจำเป็นในการCommunicationเรียนและเป็นที่ชื่นชอบของฉันมากขึ้น +1
Chris Mantle

1

ฉันไม่แน่ใจว่ามันเหมือนกันใน Java หรือไม่ แต่ประเภท enum ใน C จะถูกแมปกับจำนวนเต็มโดยอัตโนมัติเช่นกันดังนั้นคุณสามารถใช้ชนิดหรือจำนวนเต็มเพื่อเข้าถึงได้ คุณลองเข้าถึงมันด้วยจำนวนเต็มหรือยัง?


2
Enums ใน Java ไม่ทำงานในลักษณะนั้น เป็นประเภทที่ชัดเจน
Chris Thompson

แต่ละอ็อบเจ็กต์ enum จะมีหมายเลขภายใน (คือตำแหน่งที่มีการประกาศ) และสามารถเข้าถึงได้โดย.ordinal()วิธีการ (วิธีอื่นให้ใช้BonusType.values()[i]) แต่ในตัวอย่างที่อ้างถึงข้างต้นดัชนีที่นี่และค่าภายนอกไม่ตรงกัน
Paŭlo Ebermann

1

คำถามที่ดีจริงๆ :-) ฉันใช้วิธีแก้ปัญหาที่คล้ายกับ Mr. Ferguson เมื่อไม่นานมานี้ enum ที่แยกส่วนของเรามีลักษณะดังนี้:

final class BonusType extends Enum
{

    private BonusType(String s, int i, int id)
    {
        super(s, i);
        this.id = id;
    }

    public static BonusType[] values()
    {
        BonusType abonustype[];
        int i;
        BonusType abonustype1[];
        System.arraycopy(abonustype = ENUM$VALUES, 0, abonustype1 = new BonusType[i = abonustype.length], 0, i);
        return abonustype1;
    }

    public static BonusType valueOf(String s)
    {
        return (BonusType)Enum.valueOf(BonusType, s);
    }

    public static final BonusType MONTHLY;
    public static final BonusType YEARLY;
    public static final BonusType ONE_OFF;
    public final int id;
    private static final BonusType ENUM$VALUES[];

    static 
    {
        MONTHLY = new BonusType("MONTHLY", 0, 1);
        YEARLY = new BonusType("YEARLY", 1, 2);
        ONE_OFF = new BonusType("ONE_OFF", 2, 3);
        ENUM$VALUES = (new BonusType[] {
            MONTHLY, YEARLY, ONE_OFF
        });
    }
}

เมื่อเห็นสิ่งนี้ก็ชัดเจนว่าทำไมจึงordinal()ไม่เสถียร มันอยู่iในsuper(s, i);. ฉันยังมองโลกในแง่ร้ายว่าคุณสามารถคิดวิธีแก้ปัญหาที่หรูหรากว่าที่คุณระบุไว้ได้ หลังจาก enums ทั้งหมดเป็นคลาสสุดท้ายใด ๆ


1

เพื่อความสมบูรณ์นี่คือวิธีการทั่วไปในการดึงค่า enum ด้วยดัชนีจากประเภท enum ใด ๆ ความตั้งใจของผมคือการทำให้รูปลักษณ์และความรู้สึกวิธีการเช่นEnum.valueOf (Class, String) FYI ผมคัดลอกวิธีการนี้จากที่นี่

ปัญหาที่เกี่ยวข้องกับดัชนี (ที่กล่าวถึงในเชิงลึกแล้ว) ยังคงมีผล

/**
 * Returns the {@link Enum} instance for a given ordinal.
 * This method is the index based alternative
 * to {@link Enum#valueOf(Class, String)}, which
 * requires the name of an instance.
 * 
 * @param <E> the enum type
 * @param type the enum class object
 * @param ordinal the index of the enum instance
 * @throws IndexOutOfBoundsException if ordinal < 0 || ordinal >= enums.length
 * @return the enum instance with the given ordinal
 */
public static <E extends Enum<E>> E valueOf(Class<E> type, int ordinal) {
    Preconditions.checkNotNull(type, "Type");
    final E[] enums = type.getEnumConstants();
    Preconditions.checkElementIndex(ordinal, enums.length, "ordinal");
    return enums[ordinal];
}

นั่นไม่ใช่สิ่งที่ฉันกำลังมองหาจริงๆเนื่องจากสิ่งนี้จะดึงค่า enum ตามลำดับเท่านั้นไม่ใช่โดย id จำนวนเต็มที่กำหนด (ดูคำถามของฉัน) นอกจากนี้ถ้าฉันต้องการอย่างนั้นฉันก็สามารถใช้ได้MyEnumType.values()- ไม่จำเป็นต้องใช้วิธีตัวช่วยแบบคง
sleske

0
Int -->String :

public enum Country {

    US("US",0),
    UK("UK",2),
    DE("DE",1);


    private static Map<Integer, String> domainToCountryMapping; 
    private String country;
    private int domain;

    private Country(String country,int domain){
        this.country=country.toUpperCase();
        this.domain=domain;
    }

    public String getCountry(){
        return country;
    }


    public static String getCountry(String domain) {
        if (domainToCountryMapping == null) {
            initMapping();
        }

        if(domainToCountryMapping.get(domain)!=null){
            return domainToCountryMapping.get(domain);
        }else{
            return "US";
        }

    }

     private static void initMapping() {
         domainToCountryMapping = new HashMap<Integer, String>();
            for (Country s : values()) {
                domainToCountryMapping.put(s.domain, s.country);
            }
        }

0

ฉันต้องการสิ่งที่แตกต่างออกไปเพราะฉันต้องการใช้วิธีการทั่วไป ฉันกำลังอ่าน enum ไปและกลับจากอาร์เรย์ไบต์ นี่คือสิ่งที่ฉันคิดขึ้น:

public interface EnumConverter {
    public Number convert();
}



public class ByteArrayConverter {
@SuppressWarnings("unchecked")
public static Enum<?> convertToEnum(byte[] values, Class<?> fieldType, NumberSystem numberSystem) throws InvalidDataException {
    if (values == null || values.length == 0) {
        final String message = "The values parameter must contain the value";
        throw new IllegalArgumentException(message);
    }

    if (!dtoFieldType.isEnum()) {
        final String message = "dtoFieldType must be an Enum.";
        throw new IllegalArgumentException(message);
    }

    if (!EnumConverter.class.isAssignableFrom(fieldType)) {
        final String message = "fieldType must implement the EnumConverter interface.";
        throw new IllegalArgumentException(message);
    }

    Enum<?> result = null;
    Integer enumValue = (Integer) convertToType(values, Integer.class, numberSystem); // Our enum's use Integer or Byte for the value field.

    for (Object enumConstant : fieldType.getEnumConstants()) {
        Number ev = ((EnumConverter) enumConstant).convert();

        if (enumValue.equals(ev)) {
            result = (Enum<?>) enumConstant;
            break;
        }
    }

    if (result == null) {
        throw new EnumConstantNotPresentException((Class<? extends Enum>) fieldType, enumValue.toString());
    }

    return result;
}

public static byte[] convertEnumToBytes(Enum<?> value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
    if (!(value instanceof EnumConverter)) {
        final String message = "dtoFieldType must implement the EnumConverter interface.";
        throw new IllegalArgumentException(message);
    }

    Number enumValue = ((EnumConverter) value).convert();
    byte[] result = convertToBytes(enumValue, requiredLength, numberSystem);
    return result;
}

public static Object convertToType(byte[] values, Class<?> type, NumberSystem numberSystem) throws InvalidDataException {
    // some logic to convert the byte array supplied by the values param to an Object.
}

public static byte[] convertToBytes(Object value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
    // some logic to convert the Object supplied by the'value' param to a byte array.
}
}

ตัวอย่างของ enum:

public enum EnumIntegerMock implements EnumConverter {
    VALUE0(0), VALUE1(1), VALUE2(2);

    private final int value;

    private EnumIntegerMock(int value) {
        this.value = value;
    }

public Integer convert() {
    return value;
}

}

public enum EnumByteMock implements EnumConverter {
    VALUE0(0), VALUE1(1), VALUE2(2);

    private final byte value;

    private EnumByteMock(int value) {
        this.value = (byte) value;
    }

    public Byte convert() {
        return value;
    }
}

0

เพียงเพราะคำตอบที่ยอมรับนั้นไม่มีอยู่ในตัว:

รหัสสนับสนุน:

public interface EnumWithCode<E extends Enum<E> & EnumWithCode<E>> {

    public Integer getCode();

    E fromCode(Integer code);
}


public class EnumWithCodeMap<V extends Enum<V> & EnumWithCode<V>> {

    private final HashMap<Integer, V> _map = new HashMap<Integer, V>();

    public EnumWithCodeMap(Class<V> valueType) {
        for( V v : valueType.getEnumConstants() )
            _map.put(v.getCode(), v);
    }

    public V get(Integer num) {
        return _map.get(num);
    }
}

ตัวอย่างการใช้งาน:

public enum State implements EnumWithCode<State> {
    NOT_STARTED(0), STARTED(1), ENDED(2);

    private static final EnumWithCodeMap<State> map = new EnumWithCodeMap<State>(
            State.class);

    private final int code;

    private State(int code) {
        this.code = code;
    }

    @Override
    public Integer getCode() {
        return code;
    }

    @Override
    public State fromCode(Integer code) {
        return map.get(code);
    }

}


0

หากคุณมีรถคลาส

public class Car {
    private Color externalColor;
}

และคุณสมบัติสีเป็นคลาส

@Data
public class Color {
    private Integer id;
    private String name;
}

และคุณต้องการแปลงสีเป็น Enum

public class CarDTO {
    private ColorEnum externalColor;
}

เพียงเพิ่มวิธีการในคลาสColorเพื่อแปลงสีในColorEnum

@Data
public class Color {
    private Integer id;
    private String name;

    public ColorEnum getEnum(){
        ColorEnum.getById(id);
    }
}

และภายในColorEnumใช้เมธอด getById ()

public enum ColorEnum {
...
    public static ColorEnum getById(int id) {
        for(ColorEnum e : values()) {
            if(e.id==id) 
                return e;
        }
    }
}

ตอนนี้คุณสามารถใช้ classMap

private MapperFactory factory = new DefaultMapperFactory.Builder().build();
...
factory.classMap(Car.class, CarDTO.class)
    .fieldAToB("externalColor.enum","externalColor")
    .byDefault()
    .register();
...
CarDTO dto = mapper.map(car, CarDTO.class);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.