Carcigenicate
Carcigenicate

Reputation: 45736

How do I set a final field via a setter?

I have the following abbreviated class:

public class Employee {

    private final float pointPosition;

    public Employee(float pointPosition) {
        this.pointPosition = pointPosition;
    }

}

I'd like to do checks on the pointPosition being passed in by the constuctor, to ensure that it doesn't exceed 1.0.

I tried moving the assignment to it's own private setter method that does a precondition check, but obviously that gave me an error since I'm reassigning a final field outside of the constructor.

I could change the constructor to something like:

public Employee(float newPointPosition) {
    verifyPointPosition(newPointPosition); //Will throw
    this.pointPosition = pointPosition;
}

But I'd prefer to have it all wrapped up neatly in it's own method.

What are my options here?

Upvotes: 4

Views: 3602

Answers (2)

tkausl
tkausl

Reputation: 14269

Option 1: Don't make it final

You could just not make it final and make the setter private.


Option 2: Do the check and set in the Constructor

That's what you already showed.


Option 3: The hackish way

You can set final variables with reflection, however i would definitely not recommend this unless you're forced to.


I'd go with Option 2. If you're worried that your constructor gets too messy, you can just create additional constructors and set them private, for example:

public class MyClass {
    private final float variable;

    public MyClass(float variable) {
        this();
        if(variable < 0.0f || 1.0f < variable)
            throw new IllegalArgumentException("'variable' has to be between 0.0 and 1.0");
        this.variable = variable;
    }

    private MyClass() {
        //Set everything else
    }
}

Actually, this Code will not compile.

Upvotes: 2

durron597
durron597

Reputation: 32323

I recommend doing this by just wrapping the argument passage in a single method call from the constructor.

You haven't said what behavior you want, whether to throw an exception if the value is invalid, or whether to just sanitize it to a normal value, but either way this will work:

public class Employee
  private static final float MAX_POSITION = 1.0f;
  private final float pointPosition;

  public Employee(float pointPosition) {
    this.pointPosition = sanitizePointPosition(pointPosition);
  }

And then you have two options:

  1. Throw an exception:

    private float sanitizePointPosition(float pointPosition) {
      if(pointPosition > MAX_POSITION) {
        throw new IllegalArgumentException("Point position must be <= "
                   + MAX_POSITION + ", it was: " + pointPosition);
      }
      return pointPosition;
    }
    
  2. Set the value to something normal

    private float sanitizePointPosition(float pointPosition) {
      return pointPosition > MAX_POSITION ? MAX_POSITION : pointPosition;
    }
    

Upvotes: 2

Related Questions