簡體   English   中英

Java流參數限制沒有限制(MongoDB不一致)

[英]Java stream parameter limit with no limit (MongoDB inconsistency)

我有一個方法返回項目列表並采取限制(由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不一致

例如,MongoDB的FindIterable#limit可以取0null作為無限制。

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#skipFindIterable#skip

          --------------------------
          | Java       | Mongo     |
------------------------------------
limit = 0 | none items | all items |
------------------------------------
skip = 0  | none skip  | none skip |
------------------------------------

使用Stream#limit重構方法

我想沒有辦法將“無限制”參數傳遞給Stream#limit ,所以我必須重構這個方法以取“limit”和0null-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());
}

有一種更好的方法來實現方法limit之間的一致性?

所以你要做的事情有幾層問題。

你說“實用性不是一個論證”,這很好,但我要指出Long.MAX_VALUE確實超過了地球上的原子數量,所以你獲得的數據量大於數據庫的數量小。 更不用說你繼續將這些數據收集到一個列表中,這樣你就可能在自己的應用程序中遇到內存問題。

所以第二件事是limit()的語義是它對條目數量施加固定限制,而“無窮大”不是固定限制; 因此limit()不是你想要的。

第三,你似乎正在尋找一種方法,所以我們有一個你可以使用的模式,那就是維持自己的計數器。 你想要的是類似於AtomicBigInteger東西,它在JDK中不存在但是在這里顯示

所以你要做的就是像這樣創建一個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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM