I have a method which return list of items and takes a limit (used by Stream#limit) as parameter:
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.
MongoDB inconsistency
For example MongoDB's FindIterable#limit can take 0 or null as no limit.
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.
Consistency in methods Stream#skip and FindIterable#skip is preserved.
-------------------------- | Java | Mongo | ------------------------------------ limit = 0 | none items | all items | ------------------------------------ skip = 0 | none skip | none skip | ------------------------------------ Refactor method with Stream#limit
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".
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?
Long.MAX_VALUEnot a solution"?Long.MAX_VALUEis not a solution because it is only a workaround. In this case (in memory implementation replacement for fetching from database) theoretically is the risk that may be more than2^63-1records ;) (but practically it isn't an argument). But I would like to know how to work with Java streams. Java streams in memory can be very long or even infinity (for exampleIntStream.iterate(0, i -> i + 1)) and there is may be a case whereLong.MAX_VALUEis too small.limit, but avoid code duplication. Of course, when the stream source does already support a size (likeIntStream.range,Arrays.stream(…),List.subList(…).stream(), orRandom.ints(…)), you should prefer specifying the size in the first place. Usinglimit, even withLong.MAX_VALUEhas performance drawbacks.