5

I am quite new to Java lambdas, and I am not sure if what I want is achievable: I have a list of objects, which I'd like to filter to extract those of them that are matching a given condition, and put them in a separated list (so I can perform some operation on them, keeping the original list unmodified) I came up with this:

  List<Suggestion> only_translations = original_list.stream().
    filter(t -> t.isTranslation).
    collect(Collectors.toCollection(() -> new ArrayList<Suggestion>()));

But even if I am getting a new list object, the nodes seem to be linked to the original ones (by reference, not new objects copied from the original list), so modifying the objects in the new list is modifying also the objects in the original one.

So, I'd like to know if it's posible to achieve that (using lambdas, I know I can do it the "classical" way iterating all the elements), and in that case, how. Thanks in advance!

Holger
  • 285,553
  • 42
  • 434
  • 765
motagirl2
  • 589
  • 1
  • 10
  • 21
  • `collect()` is for mutable reduction. – Jude Niroshan May 24 '17 at 08:22
  • so... what should I use instead? – motagirl2 May 24 '17 at 08:23
  • 1
    @JudeNiroshan - Depends on what argument you give it. `collect(Collectors.toList())`, for example. – Oliver Charlesworth May 24 '17 at 08:23
  • 5
    This isn't really an issue around lambdas, it's around creating copies of your `Suggestion` instances. It depends on whether you have a mechanism to copy them. In other words, you first need to figure out how you'd achieve this the "classical" way! – Oliver Charlesworth May 24 '17 at 08:24
  • @OliverCharlesworth Sure, I have copy constructor for that class... But I have no idea on where I should put them into the code I posted (maybe it's not a good approach) – motagirl2 May 24 '17 at 08:27
  • 2
    FYI, `() -> new ArrayList()` is equivalent to `ArrayList::new`. But if you don't need to modify the result list, just use the `toList()` collector. – shmosel May 24 '17 at 08:27

2 Answers2

5

Assuming your Suggestion somewhat possess a public Suggestion copy(); method (like implementing a Copyable<Suggestion> interface), you could do :

List<Suggestion> only_translations = original_list.stream()
    .filter(t -> t.isTranslation)
    .map(t -> t.copy())       // or .map(Suggestion::copy)
    .collect(Collectors.toList()));

EDIT : with the copy constructor :

List<Suggestion> only_translations = original_list.stream()
    .filter(t -> t.isTranslation)
    .map(t -> new Suggestion(t))  // or .map(Suggestion::new)
    .collect(Collectors.toList()));
djm.im
  • 3,295
  • 4
  • 30
  • 45
Jeremy Grand
  • 2,300
  • 12
  • 18
  • 3
    Which can be shortened to `Suggestion::copy` or `Suggestion::new` respectively. – Oliver Charlesworth May 24 '17 at 08:30
  • @OliverCharlesworth I completely agree on the copy part. However, I kind of dislike the `Suggestion::new` shortening syntax as, even if the compiler (or any attentive reader) understands that it's an `UnaryOperator`, it can easily be confused with other constructors. The long version is more readable IMO. – Jeremy Grand May 24 '17 at 08:59
2

Since you say you have a copy constructor, just add this before the collect operation to get a list of copied objects:

.map(Suggestion::new)
shmosel
  • 49,289
  • 6
  • 73
  • 138