10

Say we have a Customer class:

public class Customer {
    private Car[] cars;
    // getter, setter, constructor
}

and collection of customers which we need to map on cars.

Currently I'm doing it somehow like this:

Collection<Customer> customers = ...
customers.stream().flatMap(
        customer -> Arrays.stream(customer.getCars())
)...

It works well, but the code doesn't look elegant. I'd really like to replace it with code that uses method references which usually looks more readable and more compact. But using a field of array type makes it hard.

Question: is there any way of enhancing the flatMap call so it will be more readable/compact/clear?

Sasha Shpota
  • 9,436
  • 14
  • 75
  • 148
  • 6
    Well you can do `customers.stream().map(Customer::getCars).flatMap(Arrays::stream)` but IMO your solution is readable and elegant. – Alexis C. Dec 21 '17 at 10:41

3 Answers3

14

You can split the flatMap call into two calls - map and flatMap - each receiving a method reference:

Collection<Customer> customers = ...
customers.stream()
         .map(Customer::getCars)
         .flatMap(Arrays::stream)...
Eran
  • 387,369
  • 54
  • 702
  • 768
7

Just add a method to Customer returning a stream of Cars. Using typical naming conventions, it would look like

public Stream<Car> cars() {
    return Arrays.stream(cars);
}

Then, you can use it like

customers.stream().flatMap(Customer::cars)

Generally, properties of a mutable type like an array should be handled with care. The only way to prevent modification through a getter, is to make a copy. So providing an alternative method returning a read-only type like a Stream, which does not need copying, has additional uses besides making flatMap neat.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • 5
    This approach has the extra advantage that, if the array of cars is `null`, you can also handle this case in the method: `return cars == null ? Stream.empty() : Arrays.stream(cars);` – fps Dec 21 '17 at 16:17
3

You could use :

 .map(Customer::getCars)
 .flatMap(Arrays::stream)

But I don't think this is more elegant in any way. And also having everything as methods references like this makes it less readable, for me at least. I should explain myself as why I see this less readable, because there are two stages that I need to understand now when reading this code. why map is done and why flatMap is done - might seem minor though.

Eugene
  • 117,005
  • 15
  • 201
  • 306