我有一个方法,该方法返回项目列表并以一个限制(由Stream#limit
使用)作为参数:
public List<Integer> getItems(Long limit) {
return IntStream.range(1, 10)
.limit(limit)
.boxed()
.collect(Collectors.toList());
}
如何设置参数以接受所有项目(无限制)?
我的尝试:
Long limit5 = 5L;
System.out.println("With limit 5:" + getItems(limit5));
// works fine: 5 items
Long noLimitZero = 0L;
System.out.println("Without limit (zero): " + getItems(noLimitZero));
// why 0 mean "no items" instead of "all items"
Long noLimitNegative = -1L;
System.out.println("Without limit (negative number): " + getItems(noLimitNegative));
// IllegalArgumentException
Long noLimitNull = null;
System.out.println("Without limit (null): " + getItems(noLimitNull));
// NullPointerException
通过Long.MAX_VALUE
不是解决方案。
例如,MongoDB的FindIterable#limit
可以无限制地使用0
或null
。
public List<Integer> getItems(Long limit) {
MongoDatabase mongo = new MongoClient().getDatabase("example");
MongoCollection<Document> documents = mongo.getCollection("items");
FindIterable<Document> founded = documents.find();
List<Integer> items = new ArrayList<>();
for (Document doc : founded.limit(limit.intValue())) {
items.add(doc.getInteger("number"));
}
return items;
}
方法之间的这种不一致会导致不兼容,例如,一个与方法List<Integer> getItems(Long limit)
的接口以及两个实现:内存和MongoDB。
方法Stream#skip
和FindIterable#skip
的一致性得以保留。
--------------------------
| Java | Mongo |
------------------------------------
limit = 0 | none items | all items |
------------------------------------
skip = 0 | none skip | none skip |
------------------------------------
我想没有办法将“无限制”参数传递给Stream#limit
,所以我必须重构此方法以采用“限制”和0
或null
或{{1 }}为“无限制”。
-1
或者:
public static List<Integer> getItems(Long limit) {
if (limit == null || limit == 0 || limit == -1) {
return IntStream.range(1, 10)
.boxed()
.collect(Collectors.toList());
} else {
return IntStream.range(1, 10)
.limit(limit)
.boxed()
.collect(Collectors.toList());
}
}
有更好的方法来实现方法public static List<Integer> getItems(Long limit) {
IntStream items = IntStream.range(1, 10);
if (limit != null && limit != 0 && limit != -1) {
items = items.limit(limit);
}
return items.boxed()
.collect(Collectors.toList());
}
之间的一致性吗?
答案 0 :(得分:0)
因此,您尝试执行的操作存在几层问题。
您说“实用性不是一个论点”,这很好,但是让我指出,Long.MAX_VALUE
确实超过了地球上原子的数量,因此您获得更多条目的可能性来自数据库的确很小。更不用说继续将这些数据收集到一个列表中,因此您也可能在自己的应用程序中遇到内存问题。
因此,第二件事是limit()
的语义是它对条目的数量施加了固定的限制,而“ infinity”不是固定的限制;因此limit()
并不是您想要的。
第三,您似乎正在寻找一种解决方法,因此我们可以使用一种模式来维持自己的计数器。您想要的是类似AtomicBigInteger
的东西,它在JDK but is shown here中不存在。
所以您要做的是像这样创建一个Predicate
class BelowValue<T> implements Predicate<T> {
BigInteger limit = BigInteger.ZERO;
AtomicBigInteger counter = new AtomicBigInteger();
public BelowValue(BigInteger limit) {
this.limit = limit;
}
public BelowValue() {}
public boolean test(T ignored) {
// short circuit on zero
if (BigInteger.ZERO.compareTo(limit) == 0) { return true; }
// check actual condition
return counter.incrementAndGet().compareTo(limit) > 0;
}
}
然后您可以在(Java 8)的流中使用它
Predicate<T> filter = new BelowValue<>(limit);
return stream
.filter(filter)
.boxed()
.collect(Collectors.toList());
但是请注意,filter
不是短路操作,因此,如果您有无限流,则该流不会终止(并且如果流的长度比限制大小)。
Java 9的takeWhile
处于短路状态,因此在上面的示例中,您可以用filter
代替它。