Declare final variable, but set later
Solution 1:
You can set a final
variable only in a constructor or in an initializer. Regular methods cannot change the value of variables declared final
.
Solution 2:
You can't. But you can guarantee no external object changes it if it's private and you don't have a setter for it.
Alternatively, you can wrap the long value in another class - LazyImmutableLong
. But this is a more verbose approach, and you probably don't need it (note: the class below is not thread-safe)
class LazyImmutableLong {
private Long value;
public void setValue(long value) {
if (this.value != null) {
return; // the value has already been set
}
this.value = value;
}
public long getValue() {return value;}
}
And in your activity
private LazyImmutableLong id = new LazyImmutableLong();
public void onCreate(..) {
id.setValue(..);
}
Solution 3:
The following Worm
(Write-Once-Read-Many) class could help in this kind of scenario.
We could create a nested Wrapper
class, that stores the final variable you need. To initialize this variable, you just should call a constructor of the wrapper
object. When you call the method getData()
, you will get a reference of the final variable in case it is initialized, otherwise, you will get null
.
The methods getData()
and setData(T data)
are required to be thread-safe. To provide it, we use a volatile
modifier for the wrapper
object. Reading a volatile variable is synchronized and writing to a volatile variable is synchronized, too. Even though some efforts were made to make this code thread-safe I didn't test it in this respect. Depending on the level of thread safety you may consider to make setter and getter synchronized.
public class Worm<T> {
private volatile Wrapper<T> wrapper;
public Worm() {}
public Worm(T data) throws IllegalAccessError
{
setData(data);
}
public T getData()
{
if (wrapper == null)
return null;
return wrapper.data;
}
public void setData(T data) throws IllegalAccessError
{
if (wrapper != null)
throw new IllegalAccessError();
else
wrapper = this.new Wrapper<>(data);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Worm<T> other = (Worm<T>) obj;
return Objects.equals(this.getData(), other.getData());
}
@Override
public int hashCode() {
return Objects.hashCode(this.getData());
}
final private class Wrapper<T> {
final private T data;
Wrapper(T data) {
this.data = data;
}
}
}