Want to declare a list as List<String> info = Collections.emptyList()
but when user calls add(String msg) then re-init to a modifiable list.
Is this the correct way:
private List<String> info = Collections.emptyList();
public void addInfo(String s){
final List<String> e = Collections.emptyList();
if(info == e){
info = new ArrayList<>();
}
info.add(s);
}
Or
if(info.equals(e)){
If I have 3 of these can I have this common code :
public void addInfo(String s) {
info = addTo(s, info);
}
public void addWarn(String s) {
warn = addTo(s, warn);
}
public void addErr(String s) {
errs = addTo(s, errs);
}
private List<String> addTo(String s, @org.jetbrains.annotations.NotNull List<String> t){
final List<String> e = Collections.emptyList();
if(t.equals(e)){
t = new ArrayList<>();
}
t.add(s);
return t;
}
I guess the following wont work due to the new list being created?
private void addTo(String s, @org.jetbrains.annotations.NotNull List<String> t){
final List<String> e = Collections.emptyList();
if(t.equals(e)){
t = new ArrayList<>();
}
t.add(s);
}
Note that even if Collections.emptyList()
always returns the one instance held in Collections.EMPTY_LIST
, a reference comparison does not detect when a caller used JDK 9+ List.of()
to initialize the field. On the other hand, being non-empty does not guaranty mutability either.
The entire logic is suitable only for a private
method were all callers and their usage are known.
But you should consider the alternative of dropping these special cases altogether. Since Java 8, the default constructor new ArrayList<>()
will not create a backing array. It is deferred until the first addition of an element.
So you can initialize all fields with a plain new ArrayList<>()
and implement the addInfo
, addWarn
, and addErr
with a plain add
call, getting rid of the addTo
method, the conditionals, and the repeated assignments. Even declaring the fields final
is possible. While still not requiring a significant amount of memory for the unused lists.