Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java collect with lambda expression example

I was trying to convert this

 String r = "";
 for ( Persona p : list ) {
    r += p.lastName;
 }

To stream().filter.collect() form, but I want to know how to write the collect with a lambda expression (not method references). I couldn't find a good example.

This is what I have

class B {
    public static void main( String ... args ) {
        List<Person> p = Arrays.asList(
                new Person("John", "Wilson"),
                new Person("Scott", "Anderson"),
                new Person("Bruce", "Kent"));

        String r;
        String s = p.stream()
            .filter( p -> p.lastName.equals("kent"))
            .collect((r, p) -> r += p.lastName);/// ?????
    }
}
class Person {
    String name;
    String lastName;
    public Person( String name, String lastName ) {
        this.name = name;
        this.lastName = lastName;
    }
}

All the examples I find are using method references whereas I think there should be an easy way to write a lambda expression instead.

like image 981
OscarRyz Avatar asked Mar 12 '23 16:03

OscarRyz


2 Answers

Assuming you don't want to use any ready-made collector like Collectors.joining(), you could indeed create your own collector.

But, as the javadoc indicates, collect() expects either 3 functional interface instances as argument, or a Collector. So you can't just pass a single lambda expression to collect().

Assuming you want to use the first version, taking 3 lambda expressions, you'll note, by reading the javadoc, that the result must be a mutable object, and String is not mutable. So you should instead use a StringBuilder. For example:

StringBuilder s = 
    p.stream()
     .filter( p -> p.lastName.equals("kent"))
     .map(p -> p.lastName)
     .collect(StringBuilder::new,
              StringBuilder::append,
              StringBuilder::append);

This uses method references, but all method references can be written as lambda expressions. The above is equivalent to

StringBuilder s = 
    p.stream()
     .filter( p -> p.lastName.equals("kent"))
     .map(p -> p.lastName)
     .collect(() -> new StringBuilder(),
              (stringBuilder, string) -> stringBuilder.append(string),
              (stringBuilder1, stringBuilder2) -> stringBuilder1.append(stringBuilder2));
like image 166
JB Nizet Avatar answered Mar 20 '23 01:03

JB Nizet


You can also use the .reduce() function, it's easier to read than the collect.

    String s = p.stream()
        .filter( p -> p.lastName.equals("kent"))
        .reduce("", (acc, p) -> acc + p.lastName(), String::concat);

Version with StringBuilder:

    StringBuilder s = p.stream()
        .filter( p -> p.lastName.equals("kent"))
        .reduce(new StringBuilder(), (acc, p) -> acc.append(p.lastName()), StringBuilder::append);
like image 41
Jiri Kremser Avatar answered Mar 20 '23 01:03

Jiri Kremser