11

I have a Java class that is something of the form:-

public class Angle
{
    ANGLE_TYPE angleType;

    ANGLE_TYPE defaultAngleType = ANGLE_TYPE.RAD;

    enum ANGLE_TYPE
    {
        DEG, RAD, DEGMIN, DEGMINSEC;
    }
}

The class has an 'enum' defined, as can be seen. My question regards the instance variable, 'defaultAngleType'. I want it to be the case so that this variable can only be assigned the values RAD or DEG, and to throw an error otherwise.

Any idea how to acheive this?

Konstantin Yovkov
  • 59,030
  • 8
  • 92
  • 140
Jeremy Watts
  • 117
  • 1
  • 8
  • How will you be setting defaultAngleType? As you could just have an if statement in a setter method – McNultyyy Sep 09 '15 at 12:36
  • By the way, the [naming convention for enum](http://stackoverflow.com/q/3069743/642706) is that `ANGLE_TYPE` would be `AngleType` as that is actually a Java class. The `DEG`, `RAD`, and such should be all uppercase as those truly are constants, static class members of type `AngleType`. I’m not being pedantic; I've found in my own use of enums that following this naming convention made my own code more understandable. The IDEs such as NetBeans recognize enums and use special formatting for the enum name (“AngelType”) making it even easier to read, and even less necessary to flag your enums. – Basil Bourque Feb 09 '16 at 03:08

6 Answers6

18

You can use an EnumSet. For example:

Set<ANGLE_TYPE> allowed = EnumSet.of(RAD, DEG);
Basil Bourque
  • 218,480
  • 72
  • 657
  • 915
omerkudat
  • 8,459
  • 4
  • 30
  • 41
3

Probably the enum is not the best structure to use for this.

I'd apply some inheritance-based approach.

interface Angle { }
class DegMin implements Angle { }
class DegMinSec implements Angle { }

interface SpecialAngle extends Angle { } 
class Deg implements SpecialAngle { }
class Rag implements SpecialAngle { }

Having this hierarchy, all of the classes are Angle(s), but only two of them are SpecialAngle(s) (Deg and Rad).

Then, in your class, you'd have:

public class Angle
{
    Angle angleType;

    SpecialAngle defaultAngleType = new Rad();
}

Now defaultAngleType can only hold instances of Rad or Deg.

Konstantin Yovkov
  • 59,030
  • 8
  • 92
  • 140
1

Make defaultAngleType private. In the setter for defaultAngleType, check the argument, and do something like:

public void setDefaultAngleType(ANGLE_TYPE type){
    if(type.equals(DEG) || type.equals(RAD))
        defaultAngleType = type;
    else
        throw new Exception();
}
mattm
  • 5,353
  • 7
  • 39
  • 71
1

Make the constructor of Angle private, and only allow its creation through static factory methods:

private Angle(ANGLE_TYPE type, float value) {
   //...
}

static Angle degrees(float value) {
  return new Angle(ANGLE_TYPE.DEG, value);
}

static Angle radians(float value) {
  return new Angle(ANGLE_TYPE.RAD, value);
}

This means that trying to create one of the others becomes a compile-time error, rather than a runtime error.

Of course, you need to control access to the angleType variable by making it private and providing a getter, because you can't otherwise stop somebody changing the field to one of the forbidden values.

Andy Turner
  • 122,430
  • 10
  • 138
  • 216
0

Here is a redesign suggestion:

You could state that an Angle is always expressed in radians, but has 4 different constructors:

  1. radians
  2. degrees
  3. degrees, minutes
  4. degrees, minutes, seconds

Constructors 2 to 4 would immediately convert degrees/minutes/seconds to radians.

Or you could create a DegreeAngle class extending Angle which would add degree/minutes/seconds setters and getters.

maxime.bochon
  • 542
  • 4
  • 13
0

If you didn't want to use EnumSet you can do a primitive subset by this method, although it does require quite a bit of boilerplate and more protection of fields.

public class Angle {

    private ANGLE_TYPE angleType;

    private ANGLE_TYPE defaultAngleType = DEFAULT_ANGLE_TYPE.RAD.angleType;

    enum ANGLE_TYPE {
        DEG, RAD, DEGMIN, DEGMINSEC;
    }

    enum DEFAULT_ANGLE_TYPE {

        DEG(ANGLE_TYPE.DEG),
        RAD(ANGLE_TYPE.RAD);

        private ANGLE_TYPE angleType;

        DEFAULT_ANGLE_TYPE(ANGLE_TYPE angleType) {
            this.angleType = angleType;
        }

    }

    public Angle(ANGLE_TYPE angleType, DEFAULT_ANGLE_TYPE defaultAngleType) {
        this.angleType = angleType;
        this.defaultAngleType = defaultAngleType.angleType;
    }

}
DJO
  • 11
  • 1