enum properties & side effects - java

I have a question regarding enum (it might be a simple one but ....).
This is my program:
public class Hello {
public enum MyEnum
{
ONE(1), TWO(2);
private int value;
private MyEnum(int value)
{
System.out.println("hello");
this.value = value;
}
public int getValue()
{
return value;
}
}
public static void main(String[] args)
{
MyEnum e = MyEnum.ONE;
}
}
and my question is: Why the output is
hello
hello
and not
hello
?
How the code is "going" twice to the constructor ?
When is the first time and when is the second ?
And why the enum constructor can not be public ?
Is it the reason why it print twice and not one time only ?

Enums are Singletons and they are instanciated upon loading of the class - so the two "hello"s come from instanciating MyEnum.ONE and MyEnum.TWO (just try printing value as well).
This is also the reason why the constuctor must not be public: the Enum guarantees there will ever only be one instance of each value - which it can't if someone else could fiddle with the constructor.

How the code is "going" twice to the constructor ?
Conctructor is invoked for each element of enum. Little change your example for demonstration it:
public class Hello {
public enum MyEnum {
ONE(1), TWO(2);
private int value;
private MyEnum(int value) {
this.value = value;
System.out.println("hello "+this.value);
}
public int getValue() {
return value;
}
}
public static void main(String[] args) {
MyEnum e = MyEnum.ONE;
}
}
Output:
hello 1
hello 2

Your constructor invoke twice. The moment of loading your Enum class it will invoke number of time which equals to number of enum types here.
MyEnum e = MyEnum.ONE; // singleton instance of Enum
consider following
public class Hello {
public enum MyEnum
{
ONE(1), TWO(2), THREE(3);
private int value;
private MyEnum(int value)
{
System.out.println("hello"+value);
this.value = value;
}
public int getValue()
{
return value;
}
}
public static void main(String[] args)
{
MyEnum e = MyEnum.ONE;
}
}
Out put
hello1
hello2
hello3

Related

It there better way to cast Int to enum in Java?

I see this question
but I need to define a lot of enum type and do a lot of duplicate work, can every enum extends some thing? like this:
public static enum Type {
;
public final int value;
Type(int v) {
this.value = v;
}
public static Type fromInt(int v) {
for (Type type : values()) {
if (type.value == v) {
return type;
}
}
return null;
}
}
public static enum ENUM1 extends Type{
A(1), B(5), C(10);
}
public static enum ENUM2 extends Type{
D(1), E(20), F(30);
}
As seen in this question, you cannot subclass enums in java. End of story. If you describe in detail what you want to achieve, people might suggest better solution than enums.
About parsing to enum from its' int value, what you have done will work, but it would be better to do something like this:
public enum MyEnum {
A(1),
B(2),
C(3);
private final int value;
MyEnum(int value) {
this.value = value;
}
private static Map<Integer, MyEnum> valueToEnumMap;
public static MyEnum parseFromValue(int value) {
if (valueToEnumMap == null) {
valueToEnumMap = new HashMap<>();
for (MyEnum myEnum : MyEnum.values()) {
valueToEnumMap.put(myEnum.value, myEnum);
}
}
return valueToEnumMap.get(value);
}
}
Initialise a Map with keys the values of the enum, and values the enum itself, and get enums from this map. Depending on your use case, you might want to add check for duplicate keys, currently in case of duplication later pairs will overwrite previous ones.
Alternatively, you could try this.
import java.util.Arrays;
/** Int <-> Enum. */
public class EnumToIntMap
{
/**
*
* Main method.
*
* #param args commandline arguments, should they be needed.
*
*/
public static void main(String[] args)
{
interface Type
{
int value();
static <E extends Enum<E> & Type> E fromValue(Class<E> clazz, final int value)
{
return
Arrays.stream(clazz.getEnumConstants())
.parallel()
.filter(each -> each.value() == value)
.findAny()
.orElseThrow()
;
}
}
enum Enum1 implements Type
{
A(1),
B(5),
C(10),
;
private final int value;
Enum1(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
enum Enum2 implements Type
{
D(1),
E(20),
F(30),
;
private final int value;
Enum2(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
}
}

Add values to a Java ENUM for testing purposes

I'm trying to make some multi-threading test, using JMockit in a code similar to this one:
class scratch_1 {
public static void main(String[] args) {
for (final Car ex: Car.values()) {
System.out.println(ex.getValue());
}
}
}
enum Car {
A(1);
public int getValue() {
return value;
}
private final int value;
Car(final int value){
this.value = value;
}
}
The problem is that to test this, my for cycle should handle more than one Car (the multi-threading logic happens inside). However, I can't change the enum, because at this point in time we only have 1 car, but will have more in the following springs.
How can I add another Car in runtime, only for testing?
EDIT:
This is what I have tried that didn't work:
new Car(2); -> no new instances of enumarators
Create a second class called SpecialCar with 2 SpecialCars, and replace them during tests.
Class SpecialCar extends -> enums can't be extended
mock the values() method from Car.
so
new Expectations() {
{
car.values();
result = {car.A... }
Problem : no more cars to add to array.
There is Car.values(). So either wait writing the unit test, or:
Add a second Car value, write a the unit tests based on values(), agnostic towards the specific constant.
Remove the second Car value, and check all in into the version control system.
Some test may be disarmed because of the being just one value, and maybe even needs a check on if (Car.values().length != 0).
You can have your enum implement an interface, and have a test enum that also implements that interface, and then pass the class of the appropriate enum into the test.
public interface Vehicle {
public int getValue();
}
public enum Car implements Vehicle {
A(1);
public int getValue() {
return value;
}
private final int value;
Car(final int value){
this.value = value;
}
}
public enum TestCar implements Vehicle {
A(1), B(2);
public int getValue() {
return value;
}
private final int value;
Car(final int value){
this.value = value;
}
}
public void test(Class<? extends Vehicle> clazz) {
for (final Vehicle vehicle : clazz.getEnumConstants()) {
System.out.println(vehicle.getValue());
}
}

How to get value from a Java enum

I have a enum which looks like:
public enum Constants{
YES("y"), NO("N")
private String value;
Constants(String value){
this.value = value;
}
}
I have a test class which looks like
public class TestConstants{
public static void main(String[] args){
System.out.println(Constants.YES.toString())
System.out.println(Constants.NO.toString())
}
}
The output is:
YES
NO
instead of
Y
N
I am not sure what is wrong here ??
You need to override the toString method of your enum:
public enum Constants{
YES("y"), NO("N")
// No changes
#Override
public String toString() {
return value;
}
}
You can also add a getter to the enumeration and simply call on it to access the instance variable:
public enum Constants{
YES("Y"), NO("N");
private String value;
public String getResponse() {
return value;
}
Constants(String value){
this.value = value;
}
}
public class TestConstants{
public static void main(String[] args){
System.out.println(Constants.YES.getResponse());
System.out.println(Constants.NO.getResponse());
}
}
Create a getValue() method in your enum, and use this instead of toString().
public enum Constants{
YES("y"), NO("N")
private String value;
Constants(String value){
this.value = value;
}
}
public String getValue(){
return value;
}
And instead of:
System.out.println(Constants.YES.toString())
System.out.println(Constants.NO.toString())
(Which are also missing a semi-colon), use
System.out.println(Constants.YES.getValue());
System.out.println(Constants.NO.getValue());
Hope this solved your problem. If you do not want to create a method in your enum, you can make your value field public, but this would break encapsulation.
Write Getter and Setter for value and use:
System.out.println(Constants.YES.getValue());
System.out.println(Constants.NO.getValue());
String enumValue = Constants.valueOf("YES")
Java doc ref: https://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#valueOf(java.lang.Class,%20java.lang.String)

How to use constructor in enum?

I want to use an enum to create a singleton class in java. Should look like this:
public enum mySingleton implements myInterface {
INSTANCE;
private final myObject myString;
private mySingleton(myObject myString) {
this.myString= myString;
}
}
Looks like I cannot use any parameters in the constructor. Is there any workaround for this? Thanks in advance
Yor enum is wrong. Below correct declaration:
public class Hello {
public enum MyEnum {
ONE("One value"), TWO("Two value"); //Here elements of enum.
private String value;
private MyEnum(String value) {
this.value = value;
System.out.println(this.value);
}
public String getValue() {
return value;
}
}
public static void main(String[] args) {
MyEnum e = MyEnum.ONE;
}
}
Output:
One value
Two value
Conctructor is invoked for each element of enum.
You can try this:
enum Car {
lamborghini(900),tata(2),audi(50),fiat(15),honda(12);
private int price;
Car(int p) {
price = p;
}
int getPrice() {
return price;
}
}
public class Main {
public static void main(String args[]){
System.out.println("All car prices:");
for (Car c : Car.values())
System.out.println(c + " costs "
+ c.getPrice() + " thousand dollars.");
}
}
Also see more demos

Using enums in Java

Constants given in the following enum,
enum StringConstatns {
ONE {
#Override
public String toString() {
return "One";
}
},
TWO {
#Override
public String toString() {
return "Two";
}
}
}
public final class Main {
public static void main(String... args) {
System.out.println(StringConstatns.ONE + " : " + StringConstatns.TWO);
}
}
can be accessed just like StringConstatns.ONE and StringConstatns.TWO as shown in the main() method.
I have the following enum representing an int constant(s).
public enum IntegerConstants
{
MAX_PAGE_SIZE(50);
private final int value;
private IntegerConstants(int con) {
this.value = con;
}
public int getValue() {
return value;
}
}
This requires accessing the constant value like IntegerConstants.MAX_PAGE_SIZE.getValue().
Can this enum be modified somehow in a way that value can be accessed just like IntegerConstants.MAX_PAGE_SIZE as shown in the first case?
The answer is no, you cannot. You have to call:
IntegerConstants.MAX_PAGE_SIZE.getValue()
If you really want a shortcut, you could define a constant somewhere like this:
public class RealConstants {
final public static int MAX_PAGE_SIZE = 50;
}
public enum IntegerConstants
{
MAX_PAGE_SIZE(RealConstants.MAX_PAGE_SIZE);//reuse the constant
private final int value;
private IntegerConstants(int con) {
this.value = con;
}
public int getValue() {
return value;
}
}
This is not going to work because your first example does implicit calls to .toString() when you concatenate them with +, whereas there is no implicit conversion to int which is needed for your second example.
You could define them as static final fields, this does exactly what you are searching for:
public class IntegerConstants {
public static final int MAX_PAGE_SIZE = 50;
}

Categories

Resources