ChatGPT解决这个技术问题 Extra ChatGPT

Best way to create enum of strings?

What is the best way to have a enum type represent a set of strings?

I tried this:

enum Strings{
   STRING_ONE("ONE"), STRING_TWO("TWO")
}

How can I then use them as Strings?


Z
Zon

I don't know what you want to do, but this is how I actually translated your example code....

package test;

/**
 * @author The Elite Gentleman
 *
 */
public enum Strings {
    STRING_ONE("ONE"),
    STRING_TWO("TWO")
    ;

    private final String text;

    /**
     * @param text
     */
    Strings(final String text) {
        this.text = text;
    }

    /* (non-Javadoc)
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
        return text;
    }
}

Alternatively, you can create a getter method for text.

You can now do Strings.STRING_ONE.toString();


I don't know if it is a compiler requirement, but private String text should be final.
@Tomás Narros Yes, you can still assign to it in the constructor, as long as you don't give it a value when you declare it final.
@The Elite Gentleman It would be bad if the value of an enum constant changed during runtime, so even if not required, final would be best.
Don't forget that Enums cannot be constructed with new as the constructor is private. Essentially, object creation is prohibited and final is not really necessary in this case.
@BuhakeSindi: that's true, but accidentally one may be inclined to put a setText(String) on the enum and that can unleash hell :) final kind of documents your intent that it's a constant with compiler support. If you were to use String constants you wouldn't declare it as public static String, right?
v
vaichidrewar

Custom String Values for Enum

from http://javahowto.blogspot.com/2006/10/custom-string-values-for-enum.html

The default string value for java enum is its face value, or the element name. However, you can customize the string value by overriding toString() method. For example,

public enum MyType {
  ONE {
      public String toString() {
          return "this is one";
      }
  },

  TWO {
      public String toString() {
          return "this is two";
      }
  }
}

Running the following test code will produce this:

public class EnumTest {
  public static void main(String[] args) {
      System.out.println(MyType.ONE);
      System.out.println(MyType.TWO);
  }
}


this is one
this is two

This is not an efficient way to do this. This creates a new custom class for every value in the enumeration. In the above example, you'll see the following in the bin directory: EnumTest$MyType.class EnumTest$MyType$1.class EnumTest$MyType$2.class which will add up real quick. Best to do it as the expected answer, by passing in values to the enum constructor. I actually disagree with overriding toString(); I believe it's better to use an explicit getter such as getKey() since overriding toString() may be unexpected by another user of the enum.
totally agree with @MattQuigley . Doing so encourage users to use toString for things it should not be used for. If you need a label, you'd rather add a label attribute
Also, there is no way to go the other way around (from a string to the enum object) which is probably going to be required at some point.
overriding toString does not affect valueOf(), does it?
This may not be efficient, but it certainly is a language capability that most programmers do not know about.
B
Bart Kiers

Use its name() method:

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(Strings.ONE.name());
    }
}

enum Strings {
    ONE, TWO, THREE
}

yields ONE.


Yeah, but Strings.STRING_ONE.name() yields "STRING_ONE", not "ONE". This simply isn't a good answer. You can't have any String that wouldn't be a valid Java identifier, etc.
@Mark, true, it can't handle any character. If the OP just wants a single char, this solution is more straight forward than The Elite Gentleman suggestion. But indeed: if the range of characters exceeds the ones a valid Java identifier can have, this is a no-go. Good point.
It is very reasonable to have an internal naming convention for an enum that is different from what one would want to show with toString() (especially if a user sees the output), so I don't think this is quite what the OP was looking for.
The result from name() may be affected by a obfuscator program. I ran into a similar problem a while ago. For instance, with Proguard you need to work around this. See Processing Enumeration Classes
This is excellent. Works with values like : var_name, var_superlong_but_not_toooooo_long_name, even etc (without the tripple dots)
p
pixel

Either set the enum name to be the same as the string you want or, more generally,you can associate arbitrary attributes with your enum values:

enum Strings {
   STRING_ONE("ONE"), STRING_TWO("TWO");
   private final String stringValue;
   Strings(final String s) { stringValue = s; }
   public String toString() { return stringValue; }
   // further methods, attributes, etc.
}

It's important to have the constants at the top, and the methods/attributes at the bottom.


And also to have a private constructor.
enum constructors are private by default and require no access modifier. But that's a good point about access modifiers in general, I have updated my code to add them to the attribute and accessor.
h
hd42

Depending on what you mean by "use them as Strings", you might not want to use an enum here. In most cases, the solution proposed by The Elite Gentleman will allow you to use them through their toString-methods, e.g. in System.out.println(STRING_ONE) or String s = "Hello "+STRING_TWO, but when you really need Strings (e.g. STRING_ONE.toLowerCase()), you might prefer defining them as constants:

public interface Strings{
  public static final String STRING_ONE = "ONE";
  public static final String STRING_TWO = "TWO";      
}

actually this is what i am trying to avoid...!
Actually, if they also want the toLowerCase() on my solution, they can go Strings.STRING_TWO.toString().toLowerCase().
Sure, but that is not using them as strings as I interpreted it. As Rrackham doesn't seem to require that use, he of course should use the proposed enum solution.
You shouldn't use interface in place of a final class with private constructor. It's a discouraged practice.
@mils, the solutions using enums work just as well in a switch. I would suggest this solution only if Strings are needed directly.
m
mvermand

You can use that for string Enum

public enum EnumTest {
    NAME_ONE("Name 1"),
    NAME_TWO("Name 2");

    private final String name;

    /**
     * @param name
     */
    private EnumTest(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

And call from main method

public class Test {
    public static void main (String args[]){
        System.out.println(EnumTest.NAME_ONE.getName());
        System.out.println(EnumTest.NAME_TWO.getName());
    }
}

A
Adam111p

If you do not want to use constructors, and you want to have a special name for the method, try it this:

public enum MyType {
  ONE {
      public String getDescription() {
          return "this is one";
      }
  },    
  TWO {
      public String getDescription() {
          return "this is two";
      }
  };

  public abstract String getDescription();
}

I suspect that this is the quickest solution. There is no need to use variables final.


but with this one you still have to call getDescription() of which the asking person wants to call ONE or access it as a constant.
I prefer this. What will happen if it need to accept more informations? With this solution just add protected abstract methods and overide it. More over no need to override toString() method. Its clean and can be accept as best answer.
P
Pravin Bansal

Get and set with default values.

public enum Status {

    STATUS_A("Status A"),  STATUS_B("Status B"),

    private String status;

    Status(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
}

Need semicolon after STATUS_B (not comma).