Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 不使用受保护/受约束集合的原因_Java_Collections_Constraints_Predicate - Fatal编程技术网

Java 不使用受保护/受约束集合的原因

Java 不使用受保护/受约束集合的原因,java,collections,constraints,predicate,Java,Collections,Constraints,Predicate,是否有任何理由/参数不实现基于谓词/约束限制其成员的Java集合 考虑到这种功能经常是必需的,我希望它已经在ApacheCommons或Guava等集合框架上实现。但是,尽管如此,番石榴和芭乐还是建议不要使用类似的方法 声明说,只要有适当的文档记录,一个集合可能会对其元素设置任何限制,因此我不明白为什么不鼓励使用受保护的集合。还有什么其他选项可以确保整数集合在不隐藏整个集合的情况下从不包含负值?这只是偏好的问题-看看线程-我认为这就是它的本质。另外,只检查add()我只对不可变对象足够好。几乎没

是否有任何理由/参数不实现基于谓词/约束限制其成员的Java集合

考虑到这种功能经常是必需的,我希望它已经在ApacheCommons或Guava等集合框架上实现。但是,尽管如此,番石榴和芭乐还是建议不要使用类似的方法


声明说,只要有适当的文档记录,一个集合可能会对其元素设置任何限制,因此我不明白为什么不鼓励使用受保护的集合。还有什么其他选项可以确保整数集合在不隐藏整个集合的情况下从不包含负值?

这只是偏好的问题-看看线程-我认为这就是它的本质。另外,只检查
add()
我只对不可变对象足够好。

几乎没有一个(“可接受”)答案,所以我只想补充一些想法:

如注释中所述,已允许抛出带有原因的
IllegalArgumentException

如果元素的某些属性阻止将其添加到此集合

因此可以说,在集合接口的设计中明确考虑了这种情况,没有明显的、深刻的、纯技术的(与接口合同相关的)理由不允许创建这样的集合


然而,在考虑可能的应用程序模式时,很快就会发现这样一个集合的观察行为可能是。。。至少可以说是违反直觉的

dcsohl在评论中已经提到了一个,并提到了这样一个集合只会是另一个集合的视图的情况:

List<Integer> listWithIntegers = new ArrayList<Integer>();

List<Integer> listWithPositiveIntegers = 
    createView(listWithIntegers, e -> e > 0);

//listWithPositiveIntegers.add(-1); // Would throw IllegalArgumentException
listWithIntegers.add(-1); // Fine

// This would be true:
assert(listWithPositiveIntegers.contains(-1));
(这可能很微妙,但可能是个问题)

当创建集合后条件发生变化时(无论它是否只是一个视图),所有这些都可能变得更加棘手。例如,我们可以想象这样一系列调用:

List<Integer> listWithPositiveIntegers = createList(e -> e > 0);

listWithPositiveIntegers.add(1); // Fine
listWithPositiveIntegers.add(2); // Fine
listWithPositiveIntegers.add(Arrays.asList(3,-4,5)); // Throws

assert(listWithPositiveIntegers.contains(3)); // True or false?
assert(listWithPositiveIntegers.contains(5)); // True or false?
List<Integer> listWithPredicate = create(predicate);
listWithPredicate.add(-1); // Fine 
someMethod();
listWithPredicate.add(-1); // Throws
其中一条评论已经提到了可能的性能问题。这当然是正确的,但我认为这并不是一个强有力的技术论据:无论如何,
集合
接口的任何方法的运行时都没有形式上的复杂性保证。你不知道一个
集合需要多长时间。添加(e)
调用需要多长时间。对于
LinkedList
它是O(1),但是对于
TreeSet
它可能是O(n log n)(谁知道此时
n
是什么)

性能问题和可能的不一致性可能被视为更一般性陈述的特例:

这样的集合允许在许多操作中基本上执行任意代码,具体取决于谓词的实现。

这可能会产生任意的影响,并使关于算法、性能和确切行为(一致性方面)的推理变得不可能



底线是:不使用这样的集合可能有很多原因。但我想不出一个强有力的一般性技术理由。因此,可能存在此类集合的应用案例,但考虑到此类集合的具体用途,应牢记注意事项

我想说,这样的集合会有太多的责任,违反SRP

我在这里看到的主要问题是使用集合的代码的可读性和可维护性。假设您有一个只允许添加正整数的集合(
collection
),并在整个代码中使用它。然后需求发生变化,只允许向其中添加奇数正整数。因为没有编译时检查,所以与使用单独的封装集合的包装器类相比,在代码中查找向该集合添加元素的所有实例要困难得多

当然,虽然它甚至还没有达到这样的极限,但它与对应用程序中的所有对象使用
Object
引用有一些相似之处

更好的方法是利用编译时检查并遵循良好的OOP原则,如类型安全和封装。这意味着为集合元素创建一个单独的包装类或单独的类型

例如,如果您确实想确保只在上下文中使用正整数,可以创建一个单独的类型
PositiveInteger extends Number
,然后将它们添加到
集合中。通过这种方式,您可以获得编译时安全性,并且将
PositiveInteger
转换为
odd PositiveInteger
所需的工作量要少得多


枚举是首选专用类型而不是运行时约束值(常量字符串或整数)的一个很好的例子。

@dcsohl可以为
集合提供相同的参数。不可修改*(…)
集合(尽管有人可能会争论这是否仅仅意味着某些特定于语言的缺点)@有趣的是,
add
方法已经允许抛出一个
IllegalArgumentException
,用于“…元素的某些属性阻止将其添加到此集合”的情况。因此,我也不认为不使用这样一个集合有什么深刻的技术原因。弃用注释表明它是约束的替代品。这样的
列表
可能效率低下。例如,
Collections.swap
将检查这两个项上的谓词,即使它们都已在
列表中。您无法覆盖此行为,因为它是静态的。这可能会对
集合的性能产生重大影响。例如,sort
。@biziclop实际上,在这种情况下,
add()
的性能更差。但是
predicate.setForbiddingNegatives(true);