52

I want a class that I can create instances of with one variable unset (the id), then initialise this variable later, and have it immutable after initialisation. Effectively, I'd like a final variable that I can initialise outside of the constructor.

Currently, I'm improvising this with a setter that throws an Exception as follows:

public class Example {

    private long id = 0;

    // Constructors and other variables and methods deleted for clarity

    public long getId() {
        return id;
    }

    public void setId(long id) throws Exception {
        if ( this.id == 0 ) {
            this.id = id;
        } else {
            throw new Exception("Can't change id once set");
        }
    }
}

Is this a good way of going about what I'm trying to do? I feel like I should be able to set something as immutable after it's initialised, or that there is a pattern I can use to make this more elegant.

Richard Russell
  • 1,105
  • 1
  • 10
  • 19
  • 8
    Is there a GOOD reason for not setting it in the constructor? – Peter Svensson Jan 03 '13 at 19:57
  • 3
    @PeterLiljenberg what if OP needs to have a default constructor as well? – Woot4Moo Jan 03 '13 at 20:03
  • Is this something that could happen and has to be handled during program execution or do you want to prevent the programmer from setting it more than once? – Modus Tollens Jan 03 '13 at 20:05
  • @KatjaChristiansen it isn't the programmer you need to worry about. – Woot4Moo Jan 03 '13 at 20:06
  • @Woot4Moo then I think it should be ok for it to be null (and not final) - a variable that can be set just once feels like a pure violation of "principle of least surprise" – Peter Svensson Jan 03 '13 at 20:07
  • @Woot4Moo I asked because if that case should never happen, I'd use an assertion instead of an exception. – Modus Tollens Jan 03 '13 at 20:07
  • @PeterLiljenberg and if the contract of the class states that all fields will be initialized to non-null values what is the suggestion? I understand it is an extreme case, but the contract must be adhered to. – Woot4Moo Jan 03 '13 at 20:08
  • @Woot4Moo how would that ever be avoided :) if the fields must be non null, how is a set once variable the solution? – Peter Svensson Jan 03 '13 at 20:10
  • @PeterLiljenberg you do a null check against the value. Doing design by contract, while tedious, is of great benefit in these scenarios. If you ensure that all mutators have to go through a check on the object you can validate that your object has been updated correctly. – Woot4Moo Jan 03 '13 at 20:13
  • But they are still not initialized to non null. – Peter Svensson Jan 03 '13 at 20:15
  • 3
    What is wrong with doing it this way? I would have done it the same way: a setter that throws an exception if your try to set it a second time. – Has QUIT--Anony-Mousse Jan 03 '13 at 20:19
  • 1
    @Anony-Mousse I agree - even though I still think it's a bad "pattern". – Peter Svensson Jan 03 '13 at 21:03
  • 3
    @PeterLiljenberg - I can't set it in the constructor as I don't know the id at that time. The ID is returned from a remote server at a later time. After writing this question, I decided to re-design my interactions so the server creates the object itself, but I'm still interested in the best approach here. – Richard Russell Jan 04 '13 at 09:37
  • @KatjaChristiansen - I think using assert is more elegant than what I've done above, but it does mean that the exception won't explicitly be thrown, so I'll likely forget to catch it. – Richard Russell Jan 04 '13 at 09:39
  • What's the scope? Do you need to expose the setter method somehow or an it be isolated in the same class/method? If its a small scope (class, method, factory, package) you might be able to have an interface without the setter that you expose outside and create the actual implementation inside your "scope".... – Peter Svensson Jan 04 '13 at 11:00
  • @PeterLiljenberg - I like the idea of the interface, very neat. Will think about that. – Richard Russell Jan 04 '13 at 11:40
  • 1
    @KatjaChristiansen - cambecc says below "Assertions are disabled by default--they are enabled only with the -ea flag on the JVM command line. So the behavior of your class changes depending on this flag. Without assertions enabled (again, this is the default), you can set the id as many times as you want." Perhaps assertions aren't so good... – Richard Russell Jan 09 '13 at 14:28

12 Answers12

38

Let me suggest you a little bit more elegant decision. First variant (without throwing an exception):

public class Example {

    private Long id;

    // Constructors and other variables and methods deleted for clarity

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = this.id == null ? id : this.id;
    }

}

Second variant (with throwing an exception):

     public void setId(long id)  {
         this.id = this.id == null ? id : throw_();
     }

     public int throw_() {
         throw new RuntimeException("id is already set");
     }
Andremoniy
  • 34,031
  • 20
  • 135
  • 241
  • So the first variant causes the setId to be a noOp when it's called on an already set ID. Nice idea. I also note you've changed the long to a Long so you can test for null. Is that inherently better than having it a long and testing for == 0? – Richard Russell Jan 04 '13 at 09:42
  • 1
    @RichardRussell, I think yes, that is better in a manner, because `null` value is something other, than a numeric type, which is held by your variable. It allows you assign `0` (zero) value, and throw an exception in case when this value is assigned again (in case when first value of id will be `== 0`, your test will allow new assignment, but it must do not allow this). – Andremoniy Jan 04 '13 at 10:15
  • 8
    I would advice against this or at least strongly recommend to change the method name to something like 'setIdUnlessAlreadySet' because 'setID' is quite misleading here and not what this method is doing. It sets the value unless a value is already there. Imagine you call setID(long id) but it simply does not do it. That's a debugging nightmare. – joh-mue Feb 08 '17 at 11:41
13

The "set only once" requirement feels a bit arbitrary. I'm fairly certain what you're looking for is a class that transitions permanently from uninitialized to initialized state. After all, it may be convenient to set an object's id more than once (via code reuse or whatever), as long as the id is not allowed to change after the object is "built".

One fairly reasonable pattern is to keep track of this "built" state in a separate field:

public final class Example {

    private long id;
    private boolean isBuilt;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        if (isBuilt) throw new IllegalArgumentException("already built");
        this.id = id;
    }

    public void build() {
        isBuilt = true;
    }
}

Usage:

Example e = new Example();

// do lots of stuff

e.setId(12345L);
e.build();

// at this point, e is immutable

With this pattern, you construct the object, set its values (as many times as is convenient), and then call build() to "immutify" it.

There are several advantages to this pattern over your initial approach:

  1. There are no magic values used to represent uninitialized fields. For example, 0 is just as valid an id as any other long value.
  2. Setters have a consistent behavior. Before build() is called, they work. After build() is called, they throw, regardless of what values you pass. (Note the use of unchecked exceptions for convenience).
  3. The class is marked final, otherwise a developer could extend your class and override the setters.

But this approach has a fairly big drawback: developers using this class can't know, at compile time, if a particular object has been initialized or not. Sure, you could add an isBuilt() method so developers can check, at runtime, if the object is initialized, but it would be so much more convenient to know this information at compile time. For that, you could use the builder pattern:

public final class Example {

    private final long id;

    public Example(long id) {
        this.id = id;
    }

    public long getId() {
        return id;
    }

    public static class Builder {

        private long id;

        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public Example build() {
            return new Example(id);
        }
    }
}

Usage:

Example.Builder builder = new Example.Builder();
builder.setId(12345L);
Example e = builder.build();

This is much better for several reasons:

  1. We're using final fields, so both the compiler and developers know these values cannot be changed.
  2. The distinction between initialized and uninitialized forms of the object is described via Java's type system. There is simply no setter to call on the object once it has been built.
  3. Instances of the built class are guaranteed thread safe.

Yes, it's a bit more complicated to maintain, but IMHO the benefits outweigh the cost.

cambecc
  • 4,083
  • 1
  • 23
  • 24
  • I still can't create an Example object without the Id set, and then set the Id later. Also, I don't see how the builder pattern helps here. I can't see any difference between using it vs just saying: Example e = new Example(12345) – Richard Russell Jan 04 '13 at 09:46
  • 1
    Hmmm. The "isBuilt" pattern above does allow you to create an Example object without the id set and then set the id later. After the id is set, simply call `build()` to stop any further modifications to the object. – cambecc Jan 04 '13 at 15:49
  • 7
    As for the "builder" pattern, you are right that for this trivial example there is not much difference between it and simply saying `Example e = new Example(12345L)`. The distinction comes from what the types are telling you. If you have an instance of `Example.Builder`, you know all fields are settable at any time (including the id, when you eventually set it). But once you have an instance of `Example`, you know that the object has been fully initialized and won't (can't) change in the future. That is a very powerful guarantee. – cambecc Jan 04 '13 at 15:54
5

I recently had this problem when writing some code to construct an immutable cyclic graph where edges reference their nodes. I also noticed that none of the existing answers to this question are thread-safe (which actually allows the field to be set more than once), so I thought that I would contribute my answer. Basically, I just created a wrapper class called FinalReference which wraps an AtomicReference and leverages AtomicReference's compareAndSet() method. By calling compareAndSet(null, newValue), you can ensure that a new value is set at most once by multiple concurrently modifying threads. The call is atomic and will only succeed if the existing value is null. See the example source below for FinalReference and the Github link for sample test code to demonstrate correctness.

public final class FinalReference<T> {
  private final AtomicReference<T> reference = new AtomicReference<T>();

  public FinalReference() {
  }

  public void set(T value) {
    this.reference.compareAndSet(null, value);
  }

  public T get() {
    return this.reference.get();
  }
}
entpnerd
  • 10,049
  • 8
  • 47
  • 68
  • Short, sweet and so far the only correct answer I could find here at a glance, in particular indeed because of multi-threading issues. – Harald May 24 '23 at 14:05
3

Google's Guava library (which I recommend very highly) comes with a class that solves this problem very well: SettableFuture. This provides the set-once semantics that you ask about, but also a lot more:

  1. The ability to communicate an exception instead (the setException method);
  2. The ability to cancel the event explicitly;
  3. The ability to register listeners that will be notified when the value is set, an exception is notified or the future is canceled (the ListenableFuture interface).
  4. The Future family of types in general used for synchronization between threads in multithreaded programs, so SettableFuture plays very nicely with these.

Java 8 also has its own version of this: CompletableFuture.

Luis Casillas
  • 29,802
  • 7
  • 49
  • 102
2

You can simply add a boolean flag, and in your setId(), set/check the boolean. If I understood the question right, we don't need any complex structure/pattern here. How about this:

public class Example {

private long id = 0;
private boolean touched = false;

// Constructors and other variables and methods deleted for clarity

public long getId() {
    return id;
}

public void setId(long id) throws Exception {
    if ( !touchted ) {
        this.id = id;
         touched = true;
    } else {
        throw new Exception("Can't change id once set");
    }
}

}

in this way, if you setId(0l); it thinks that the ID is set too. You can change if it is not right for your business logic requirement.

not edited it in an IDE, sorry for the typo/format problem, if there was...

Kent
  • 189,393
  • 32
  • 233
  • 301
  • This looks similar to what I had but rather than checking for 0 and implicitly assuming that means the id isn't set, having a boolean flag. Makes sense, but in my case, I know id=0 is invalid (so is equivalent to not set). – Richard Russell Jan 04 '13 at 09:52
  • 2
    @RichardRussell you can do the check in if block. if id==0, return directly, without changing the boolean. or even, if the id passed in equals current id, return directly. this will make setId(2); setId(2); twice not throw exception. you know your requirement best. :) – Kent Jan 04 '13 at 10:05
1

Here's the solution I came up with based on mixing some of the answers and comments above, particularly one from @KatjaChristiansen on using assert.

public class Example {

    private long id = 0L;
    private boolean idSet = false;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        // setId should not be changed after being set for the first time.
        assert ( !idSet ) : "Can't change id from " + this.id + " to " + id;
        this.id = id;
        idSet = true;
    }

    public boolean isIdSet() {
        return idSet;
    }

}

At the end of the day, I suspect that my need for this is an indication of poor design decisions elsewhere, and I should rather find a way of creating the object only when I know the Id, and setting the id to final. This way, more errors can be detected at compile time.

Richard Russell
  • 1,105
  • 1
  • 10
  • 19
  • 3
    You probably don't want to do this. Assertions are disabled by default--they are enabled only with the `-ea` flag on the JVM command line. So the behavior of your class changes depending on this flag. Without assertions enabled (again, this is the default), you can set the id as many times as you want. – cambecc Jan 04 '13 at 16:01
  • 2
    @RichardRussell I'm sorry, I could have made my question about the scenario you are facing a bit clearer in my comment on the question. An assert would document in the code that you really didn't intent to set the value twice and thus want the application to stop _during development_ (it would be switched off before deployment), but if you have a condition that might occur during runtime and from which you want ro recover you shouldn't use it. – Modus Tollens Jan 09 '13 at 20:35
1

I have this class, similar to JDK's AtomicReference, and I use it mostly for legacy code:

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;

@NotThreadSafe
public class PermanentReference<T> {

    private T reference;

    public PermanentReference() {
    }

    public void set(final @Nonnull T reference) {
        checkState(this.reference == null, 
            "reference cannot be set more than once");
        this.reference = checkNotNull(reference);
    }

    public @Nonnull T get() {
        checkState(reference != null, "reference must be set before get");
        return reference;
    }
}

I has single responsibilty and check both get and set calls, so it fails early when client code misuse it.

palacsint
  • 28,416
  • 10
  • 82
  • 109
1

Here are two ways; the first is basically the same as some others mentioned in other answers, but it is here to constrast with the seconds. So the first way, Once is to have a value that can be set only once by enforcing that in the setter. My implementation requires non-null values, but if you want to be able to set to null, then you would need to implement an 'isSet' boolean flag as suggested in other answers.

The second way, Lazy, is to provide a function that lazily supplies the value once the first time the getter is called.

import javax.annotation.Nonnull;

public final class Once<T> 
{
    private T value;

    public set(final @Nonnull T value)
    {
        if(null != this.value) throw new IllegalStateException("Illegal attempt to set a Once value after it's value has already been set.");
        if(null == value) throw new IllegalArgumentException("Illegal attempt to pass null value to Once setter.");
        this.value = value;
    }

    public @Nonnull T get()
    {
        if(null == this.value) throw new IllegalStateException("Illegal attempt to access unitialized Once value.");
        return this.value;
    }
}

public final class Lazy<T>
{
    private Supplier<T> supplier;
    private T value;

    /**
     * Construct a value that will be lazily intialized the
     * first time the getter is called.
     *
     * @param the function that supplies the value or null if the value
     *        will always be null.  If it is not null, it will be called
     *        at most one time.  
     */
    public Lazy(final Supplier<T> supplier)
    {
        this.supplier = supplier;
    }

    /**
     * Get the value.  The first time this is called, if the 
     * supplier is not null, it will be called to supply the
     * value.  
     *
     * @returns the value (which may be null)
     */
    public T get()
    {
        if(null != this.supplier) 
        {
            this.value = this.supplier.get();
            this.supplier = null;   // clear the supplier so it is not called again
                                    // and can be garbage collected.
        }
        return this.value;
    }
}

So you might use these as follows;

//
// using Java 8 syntax, but this is not a hard requirement
//
final Once<Integer> i = Once<>();
i.set(100);
i.get();    // returns 100
// i.set(200) would throw an IllegalStateException

final Lazy<Integer> j = Lazy<>(() -> i);
j.get();    // returns 100
Ezward
  • 17,327
  • 6
  • 24
  • 32
0

try have an int checker like

private long id = 0;
static int checker = 0;

public void methodThatWillSetValueOfId(stuff){
    checker = checker + 1

    if (checker==1){
        id = 123456;
    } 
}
0

//u can try this:

class Star
{
    private int i;
    private int j;
    static  boolean  a=true;
    Star(){i=0;j=0;}
    public void setI(int i,int j) {
        this.i =i;
        this.j =j;
        something();
        a=false;
    }
    public void printVal()
    {
        System.out.println(i+" "+j);
    }
    public static void something(){
         if(!a)throw new ArithmeticException("can't assign value");
    }
}

public class aClass
{
    public static void main(String[] args) {
        System.out.println("");
        Star ob = new Star();
        ob.setI(5,6);
        ob.printVal();
        ob.setI(6,7);
        ob.printVal();
    }
}
-2

Marking a field private and not exposing a setter should be sufficient:

public class Example{ 

private long id=0;  

   public Example(long id)  
   {  
       this.id=id;
   }    

public long getId()  
{  
     return this.id;
}  

if this is insufficient and you want someone to be able to modify it X times you can do this:

public class Example  
{  
    ...  
    private final int MAX_CHANGES = 1;  
    private int changes = 0;    

     public void setId(long id) throws Exception {
        validateExample(); 
        changes++; 
        if ( this.id == 0 ) {
            this.id = id;
        } else {
            throw new Exception("Can't change id once set");
        }
    }

    private validateExample  
    {  
        if(MAX_CHANGES==change)  
        {  
             throw new IllegalStateException("Can no longer update this id");   
        }  
    }  
}  

This approach is akin to design by contract, wherein you validate the state of the object after a mutator (something that changes the state of the object) is invoked.

Woot4Moo
  • 23,987
  • 16
  • 94
  • 151
  • Answer does not fit the question. – MrSmith42 Jan 03 '13 at 19:58
  • @Woot4Moo i did not downvote. still, i don't think the answer makes sense. the first snippet reinvents exactly the semantics of `final` without using the keyword. – gefei Jan 03 '13 at 20:04
  • @gefei pretty sure final is there for a very specific reason, is it not the case that I can use reflection and modify a private variable that is not marked as final? I believe the answer to that is yes. – Woot4Moo Jan 03 '13 at 20:06
-6

I think the singleton pattern might be something you should look into. Google around a bit to check if this pattern meets your design goals.

Below is some sudo code on how to make a singleton in Java using enum. I think this is based off Joshua Bloch's design outlined in Effective Java, either way it's a book worth picking up if you don't have it yet.

public enum JavaObject {
    INSTANCE;

    public void doSomething(){
        System.out.println("Hello World!");
    }
}

Usage:

JavaObject.INSTANCE.doSomething();
Dan
  • 1,179
  • 2
  • 10
  • 18