204

If you look in the enum api at the method name() it says that:

Returns the name of this enum constant, exactly as declared in its enum declaration. Most programmers should use the toString method in preference to this one, as the toString method may return a more user-friendly name. This method is designed primarily for use in specialized situations where correctness depends on getting the exact name, which will not vary from release to release.

Why is better to use toString()? I mean toString may be overridden when name() is already final. So if you use toString and someone overrides it to return a hard-coded value your whole application is down... Also if you look in the sources the toString() method returns exactly and just the name. It's the same thing.

Roland
  • 7,525
  • 13
  • 61
  • 124
spauny
  • 4,976
  • 9
  • 44
  • 61

7 Answers7

240

It really depends on what you want to do with the returned value:

  • If you need to get the exact name used to declare the enum constant, you should use name() as toString may have been overriden
  • If you want to print the enum constant in a user friendly way, you should use toString which may have been overriden (or not!).

When I feel that it might be confusing, I provide a more specific getXXX method, for example:

public enum Fields {
    LAST_NAME("Last Name"), FIRST_NAME("First Name");

    private final String fieldDescription;

    private Fields(String value) {
        fieldDescription = value;
    }

    public String getFieldDescription() {
        return fieldDescription;
    }
}
assylias
  • 321,522
  • 82
  • 660
  • 783
62

Use name() when you want to make a comparison or use the hardcoded value for some internal use in your code.

Use toString() when you want to present information to a user (including a developer looking at a log). Never rely in your code on toString() returning a specific value. Never test it against a specific string value. If your code breaks when someone correctly changes the toString() return, then it was already broken.

From the javadoc (emphasis mine) :

Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method.

kellyfj
  • 6,586
  • 12
  • 45
  • 66
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
32

name() is a "built-in" method of enum. It is final and you cannot change its implementation. It returns the name of enum constant as it is written, e.g. in upper case, without spaces etc.

Compare MOBILE_PHONE_NUMBER and Mobile phone number. Which version is more readable? I believe the second one. This is the difference: name() always returns MOBILE_PHONE_NUMBER, toString() may be overriden to return Mobile phone number.

Jason Baker
  • 192,085
  • 135
  • 376
  • 510
AlexR
  • 114,158
  • 16
  • 130
  • 208
  • 19
    This is not correct!! toString() returns `Mobile phone number` only if you override it to return such value. Otherwise it will return `MOBILE_PHONE_NUMBER` – spauny Nov 08 '12 at 14:59
  • 2
    @spayny, it is obvious that you have to override `toString()`. The catch is that `name()` cannot be overridden since it is final. – AlexR Nov 09 '12 at 18:51
  • 15
    @AlexR you may need to incorporate your above comment in the answer to make it 100% correct – anthonyms Apr 29 '13 at 07:03
  • 6
    I agree with @artfullyContrived as it wasn't obvious to me until I read your comments. – martinatime May 05 '14 at 15:57
19

While most people blindly follow the advice of the javadoc, there are very specific situations where you want to actually avoid toString(). For example, I'm using enums in my Java code, but they need to be serialized to a database, and back again. If I used toString() then I would technically be subject to getting the overridden behavior as others have pointed out.

Additionally one can also de-serialize from the database, for example, this should always work in Java:

MyEnum taco = MyEnum.valueOf(MyEnum.TACO.name());

Whereas this is not guaranteed:

MyEnum taco = MyEnum.valueOf(MyEnum.TACO.toString());

By the way, I find it very odd for the Javadoc to explicitly say "most programmers should". I find very little use-case in the toString of an enum, if people are using that for a "friendly name" that's clearly a poor use-case as they should be using something more compatible with i18n, which would, in most cases, use the name() method.

coding
  • 645
  • 6
  • 7
  • 4
    Thanks for answering. It's been almost 5 years since I asked this question and I've yet to use the toString() method for an enum! 99% of the times I use enums exactly for what you described: serialising and deserialising enum names to/from database. – spauny Mar 17 '17 at 08:59
  • If you are integrating with an existing system (e.g. mainframe) via webservices or just creating a new front-end for an existing database, you will frequently have enum values with hyphens. – MichaelRom Apr 16 '21 at 12:30
7

A practical example when name() and toString() make sense to be different is a pattern where single-valued enum is used to define a singleton. It looks surprisingly at first but makes a lot of sense:

enum SingletonComponent {
    INSTANCE(/*..configuration...*/);

    /* ...behavior... */

    @Override
    String toString() {
      return "SingletonComponent"; // better than default "INSTANCE"
    }
}

In such case:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better
Marcin
  • 591
  • 5
  • 12
5

name() is literally the textual name in the java code of the enum. That means it is limited to strings that can actually appear in your java code, but not all desirable strings are expressible in code. For example, you may need a string that begins with a number. name() will never be able to obtain that string for you.

Intropy
  • 85
  • 2
  • 6
2

You can also use something like the code below. I used lombok to avoid writing some of the boilerplate codes for getters and constructor.

@AllArgsConstructor
@Getter
public enum RetroDeviceStatus {
    DELIVERED(0,"Delivered"),
    ACCEPTED(1, "Accepted"),
    REJECTED(2, "Rejected"),
    REPAIRED(3, "Repaired");

    private final Integer value;
    private final String stringValue;

    @Override
    public String toString() {
        return this.stringValue;
    }
}
Kamyar Miremadi
  • 169
  • 2
  • 7