Is it possible to pass an Enum value on your call?

Asked

Viewed 93 times

2

I created in Java a enum for mass measurement units and need the user to pass a value when using it. For example:

enum Weight {
    KILOGRAMS, POUNDS;

    private float value;

    Weight(float value) {
        this.value = value;
    }
}

public class Sample {
    public static void main(String[] args) {
        Weight meuValorParaPeso = Weight.POUNDS(3400); // O peso é de 3400 libras
    }
}

I know that in Java, builders of enum can only be called within the enum and only once, in declaring its constants. A solution would be to create a method setValue to set the value. But I’d like to know if there’s any other way to do that. Preferably a form that is in a single line, as if it were a builder.

My intention with this is to pass the value to certain methods, identifying in which unit of measure the value is. For that reason, I don’t want to create a class or anything like.

  • Just to be pedantic, the unit of weight is not kilogram or pound, but some unit of strength, like Newton. Kilogram and pound are units of mass. D

  • Are you using enum wrong way. There is only one instance of each in the JVM, so change the value of meuValorParaPeso would affect all variables whose value is a POUNDS. There is no escape from creating a class (probably with 2 fields: the value and the unit of measure - in fact, having a enum for the measured unit would make more sense)

  • @Luizfelipe had forgotten that kkkkk I already edited.

  • It seems more like a conceptual error, but Java does not have Adts, so this is not possible to do, at least in the right way.

1 answer

3


Short answer

You are using enum wrong way. Create a class and you’re done.

Long answer

You can’t use it enum the way you intend it, and there are several reasons for it.

First, when you do this:

enum Weight {
    KILOGRAMS, POUNDS;
}

The JVM creates only one instance of each of the values (i.e., in the JVM there is only one instance of KILOGRAMS, and a single instance of POUNDS, both created as variables final static). There’s no way you can create other instances (you can’t have others KILOGRAMS, nor others POUNDS). The very language specification says the following:

An Enum class has no instances other than those defined by its Enum constants. It is a Compile-time error to Attempt to explicitly instantiate an Enum class.

That is, the only existing instances of a enum are those defined by their constants (in the above case they are KILOGRAMS and POUNDS). Any attempt to create new instances explicitly (such as new Weight(), new POUNDS(), etc) will give build error. You cannot create new instances of a enum, beyond those that have already been declared.

It is worth remembering that the builder of a enum may only be private or package private (the default when there is no access modifier).


That is, your idea of using a Setter value will not work as expected. If we do so:

enum Weight {
    // tenho que passar os valores para o construtor aqui, senão não compila
    KILOGRAMS(10), POUNDS(20);

    private float value;
    Weight(float value) {
        this.value = value;
    }

    public float getValue() {
        return value;
    }
    public void setValue(float value) {
        this.value = value;
    }
}

Note that I had to pass the value already in the declaration of KILOGRAMS and POUNDS, otherwise the code does not compile. That is, when each of the enum is initialized, will already be created with the respective value.

But since there’s only one instance of each, then your idea to use the Setter will not work as expected. For example:

Weight peso = Weight.KILOGRAMS;
System.out.println("Peso:" + peso.getValue()); // 10.0

Weight outro = Weight.KILOGRAMS;
outro.setValue(5000); // mudar o valor do outro peso
System.out.println("Outro peso:" + outro.getValue()); // 5000.0
System.out.println("Peso original:" + peso.getValue()); // 5000.0

Note that when changing the value of outro, the value of peso also changed. This is because there is actually only one instance of KILOGRAMS, so much so peso how much outro point to the same instance. You cannot use the enum to save different instances, each one with its value (that is, there is no way to have more than one KILOGRAMS, each with a value different).

And as it is also not possible to create new instances (no new KILOGRAMS(outroValor)), then really have no way to do what you want only with enum.


So what’s the solution?

Create a class (you said you didn’t want*, but in that case I see no other option unless you change your language), which contains the value and unit of measure. Something like this:

public enum WeightUnit {
    KILOGRAMS, POUNDS;
}

public class Weight {
    private float value;
    private WeightUnit unit;
}

// assim você pode fazer:
Weight w1 = new Weight(50, WeightUnit.POUNDS);
Weight w2 = new Weight(100, WeightUnit.KILOGRAMS);

This way it is also more organized, since the first option does not seem very good: your enum original is only to designate the unit of measure, not the value, so it was having a mixture of both concepts in the same place (this, and the constraints of the language, ended up making its initial goal impossible).


* <sarcasm>If you don’t want to create a class, then why are you using Java? </sarcasm> :-)

  • It’s not that I didn’t want to create a class. I just wanted to write a small, duplicity-free code as good practice dictates. And by the time I had written the question, I thought that using classes I would have to duplicate the code several times, because in my head, I would have to create a class for Weight, another to Distance, and so on, all with the same functionality. But then I thought better and created a generic class that solved almost all problems. Anyway, thank you very much for your reply :-)

  • @Jeanextreme002 Smaller code is not necessarily better, often the attempt to "write less" can end up making things worse (as you yourself realized). I see "good practice" as a general guide (recommendations), it is not something that should be followed by-scratching-blindly-at-all-cost-without-thinking (I prefer to be pragmatic, breaking "rules" when necessary). Java is verbose (one of the criticisms to it; today it has improved a little, but it is not yet ideal), and in this case there is not much to do. And creating 2 classes or 2 enums for "weight" and "distance" is not a problem...

  • ...because they are 2 different concepts (although related, since both are units of measure). Of course, the perfect modeling doesn’t exist either, and it depends a lot on the requirements of the system to know which approach would work best (so I just gave a generic suggestion, because I don’t know the whole context, and how does that escape the scope of the question). You could do it in one class (Unit, with a field describing the unit type/name, for example), but without knowing the requirements, it is not possible to enter what would be "better".

Browser other questions tagged

You are not signed in. Login or sign up in order to post.