Ag863
Ag863

Reputation: 47

Why chaining is not working when passed as lambdas in predicate?

I am new in functional programming. I want to understand which concept am I missing here.

    Stream<Employee> stream1 = getEmployeeListOne().stream();
    Stream<Employee> stream2 = getEmployeeListTwo().stream();
    Predicate<Employee>predicate=x->x.getFirstName().startsWith("L");
    //Below line is compile time error
    List<Employee>list=stream1.filter((x->x.getFirstName().startsWith("L")).or(x->x.getLastName().startsWith("L"))).collect(Collectors.toList());
    //Below line works well 
    //List<Employee>list2=stream1.filter(predicate.or(x->x.getLastName().startsWith("L"))).collect(Collectors.toList());
    

It simply says lambda expression not expected here

Upvotes: 1

Views: 134

Answers (2)

Bohemian
Bohemian

Reputation: 424993

A Predicate has the or() method.
A lambda does not.

If you assign the lambda to a variable of type Predicate, you’re fulfilling the implementation of Predicate’s single unimplemented method test(), which only then has an or() method.

Upvotes: 1

silentsudo
silentsudo

Reputation: 6963

THis is how i have tried to do it, extract similar test condition in a method , make predicate return boolean of composite condition.

The chaining does work if you write

final Predicate<Employee> onlyEmpNameStarsWithL = employee -> nameStartsWithL(employee.firstName);// || nameStartsWithL(employee.lastName);

and then use full code as below:

List<Employee> allEmployeeWithLInName = employeeStream.filter(Objects::nonNull)
                .filter(onlyEmpNameStarsWithL.or(e -> nameStartsWithL(e.lastName)))
                .collect(Collectors.toList());

        allEmployeeWithLInName.forEach(System.out::println);

Or the complete other approach

final Predicate<Employee> onlyEmpNameStarsWithL = 
employee -> nameStartsWithL(employee.firstName) || nameStartsWithL(employee.lastName);

helper method

    static boolean nameStartsWithL(String name) {
        return name != null && name.startsWith("L");
    }

Full source code

package examples;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

class Employee {
    String firstName;
    String lastName;

    public Employee(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                '}';
    }
}

public class LambdaPredicate {
    static boolean nameStartsWithL(String name) {
        return name != null && name.startsWith("L");
    }

    public static void main(String[] args) {
        List<Employee> employeeList = Arrays.asList(
                new Employee("A", "P"),
                new Employee("B", "L"),
                null,
                new Employee("C", "Q"),
                new Employee("L", "I"),
                new Employee("L", "L")
        );

        final Predicate<Employee> onlyEmpNameStarsWithL = employee -> nameStartsWithL(employee.firstName) || nameStartsWithL(employee.lastName);
        Stream<Employee> employeeStream = employeeList.stream();

        List<Employee> allEmployeeWithLInName = employeeStream.filter(Objects::nonNull)
                .filter(onlyEmpNameStarsWithL)
                .collect(Collectors.toList());

        allEmployeeWithLInName.forEach(System.out::println);
    }
}

Output

Employee{firstName='B', lastName='L'}
Employee{firstName='L', lastName='I'}
Employee{firstName='L', lastName='L'}

Upvotes: 0

Related Questions