英文:
Lazy reinit a list to modifiable after declaring with Collections.emptyList()
问题
以下是翻译好的部分:
想要将列表声明为`List<String> info = Collections.emptyList()`,但当用户调用add(String msg)时,重新初始化为可修改的列表。
这是正确的方式吗:
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);
}
还是
`if (info.equals(e)) {`
如果我有3个这样的情况,我是否可以有以下通用代码:
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;
}
我猜下面的方式不会工作,因为会创建新列表:
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);
}
请注意,最后一个方法中的更改不会影响传递给方法的列表参数,因为Java是按值传递的。所以,最后一个方法可能不会按预期工作。
英文:
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);
}
答案1
得分: 2
请注意,即使Collections.emptyList()
始终返回保存在Collections.EMPTY_LIST
中的一个实例,引用比较不能检测到调用者是否使用了JDK 9+的List.of()
来初始化字段。另一方面,非空也不一定保证可变性。
整个逻辑仅适用于所有调用者及其使用情况已知的private
方法。
但您应该考虑彻底放弃这些特殊情况的替代方案。自从Java 8以来,默认构造函数new ArrayList<>()
将不会创建后备数组。它将推迟到首次添加元素时才执行。
因此,您可以使用简单的new ArrayList<>()
初始化所有字段,并使用简单的add
调用实现addInfo
、addWarn
和addErr
,摆脱addTo
方法、条件语句和重复赋值。甚至可以将字段声明为final
。即使对于未使用的列表,仍然不需要大量内存。
英文:
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.
答案2
得分: 1
考虑您的代码:
final List<String> e = Collections.emptyList();
if(info == e){
info = new ArrayList<>();
}
info.add(s);
我不认为在Java API中有任何保证emptyList()
始终会返回相同的引用(javadoc中指出:“此方法的实现不需要为每次调用创建单独的List对象”)。
考虑到您可能会修改列表,使用new ArrayList<>()
进行初始化比使用emptyList()
更有意义。实际上,使用可能需要进行修改的不可修改列表真的没有太多意义。
然而,如果您真的出于某种原因需要使用emptyList()
,那么也许可以这样做:
if (info.isEmpty())
info = new ArrayList<>();
考虑到您即将向其中添加一个项目,此测试只会通过一次。
英文:
Considering your code:
final List<String> e = Collections.emptyList();
if(info == e){
info = new ArrayList<>();
}
info.add(s);
I don't believe there's any guarantee in the Java API that the same reference will always be returned from emptyList()
(the javadoc states "Implementations of this method need not create a separate List object for each call").
Given you may modify the list it'd make more sense to initialise with new ArrayList<>()
rather than emptyList()
. Really doesn't make much sense to use an unmodifiable list that you may want to modify.
However if you really need to use emptyList()
for some reason, then perhaps:
if (info.isEmpty())
info = new ArrayList<>();
Given you are about to add an item to it this test will only pass once anyway.
答案3
得分: 1
使用.equals
是唯一正确的解决方案,但与更简单的info.isEmpty()
等效。
英文:
Using .equals
is the only correct solution -- but equivalent to the much simpler info.isEmpty()
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论