0

How can i do instance of inside Java 8 stream

for (List<Category> parentPath : getPathsInternal(parent, controlSet)) {
  if (!(parentPath instanceof LinkedList)) {
    parentPath = new LinkedList<Category>(parentPath);
  }
  parentPath.add(category);
  result.add(parentPath);
}

I am not sure how to write such function in Java 8 stream . Any directions ?

if (!(parentPath instanceof LinkedList)) {
    parentPath = new LinkedList<Category>(parentPath);
  }
Saurabh Kumar
  • 16,353
  • 49
  • 133
  • 212
  • 2
    You know lambdas can be more than one line, right? And they can include any statements you want? – Louis Wasserman Jun 08 '16 at 21:38
  • i can do getPath...Stream().forEach(....all logic..) but i would like to see a better way which might be possible – Saurabh Kumar Jun 08 '16 at 21:40
  • 2
    In 99% of all `LinkedList` usages, it is the wrong choice. The other 1% need a complete application redesign anyway. So, why are you converting non-`LinkedList`s to `LinkedList`s and why are you doing it *conditionally*? Is “sometimes modifying the source” really what you want to achieve? – Holger Jun 09 '16 at 08:21
  • @Holger Yes, even though this isn't codereview.SE, there are several odd things about this code. 1) One might think `getPathsInternal` returns data that the caller owns and can manipulate, or it requires the caller to make copies, not one or the other based on a conditional. 2) The conditional copying is based on the data's *type*, which seems quite brittle. 3) The originals or copies are `LinkedList`, which as you say is the wrong choice 99% of the time. I agree. I'm wondering if this is an [XY problem.](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – Stuart Marks Jun 09 '16 at 23:54
  • My point here is that this example might lead one to think, "Streams can't handle cases like this." But this code is an odd case to begin with, and even the conventional (non-Streams) code makes one squint a bit and think, "Why is it doing that?" – Stuart Marks Jun 09 '16 at 23:56

4 Answers4

3
getPathsInternal(parent, controlSet).stream()
   .map(parentPath -> 
       (parentPath instanceof LinkedList) 
           ? parentPath : new LinkedList<>(parentPath))
   .peek(parentPath -> parentPath.add(category))
   .collect(toList()); // or whatever result is
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • I think using `peek()` to produce a side-effect is generally frowned upon. Though it's more of a problem with OP's question than your answer. – shmosel Jun 08 '16 at 21:57
  • 1
    The whole _point_ of `peek` is side effects. It literally can't be used for anything else. (But yes, trying to do side effects at all is problematic.) – Louis Wasserman Jun 08 '16 at 22:01
  • I mean other than for debugging purposes. There's a reason it was named "peek", not "do" or "consume". – shmosel Jun 08 '16 at 22:03
  • 1
    @shmosel: if you are referring to [this post](http://stackoverflow.com/a/33636377/2711488), everything said there about `peek`, applies to “`map` with side effect” as well. The difference between `map` and `peek` is, that there is a use case for “`map` without side-effect”. Besides that, it’s not the `peek` vs. `map` aspect that makes the whole thing questionable. The code is either, modifying the source element or just a copy, based on a condition as suspicious as `source instanceof LinkedList`. Why does nobody stumble about *that*? – Holger Jun 09 '16 at 09:04
2

I think this code is the same:

getPathsInternal(parent, controlSet).stream()
    .map(parentPath -> (parentPath instanceof LinkedList) ? parentPath : new LinkedList<>(parentPath))
    .peek(parentPath -> parentPath.add(category))
    .collect(Collectors.toList())
Andrew Rueckert
  • 4,858
  • 1
  • 33
  • 44
1

There are a bunch of ways to do this, but probably the most readable is to split into two functional idioms.

List<Category> result = getPathsInternal(parent, controlSet).stream()
    .map((parentPath) -> parentPath instanceof LinkedList ? parentPath : new LinkedList<>())
    .collect(Collectors.toList())
result.stream()
    .forEach((parentPath) -> parentPath.add(category));
Dean Povey
  • 9,256
  • 1
  • 41
  • 52
  • If you are not planning to use stream functions with result, you could also use List::forEach instead: result.forEach(parentPath -> parentPath.add(category)); – srborlongan Jun 09 '16 at 05:20
0

Adding to the discussion about peek originating from Louis' answer:

As the

parentPath.add(category)

is rather a transformation of the streamed object itself, I see this as a map operation, even if you have to use block-syntax in this case:

getPathsInternal(parent, controlSet).stream()
   .map(parentPath -> 
       (parentPath instanceof LinkedList) 
          ? parentPath : new LinkedList<>(parentPath))
   .map(parentPath -> { parentPath.add(category); return parentPath; })
   .collect(toList());
mtj
  • 3,381
  • 19
  • 30