Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a for-loop to find the first occurrence to Java streams?

I have the following code that is functionally working

for (UniversityClass class : allClasses)
    {
        Period<Date> classDate = class.getClassDates();
        if (classDate.start().before(classEndDate)
                && classDate.end().after(classBeginDate))
        {
            classBooked = true;
            break;
        }
    }

I have tried this:

allClasses.stream().filter(class -> {
            Period<Date> classDate = class.getClassDates();
            if (classDate.start().before(classEndDate)
                && classDate.end().after(classBeginDate))

            return true;
        }).findFirst().ifPresent($ -> {
            classBooked = true;
        });

But this throws to add a return statement. Also, the classBooked variable needs to be declared final, but that cannot be done. What is the mistake being done?

Also, once true, I need to break from it. that is why I thought of adding findFirst().ifPresent()

like image 873
evan Avatar asked May 13 '20 10:05

evan


People also ask

How to get first element from list in Java 8?

In Java 8, you can use the Stream. findFirst() method to get the first element of Stream in Java. This is a terminal operation and is often used after applying several intermediate operations e.g. filter, mapping, flattening, etc.

Are Java streams more efficient than for loops?

Remember that loops use an imperative style and Streams a declarative style, so Streams are likely to be much easier to maintain. If you have a small list, loops perform better. If you have a huge list, a parallel stream will perform better.

Which is faster foreach or stream in Java?

parallel foreach() Works on multithreading concept: The only difference between stream(). forEach() and parallel foreach() is the multithreading feature given in the parallel forEach(). This is way faster that foreach() and stream.


2 Answers

You can use anyMatch in place of filter, findFirst:

classBooked = allClasses.stream()
                        .anyMatch(c -> {
                            Period<Date> classDate = c.getClassDates();
                            return (classDate.start().before(classEndDate) && classDate.end().after(classBeginDate));
                        });

You may also use map to be slightly more readable:

classBooked = allClasses.stream()
                        .map(UniversityClass::getClassDates)
                        .anyMatch(d -> d.start().before(classEndDate) && d.end().after(classBeginDate));
like image 92
Jean-Baptiste Yunès Avatar answered Sep 18 '22 15:09

Jean-Baptiste Yunès


To fix the specific problems in your code, your lambda always needs to return a value, and the ifPresent needs to be changed to isPresent:

final boolean classBooked = allClasses.stream()
        .filter(c -> {
            final Period<Date> classDate = c.getClassDates();
            return classDate.start().before(classEndDate)
                && classDate.end().after(classBeginDate)
        })
        .findFirst().isPresent();

However, anyMatch, as shown in the other answers, is a better solution.

like image 41
Konrad Rudolph Avatar answered Sep 20 '22 15:09

Konrad Rudolph