我不了解这种方法的实现。它的
public static <T> List<T> add(List<T> list, T element) {
final int size = list.size();
if (size == 0) {
return ImmutableList.of(element);
} else if (list instanceof ImmutableList) {
if (size == 1) {
final T val = list.get(0);
list = Lists.newArrayList();
list.add(val);
} else {
list = Lists.newArrayList(list);
}
}
list.add(element);
return list;
}
为什么不直截了当list.add(element)
?
答案 0 :(得分:2)
代码正在实施添加到给定的列表。如果输入列表是ImmutableList
,则它首先创建一个可变列表(否则它不能添加到它)并将元素复制到它。如果不是,它只使用现有列表。
如果传入的列表为空,则返回ImmutableList
有点奇怪,但如果给出非空ArrayList
,则返回ImmutableList
from django.conf.urls import url
from . import views
app_name = 'saferdb'
urlpatterns = [
url(r'^/$', views.index, name='index'),
url(r'^(?P<pk>[0-9]+)/$', views.detail, name='detail'),
]
1}}要添加,但也许这在更广泛的背景下是有意义的,在何处以及如何使用它。但这种不一致肯定是我在代码审查中查询的内容。
答案 1 :(得分:1)
此方法是反模式,不应使用。它摧毁了可变和不可变的数据结构,提供了两种实现中最差的。
List
失去那个重要的上下文。请参阅&#34;接口&#34;不是ImmutableCollection
的实现部分。通常没有意义可互换地使用这两种类型 - 如果要将内容添加到现有集合中,请使用您拥有的可变集合。如果您打算将集合变为不可变,请不要尝试向其添加内容。此方法会丢弃该意图,并将导致运行时错误和/或性能降低。
答案 2 :(得分:0)
ImmutableList
为什么不是一个直截了当的
list.add(element)
?
如果给定列表不可变,则无法调用该方法。实际上你可以,但通常这样的方法将抛出UnsupportedOperationException
。 documentation的Guavas ImmutableList#add
说
<强>已过时即可。不支持的操作。
保证抛出异常并保留列表未修改。
然而,该方法的目标似乎是通过创建可变克隆来为ImmutableList
支持添加。所以直接的实现将是:
public static <T> List<T> add(List<T> list, T element) {
if (list instanceof ImmutableList) {
// Create mutable clone, ArrayList is mutable
list = Lists.newArrayList(list);
}
list.add(element);
return list;
}
请注意,类型可能会发生变化。虽然输入可能是ImmutableList
,但输出肯定不是。
你可以通过创建一个临时克隆来保持类型,添加它(如图所示)然后再包装一些ImmutableList
。然而,这似乎不是这种方法的目标。
另请注意,在相同情况下的方法可能会向给定列表添加内容,而在某些情况下则会创建新实例。因此,该方法的调用者必须意识到该方法有时会改变他的论点,有时不会。对我来说,这是一个非常奇怪的行为,它必须在文档中突出显示,但我不建议做这样的事情。
该方法的另一个目标似乎是在方法调用时保持列表不可变(如果为空)。这有点奇怪,但可能会在文档中突出显示。因此他们添加了这个电话:
if (size == 0) {
return ImmutableList.of(element);
}
除此之外,他们通过调用
来做一些次要的东西Lists.newArrayList();
而不是
Lists.newArrayList(list);
如果list
目前的尺寸为1
。但是我不确定他们为什么要这么做。在我看来,他们可以保持原样。
总而言之,我可能会实现像
这样的方法/**
* Creates a new list with the contents of the given list
* and the given element added to the end.
*
* <T> The type of the lists elements
*
* @params list The list to use elements of, the list will not be changed
* @params element The element to add to the end of the resulting list
*
* @return A new list with the contents of the given list and
* the given element added to the end. If the given list was
* of type {@link ImmutableList} the resulting list will
* also be of type {@link ImmutableList}.
**/
public static <T> List<T> add(List<T> list, T element) {
List<T> result;
// Create a Stream of all elements for the result
Stream<T> elements = Stream.concat(list.stream(), Stream.of(element));
// If the list was immutable, make the result also immutable
if (list instanceof ImmutableList) {
result = ImmutableList.of(elements.toArray(T[]::new));
} else {
result = elements.collect(Collectors.toList());
}
return result;
}
这样你就不会改变参数list
,如果是,你也会保留列表ImmutableList
。使用Stream#concat
方法可以使这里的事情更有效(它是一个惰性方法),否则我们需要在它们之间创建临时克隆。
但是我们不知道您的方法有哪些目标,因此可能在您的特定方法的上下文中它的作用更有意义。
答案 3 :(得分:0)
这种方法不是&#34;直截了当的list.add(element)
&#34;是因为此方法旨在能够向ImmutableList
添加元素。很明显,这些是不可改变的(如果你看一下,他们的原生add
方法throws an UnsupportedOperationException
),所以唯一的方法就是&#34;添加&#34;对他们来说就是创建一个新列表。
新返回的列表现在是可变的这一事实是一个奇怪的设计决定,只有更广泛的上下文或来自代码作者的输入才能帮助解决这个问题。
空输入列表将返回不可变列表的特殊情况是另一个奇怪的设计决策。没有条件分支,该函数可以正常工作。
因为此方法返回列表的副本,所以应该小心地将结果分配给某个东西,可能是原始变量:
myList = TheClass.add(myList, newElement);
并注意以下用法实际上无效:
TheClass.add(myList, newElement);