-
Notifications
You must be signed in to change notification settings - Fork 29
Description
Hello dev.java team!
Thanks for the excellent https://dev.java/learn/api/streams/ series of articles on Java Streams.
I would like to report a few typos and other small possible mistakes.
In the latest version of article "Adding a Terminal Operation on a Stream", https://dev.java/learn/api/streams/terminal-operations/ (archived at https://web.archive.org/web/20260225004953/https://dev.java/learn/api/streams/terminal-operations/ ):
- A verbatim duplicated code block is introduced with the expectation of being distinct.
After the code block:
Stream<String> strings = Stream.of("one", "two", "three", "four");
List<String> result =
strings.filter(s -> s.length() == 3)
.map(String::toUpperCase)
.toList();
IO.println("result = " + result);
is presented,
it is said "Starting with Java SE 16, you have a second, even simpler, pattern."
followed by a code block with:
Stream<String> strings = Stream.of("one", "two", "three", "four");
List<String> result =
strings.filter(s -> s.length() == 3)
.map(String::toUpperCase)
.toList();
IO.println("result = " + result);
Which is identical, and thus cannot be "even simpler", suggesting this was repeated in error, see screenshot below:
Maybe the first block was supposed to use ".collect(Collectors.toList())" and the 2nd block ".toList()" (which is newer and simpler)?
However, the article also says the first pattern produces a modifiable list in contrast to the 2nd, but in fact .collect(Collectors.toList()), while not guaranteed to produce an unmodifiable list (unlike .toList),
has no guarantee on modifiability at all, with the documentation stating "there are no guarantees on the type, mutability, serializability, or thread-safety of the List returned; if more control over the returned List is required, use toCollection(Supplier)." (https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/stream/Collectors.html#toList() ).
So the sentence "If what you need is a modifiable list, you should stick to the first collector pattern" must be referring to something else, like .forEach(someList::add) for a manually created mutable list, someList, or should refer to Collectors.toCollection .
-
In the next section, when introducing the ".collect(Collectors.toList())" approach, the text states "You already used this pattern in a previous example", when no previous example in this article used this approach. (This also suggests that in the duplicated block above, maybe one of the blocks was intended to be using ".collect(Collectors.toList())" instead of ".toList()"? I think .toList() came in SE 16, so maybe that was supposed to be the second example and ".collect(Collectors.toList())" the first?)
-
Not a mistake, but repetition worth reviewing for possible consolidation:
"Starting with Java SE 16, there is a better way to collect your data in an immutable list, which can be more efficient on some cases. [Same code block as presented 2x above, showing Stream.toList() again]"
"This optimization has been implemented in the Stream.toList() method, which has been added to Java SE 16. If what you need is an immutable list, then you should be using this pattern." -
Re: "The supplier you used to tune the initial size of you instance of ArrayList can also be used to build any implementation of Collection, including implementations that are not part of the JDK."
In "used to tune the initial size of you instance", "you instance" should be "your instance". -
Re: "We already covered the max() and min() methods from the specialized streams of numbers: IntStream, LongStream and DoubleStream. You know that these operations do not have an identity element, so you should not be surprised to discover that there are all returning optional objects."
"there are all returning optional objects" should be "they are all returning optional objects" -
In "You may have noticed an important difference between the different terminal operation that we have covered here.", "operation" should be plural.
In the latest version of the "Creating Streams" article, https://dev.java/learn/api/streams/creating/ (as archived at https://web.archive.org/web/20260224131949/https://dev.java/learn/api/streams/creating/ ):
-
In the sentence "The random numbers depends on that seed", "depends" should be "depend".
-
Potentially confusing:
random.ints()described with a range which might not be recognized as matching the code
(endpoints excluded range; English typically uses endpoints inclusive; and the APIs, including Random.ints(), half-open / half-closed intervals, specifically right-open aka start-inclusive-end-exclusive)
Specifically, it is written "Here is a first pattern of code that generates 10 random integers between 0 and 5."
when the associated code snippet uses
random.ints(10, 1, 5)
.boxed()
.toList();
which would return random integers between 1 (inclusive) and 5 (exclusive) (the right-open interval [1, 5)), which is between 0 and 5 only if both endpoints are treated as exclusive (open integer interval (0, 5)) (the text does not specify that both endpoints are excluded).
Endpoints excluded integer intervals/ranges are unusual in both plain English (typically inclusive) and programming (typically half-open / half-closed).
E.g. the Java language specification v25 in English gives numeric ranges typically inclusive, like "an integer between [Emin] and [Emax], inclusive" or "the components of the array are referenced using integer indices from 0 to n - 1, inclusive" or "the shift distance actually used is therefore always in the range 0 to 31, inclusive", etc, while the Java APIs usually use half-open / half-closed intervals (which combine well without double counting), e.g. as in the API used here Random.ints() but also String.substring(), Time APIs like Duration.between, or many other places.
(Many applications use half-open intervals (typically right-open inclusive-exclusive) as any interval can be subdivided easily into half-open intervals without overlap or double counting; intervals excluding both endpoints do not combine well and are usually not used; that is e.g. the right-open interval [1, 3) can be combined with [3, 5) to intuitively get the new half-open interval spanning both, [1, 5). Whereas combining open intervals (both endpoints excluded) with the same endpoints does not even result in an interval, e.g. (1,3) combined with (3, 5) gives the disconnected integers 2 and 4 ({2, 4})).
-
"Being able to process these lines with the Stream API gives you a more readable and more maintainable code."
"gives you a more readable and more maintainable code" should be "gives you more readable and maintainable code" -
"To run it, you need to copy it, paste it in your IDE, and adjust de path to fit your local installation."
"adjust de path" should be "adjust the path" -
"Note that you cannot run this code in your brower." "brower" should be "browser".
In the latest version of an article "Reducing a Stream", https://dev.java/learn/api/streams/reducing/ (archived at https://web.archive.org/web/20260224224658/https://dev.java/learn/api/streams/reducing/ )
-
In the sentence "There are two caveats you need to understand though. Let us the first one here and the second one in the next section. ",
"Let us the first one here" is missing a word after "us". Maybe it was intended to read "Let us discuss the first one here" or something similar. -
Re: "A way to check for that property can be just to run your binary operator on random data and verify if you always get the same result. If you do not, then you know your binary operator is not associative. If you do, then, unfortunately, you cannot conclude reliably." Not a mistake but the last sentence seems unclear. It might be clearer if the last sentence were replaced with something like "If you do, then the operator might be associative but it still may not be, as such a result is inconclusive."
-
Re: "Let us an example with a reduction that does not have an identity element."
"Let us an" should be "Let us do an". -
Re: "The combiner combines two integers: the partial sums of the lengths of the strings processed so far. So the identity element you need to provide is the identity element: O."
"O" should be the number "0". -
In the sentence: "This way of writing thing clearly shows the fusion of the mapping, modeled by the mapper and the reduction, modeled by the binary operator":
"thing" should be "things", and I think there should be a comma after "mapper".
In the latest version of the article "Adding Intermediate Operations on a Stream", https://dev.java/learn/api/streams/intermediate-operation/ (archived at https://web.archive.org/web/20260224062952/https://dev.java/learn/api/streams/intermediate-operation/ ),
-
In the sentence, "This mapToInt() method takes a ToIntFuction as an argument." , "ToIntFuction" should be "ToIntFunction"
-
Under "Filtering a Stream",
"This method is available on streams of objects and stream of primitive types." , it should read "and streams of primitive types" with a plural streams for both types of streams.
In the next example's code block it is written:
Country uk = new Country("United Kindgom", List.of(london, manchester));
with a typo in "United Kindgom".
- Re: "The reason why it is better to use the flatMap() way is that concat() creates intermediates streams during the concatenation." This should use "intermediate" instead of "intermediates".
Thanks so much for all this content!
(If these typo/error reports continue to be desired, it is fine to leave this issue open even after fixing what is reported above so I can add any additional items found, as I am still working through the Streams articles.)