1

I'm trying to perform the following stream operations on an ArrayList named parts:

parts
    .stream()
    .map(t -> t.toLowerCase())
    .distinct()
    .sorted()
    .collect(Collectors.toList());

where parts contains Strings like this:

Adventures
in
Disneyland
Two
blondes
were
going
to
Disneyland
....

Except upon looking at the debugger, parts isn't changed at all. Not sure if I'm missing some step of the process?

Ivar
  • 6,138
  • 12
  • 49
  • 61
J. Doe
  • 85
  • 1
  • 6
  • Linked: https://stackoverflow.com/questions/54896120/take-string-input-parse-each-word-to-all-lowercase-and-print-each-word-on-a-lin – MC Emperor Feb 28 '19 at 00:02

4 Answers4

7

upon looking at the debugger, "parts" isn't changed at all

Correct. Streams don't modify the elements of the collection that was used to create the stream. The stream is ultimately returning a new List that contains the mapped items. Just create a variable and assign the return value of your stream operations to it:

List<String> modifiedList = parts.stream()
    .map(t -> t.toLowerCase())
    .distinct()
    .sorted()
    .collect(Collectors.toList());
Jordan
  • 2,273
  • 9
  • 16
  • Why am I not allowed to store this new list in an ArrayList? It gives me a red line under the .toList method – J. Doe Feb 28 '19 at 00:00
  • 1
    @J.Doe because you can't be sure that the returned `List` is (and will always be) an `ArrayList`. It returns a `List`, which means that the actual type may be any subclass of that interface – Andrew Tobilko Feb 28 '19 at 00:02
  • @J.Doe, there's a common best-practice when writing code involving interfaces: "[program to the interface](https://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface)". In this example, all we know is that we get back a `List`, and it doesn't *matter* if it's an `ArrayList` or a `LinkedList`, or any other custom list class. All that matters is that what comes back conforms to the `List` interface. So if, years from now, some new, more-optimal list implementation is popularized, the stream code can return a fancy new `AwesomeList`, and your code will still work. – Jordan Feb 28 '19 at 00:43
4

You are not storing the collected list anywhere. Streams don't change the collection in-place.

You should do:

parts = parts.stream().....;

Edit based on comments:

To get an ArrayList as opposed to any List, change your collector to:

.collect(Collectors.toCollection(ArrayList::new));
Kartik
  • 7,677
  • 4
  • 28
  • 50
1

A stream does not alter the source of the stream so you are observing expected behaviour.

You should capture the result of your stream processing and inspect that in your debugger, eg.

List<String> result = parts.stream()...
dave
  • 11,641
  • 5
  • 47
  • 65
1

This will create a new list and is how the map operator works. You are replacing the items in the stream with new objects and then you collect the stream into a new list.

You have to assign the result to the new list.

leurer
  • 441
  • 3
  • 10