You can often convert your iterative solution directly to a stream by using .collect:
Map<Integer, CarShop> result = someListOfCars.stream().collect(
HashMap::new,
(map, car) -> car.getCarProducts().forEach(
prod -> map.put(prod.getId(), car.getCarShop())
),
Map::putAll
);
You can make the solution more flexible at the cost of additional allocations:
Map<Integer, CarShop> result = someListOfCars.stream()
.flatMap(car -> car.getCarProducts().stream()
.map(prod -> new SimpleImmutableEntry<>(prod.getId(), car.getCarShop()))
).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b));
This will allow you to collect any way you wish. For example, you would be able to remove (a,b)->b to force an exception if there are duplicate ids instead of silently overwriting the entry.
CarCarProductandCarShopclasses looks like (car.getCarProducts()doesn't feel very intuitive to me)?