-1

Consider I have an array list of Optional objects like List<Visit> visit = {Optional[Visit], Optional[Visit], ...}. How do i get the Visit object from the Optional and just return those objects as a List?

I tried something like this:

return Stream.of(visits).filter(value -> Optional.isPresent(value))
    .map((Visit t) -> Optional.get(t))
    .collect(Collectors.toList());

and this:

return Stream.of(visits)
   .map(visit -> Optional.of(visit).get())
   .collect(Collectors.toList());

But this doesn't compile.

I am trying to use Lightweight-Stream-API as the stream library.

M. Justin
  • 14,487
  • 7
  • 91
  • 130
irobotxx
  • 5,963
  • 11
  • 62
  • 91
  • Your version is actually fine so long as you can extract it into a separage function. You can use `flatMap`, of course, but I would suggest refactoring your code to replace `List>` with `List`. – M. Prokhorov May 11 '17 at 15:15
  • 1
    Your code doesn't compile because there is no static method `Optional.isPresent(Object)`. Both `isPresent` and `get` are instance methods. It is also not clear what are you trying to do by calling `Optional.of(t).get()` - this code is almost pointless since there is a lot cleaner and readable way to throw a `NullPointerException`. – M. Prokhorov May 11 '17 at 15:22
  • @M.Prokhorov Let me try to explain properly what am trying to achieve. i call response. getVisits() from a method after an API call. and the return type is List but each Visit object within the list is wrapped with an Optional. So am basically trying to get the value from the optional and add them to a new List which just contains Visits without the optional. – irobotxx May 11 '17 at 15:30
  • @irobotxxx I was going to write a simpler answer, but what is the type of `visits`? I seemed to be confused whether it is `List` or `List>` – Jacob G. May 11 '17 at 15:33
  • @JacobG. please see my comment above. its basically List but in the list i have [Optional [Visit] ]. – irobotxx May 11 '17 at 15:36
  • Okay, I assume you didn't specify a generic type, so it's actually a `List>`. Harmlezz's answer should work perfectly fine for you. – Jacob G. May 11 '17 at 15:37
  • 2
    @irobotxxx, if it's `List`, then objects can't be "wrapped" into an optional, because then it would be `List>`. I would also insist that you should rather change code so it _doesn't_ wrap into an optional. There is no purpose in this data structure (list of optionals) apart from making developers angry and confused. – M. Prokhorov May 11 '17 at 15:56
  • @M.Prokhorov i would agree with you on that one. I must have done something wron when mapping from the api response to my domain response. Am really sorry for the confusion. – irobotxx May 11 '17 at 16:10
  • @irobotxxx, if your API responds with optionals, you should unwrap them as soon as possible. There is a handy method `ifPresent` that you can use like this: `optional.ifPresent(myList::add)`. – M. Prokhorov May 11 '17 at 16:16
  • @M.Prokhorov yeah.you are right. that was the problem. i did it a bit too late which caused the issue. – irobotxx May 12 '17 at 08:57

2 Answers2

4

You may do it this way:

return visits.stream()
             .map(visit -> visit.orElse(null))
             .filter(Objects::nonNull)
             .collect(Collectors.toList());

Assuming visits is of type List<Optional<Visit>>.

Causes Of Your Code Not Compiling

Assuming that the variable visits is of type List<Optional<Visit>> the statement you posted:

Stream.of(visits).filter(value -> Optional.isPresent(value))
                 .map((Visit t) -> Optional.get(t))
                 .collect(Collectors.toList());

has the following problems:

  1. Stream.of() takes either one element or many elements of type T and creates a Stream. You use visits as one element of type List<Optional<Visit>> and I think you intend to get a Stream of Optional<Visit> which you may achieve by using visits.stream().

  2. filter(value -> Optional.isPresent(value)) does invoke isPresent(T t) in a static way while the method isPresent(T t) doesn't exist, neither statically nor as an instance method. I think what you intend to do is: filter(value -> value.isPresent()) which is equal to filter(Optional::isPresent). The difference of the second is that Optional::isPresent does not invoke a static method but results in a method reference.

  3. map((Visit) t -> Optional.get(t)) does as well invoke a method get(T t) in a static way which doesn't exist, neither statically nor as an instance method. I think you intended to invoke map((Visit) t -> t.get()) which is equal to map(Optional::get).

Fixing those issues would result in the new statement:

visits.stream().filter(Optional::isPresent)
               .map(Optional::get)
               .collect(Collectors.toList());

The difference to my solution is only that you map after filter. As a reader to get it right you need to remember that Optional::get will always return a non-null value. If you map first and filter second you do not have to remember there are no null values because you filter them out in the second step.

Harmlezz
  • 7,972
  • 27
  • 35
  • Thanks for the response but could you please view my comments above to clarify what am trying to do – irobotxx May 11 '17 at 15:31
  • Thanks for the detailed response. Am still getting into grips with the new Java 8 API features. Am marking these as the accepted answer, Also because of the detailed explanation. – irobotxx May 12 '17 at 09:04
4

You could do it as follows:

List<Visit> visitsWithoutOptionals = visits.stream()
    .filter(Optional::isPresent)
    .map(Optional::get)
    .collect(Collectors.toList());
fps
  • 33,623
  • 8
  • 55
  • 110