[英]Java stream parameter limit with no limit (MongoDB inconsistency)
I have a method which return list of items and takes a limit (used by Stream#limit
) as parameter: 我有一个方法返回项目列表并采取限制(由
Stream#limit
)作为参数:
public List<Integer> getItems(Long limit) {
return IntStream.range(1, 10)
.limit(limit)
.boxed()
.collect(Collectors.toList());
}
How to set the parameter to take all items (with no limit)? 如何设置参数以获取所有项目(没有限制)?
My attempts: 我的尝试:
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
Passing Long.MAX_VALUE
is not a solution. 传递
Long.MAX_VALUE
不是解决方案。
For example MongoDB's FindIterable#limit
can take 0
or null
as no limit. 例如,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;
}
This inconsistency between methods causes incompatibility, for example one interface with method List<Integer> getItems(Long limit)
and two implementations: in memory and MongoDB. 方法之间的这种不一致导致不兼容,例如一个接口与方法
List<Integer> getItems(Long limit)
和两个实现:在内存和MongoDB中。
Consistency in methods Stream#skip
and FindIterable#skip
is preserved. 方法的一致性保留
Stream#skip
和FindIterable#skip
。
--------------------------
| Java | Mongo |
------------------------------------
limit = 0 | none items | all items |
------------------------------------
skip = 0 | none skip | none skip |
------------------------------------
I guess there is no way to pass "no limit" parameter to Stream#limit
, so I must refactor this method to takes "limit" and 0
or null
or -1
as "no limit". 我想没有办法将“无限制”参数传递给
Stream#limit
,所以我必须重构这个方法以取“limit”和0
或null
或-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());
}
}
Or: 要么:
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());
}
There is a better way to achieve consistency between methods limit
? 有一种更好的方法来实现方法
limit
之间的一致性?
So there's several layers of problems with what you're trying to do. 所以你要做的事情有几层问题。
You say "practicality isn't an argument" and that's fine, but let me just point out that Long.MAX_VALUE
does exceed the amount of atoms on earth, so the probability that you're getting more entries than that from a database is really small. 你说“实用性不是一个论证”,这很好,但我要指出
Long.MAX_VALUE
确实超过了地球上的原子数量,所以你获得的数据量大于数据库的数量小。 Not to mention that you go on collecting that data into a list so you might run into memory issues in your own application as well. 更不用说你继续将这些数据收集到一个列表中,这样你就可能在自己的应用程序中遇到内存问题。
So the second thing is that the semantics of limit()
is that it imposes a fixed limit on the number of entries and "infinity" is not a fixed limit; 所以第二件事是
limit()
的语义是它对条目数量施加固定限制,而“无穷大”不是固定限制; hence limit()
just isn't what you're looking for. 因此
limit()
不是你想要的。
Third, you seem to be looking for a way around that so there us a pattern you can use, and that's maintaining your own counter. 第三,你似乎正在寻找一种方法,所以我们有一个你可以使用的模式,那就是维持自己的计数器。 What you want is something like an
AtomicBigInteger
which doesn't exist in the JDK but is shown here . 你想要的是类似于
AtomicBigInteger
东西,它在JDK中不存在但是在这里显示 。
So what you'd do is create a Predicate
like this 所以你要做的就是像这样创建一个
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;
}
}
and then you can use it in your stream with (Java 8) 然后你可以在你的流中使用它(Java 8)
Predicate<T> filter = new BelowValue<>(limit);
return stream
.filter(filter)
.boxed()
.collect(Collectors.toList());
Note however that filter
is not a short-circuiting operation, so if you have an infinite stream, this will not terminate (and be very inefficient if your stream is much longer than the limit size). 但请注意,
filter
不是短路操作,因此如果您有无限流,则不会终止(如果您的流比限制大小长得多,则效率非常低)。
Java 9's takeWhile
is short-circuiting, so you can substitute that for filter
in the above example. Java 9的
takeWhile
是短路的,因此您可以在上面的示例中将其替换为filter
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.