0

Use Case

I'm using an 3rd party library where there are two very similar classes that don't implement an interface. The code currently loops through a list of items to find the first occurrence of an object using one of these classes and then converts it to a stream where it is processed. It would be nice if I could convert this code to use a stream and have it chained to the rest of my code.

Current Code

    for (Component3Choice component: components) {
        if (component instanceof OptionalComponent3Bean) {
            OptionalComponent3Bean section = (OptionalComponent3Bean) component;

            entryStream = section.getSection().getEntry().stream()
            break;
        }
        else if (component instanceof RequiredComponent3Bean) {
            RequiredComponent3Bean section = (RequiredComponent3Bean) component;

            entryStream = section.getSection().getEntry().stream();
            break;
        }
    }
    ... do something with the stream ...

Desired Code

components.stream()
  .filter(entry -> entry instanceof OptionalComponent3Bean 
                     || entry instanceof RequiredComponent3Bean)
  .findFirst()
  .map( {{ cast entry }} )
  .map( castedEntry.getSection().getEntry())
  ... continue on with my processing

Question

Is it possible cast the entry based on the previous filter in the stream?

3
  • 1
    Does Component3Choice define a method getSection() ? Commented Mar 11, 2015 at 14:00
  • 1
    Can you modify OptionalComponent3Bean & RequiredComponent3Bean to implement an interface (for instance HasSection) which would define getSection()? Commented Mar 11, 2015 at 14:03
  • Unfortunately, I don't have access to the source code for that library. :( Commented Mar 11, 2015 at 14:04

2 Answers 2

3

No, nothing can save you from bad design, which is what it seems you're fighting against.

You can force a common interface by means of a wrapper, if you need to replicate boilerplate similar to this one in many places. Otherwise, I guess the best you can do is

static private IDontKnow getStream(Component3Choice c3c) {
  if (c3c instanceof OptionalComponent3Bean) {
    return ((OptionalComponent3Bean)c3c).getStream();
  } else if (c3c instanceof RequiredComponent3Bean) {
    return ((RequiredComponent3Bean)c3c).getStream();
  } else {
    return null;
  }
}

components.stream()
  .map(x -> getStream(x))
  .filter(x -> x!=null)
  .findFirst()
  .map(x -> x.getEntry().stream());
  ... continue on with yout processing
Sign up to request clarification or add additional context in comments.

2 Comments

Looks good as this isolates the logic. if and when the library gets updated and hopefully fixed, it'll be easier to transition.
Chiming in re another case. Wanting to stream members of a Set to .joining() but that looks for CharSequence instances like String, not Longs, etc.. This is what I did: setOfLongObjects.stream().map(it -> ""+it).collect(Collectors.joining(","))
1

Not the prettiest code, but you could do :

components.stream()
          .filter(entry -> entry instanceof OptionalComponent3Bean 
                     || entry instanceof RequiredComponent3Bean)
          .map(entry -> {
                 if ((entry instanceof OptionalComponent3Bean)
                   return ((OptionalComponent3Bean) entry).getSection().getEntry().stream(); 
                 else
                   return ((RequiredComponent3Bean) entry).getSection().getEntry().stream();
                        })
          .findFirst();

This would return an Optional<Stream<Something>>.

Note that findFirst must be the last operation, since it's terminal.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.