Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 nested loops to stream

Tags:

Trying to get my head round the Java 8 streams syntax with a simple example. Had a look at the other similar questions on this topic, but could not find any solutions that would match my example and would work for me. Basically I am trying to refactor the following snippet with two nested loops to use the new stream API:

List<Car> filteredCars = new ArrayList<>();  for (Car car : cars) {     for (Wheel wheel : wheels) {         if (car.getColor() == wheel.getColor() &&                 wheel.isWorking() == true ) {             filteredCars.add(car);             break;         }     } }  return filteredCars; 

Managed to come up with this which returns void:

return cars.stream().forEach(     car -> wheels.stream()         .filter(wheel -> wheel.getColor() == car.getColor() &&                     wheel.isWorking() == true)         .collect(Collectors.toList())); 

What is wrong with the stream syntax above and what am I missing?

like image 260
anton4o Avatar asked Mar 07 '16 12:03

anton4o


People also ask

Does Java 8 support streams?

Java 8 offers the possibility to create streams out of three primitive types: int, long and double. As Stream<T> is a generic interface, and there is no way to use primitives as a type parameter with generics, three new special interfaces were created: IntStream, LongStream, DoubleStream.

Is Java 8 stream faster than for loop?

The short version basically is, if you have a small list; for loops perform better, if you have a huge list; a parallel stream will perform better. And since parallel streams have quite a bit of overhead, it is not advised to use these unless you are sure it is worth the overhead.

Which is better stream or for loop?

If you have a small list, loops perform better. If you have a huge list, a parallel stream will perform better. Purely thinking in terms of performance, you shouldn't use a for-each loop with an ArrayList, as it creates an extra Iterator instance that you don't need (for LinkedList it's a different matter).

Can we use nested for-each loop in Java?

Java, like most other programming languages, supports nested loops. This means just a loop within a loop.


2 Answers

You can't perform two terminal operations - forEach and collect on the same Stream.

instead, you need to filter the cars list by checking for each car if it has a matching working wheel :

List<Car> filteredCars =     cars.stream()         .filter (             car -> wheels.stream()                          .anyMatch(wheel -> wheel.getColor() == car.getColor() &&                                                   wheel.isWorking()))         .collect(Collectors.toList()); 
like image 94
Eran Avatar answered Nov 02 '22 05:11

Eran


The problem is, you're creating the List(s) inside the forEach and forEach returns void. This would be the equivalent of the following for loop:

for (Car car : cars) {     List<Car> filteredCars = new ArrayList<>();     for (Wheel wheel : wheels) {          if (car.getColor() == wheel.getColor() &&                 wheel.isWorking() == true ) {              filteredCars.add(car);             break;         }     } }  return filteredCars; // whoops cannot be accessed (scope) !!! 

You could use filter on the cars stream and collect the use collect on the filtered stream to achieve the desired results:

Predicate<Car> carCheck = car -> wheels.stream().anyMatch(wheel -> car.getColor() == wheel.getColor() && wheel.isWorking());  List<Car> filteredCars = cars.stream().filter(carCheck).collect(Collectors.toList()); 
like image 35
fabian Avatar answered Nov 02 '22 06:11

fabian