0

Suppose I have this class model hierarchy:

public class A {
 private Integer id;
 private List<B> b;
}

And:

public class B {
 private Integer id;
 private List<C> c;
}

And finally:

public class C {
 private Integer id;
}

And a simple Service:

@Service
public class doSome {
  
  public void test() {
    Optional<A> a = Optional.of(a) // Suppose a is an instance with full hierarchy contains values
    /** *1 **/               // what I want to do
  }
}

Now what I want to do at the *1 position is to use lambda to extract the Optional value (if exixsts) and map the subrelation to obtain all id of the C class. I have tried something like this:

  public void test() {
    Optional<A> a = Optional.of(a);
    List<Integer> temp = a.get().getB()
                                .stream()
                                .map(x -> x.getC())
                                .flatMap(List::stream)
                                .map(y -> y.getId())
                                .collect(Collectors.toList());   // works
  }

Now I would like to put inside my lambda the a.get().getB(), I have tried several ways but with no luck.

Anyway I don't understand why I can't use two consecutive map like

 .map(x -> x.getC())
 .flatMap(List::stream)
 .map(y -> y.getId())

without using flatMap(List::stream) in the middle... the map doesn't return a new Stream of Type R (class C in this case)? Why I have to Stream it again? where am I wrong?

----------------------- UPDATE ------------------

This is just an example, It's pretty clear that the Optional here is useless but in real case could comes by a findById() JPA Query.

Holger for this reasons I would put all inside a part of code, doing something like:

public <T> T findSome(Integer id) {
  Optional<T> opt = repository.findById(id);
  return opt.map(opt -> opt).orElse(null);
}

I have read here some solution like follows:

Optional.ofNullable(MyObject.getPeople())
  .map(people -> people                                                                    
    .stream()                                                                    
    .filter(person -> person.getName().equals("test1"))
    .findFirst()
    .map(person -> person.getId()))
  .orElse(null);

And I would like to adapt at my case but without no luck.

3
  • 2
    1) it’s not clear why you create this superfluous Optional at all, then 2) it’s not clear what “I would like to put inside my lambda the a.get().getB()” is supposed to mean. Which lambda? And why do you want to put that expression inside it when you already have code that works fine? 3) See What's the difference between map() and flatMap() methods in Java 8? or in short, can you invoke getId() on a List<C>? Or do you need a construct to tell that you want to do it for every element (e.g. by streaming over it)? Commented May 25, 2021 at 11:02
  • 1
    When you invoke a method that returns an optional on purpose, i.e. because it might return an empty optional you should not perform an unconditional invocation of get on it. Commented May 25, 2021 at 11:19
  • You have to use flatMap because you have a List of Lists (every B has a List of C and you have many Bs). Commented May 25, 2021 at 13:48

1 Answer 1

1

As of and newer, you can call Optional#stream:

List<Integer> temp = a.map(A::getB)
        .stream()
        .flatMap(Collection::stream)
        .map(B::getC)
        .flatMap(Collection::stream)
        .map(C::getId)
        .collect(Collectors.toList());

If you are stuck with , you need to map to Stream (or return the empty one) and continue chaining:

List<Integer> temp = a.map(A::getB)
        .map(Collection::stream)
        .orElse(Stream.empty())
        .map(B::getC)
        .flatMap(Collection::stream)
        .map(C::getId)
        .collect(Collectors.toList());

Note: Optional<A> a = Optional.of(a) is not valid as a is already defined.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot, is what I was looking for, and Optional<A> a Optional.of(a) is a typing error (or pseudocode at most!). Thanks a lot.
You are welcome. :) Please, next time try to avoid mixing such pseudocode with a real code as it might lead others to focus on that typo rather than posting an useful answer.

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.