Is there a way to apply a function with multiple parameters to a stream?

Viewed 78

I have the following generic method for transforming a page object into a Slice:

public static <T,R> Slice<R> toSlice(final Page<T> source, Function<T,R> transform) {
  return Slice.<R>builder()
      .totalPages(BigInteger.valueOf(source.getTotalPages()))
      .pageData(source.stream()
          .map(transform)
          .collect(Collectors.toList()))
      .build();
}

I would then use this as follows:

return SliceFactory.toSlice(
            someDao.findAll(
                    predicate,
                    PageRequest.of(page, PAGE_SIZE,
                        Sort.by(Sort.Direction.DESC, DEFAULT_SORTING_PROPERTY))),
            dtoFactory::toSomeDto);

However, I would like to now pass an additional argument to dtoFactory.toSomeDto(). I'm not sure how can I turn this into a generic method, similar to the existing toSlice() method?

3 Answers

Just call it with param -> dtoFactory.toSomeDto(param, additionalParam) but in that case you have to ensure that additionalParam is effectively immutable.

You can only do it as the following below: Your other (variable) which you require to affect the result of map, needs to be an external variable, and not a Function<> input:

public static void main(String[] args){

    String anotherVariableThatAlters = "HelloWorld";

    Function<String,String> defaultFunction = (stringFromStream) -> {
        return stringFromStream + "_" + anotherVariableThatAlters;
    };

    System.out.println(Stream.of("1", "2", "3").map(defaultFunction).collect(Collectors.toList()));

}

[1_HelloWorld, 2_HelloWorld, 3_HelloWorld]

You can use BiFunction to do this.

Assuming that dtoFactory is an instance of DtoFactory, then the code

dtoFactory::toSomeDto

is really referring to a class method

public class DtoFactory {
    public R toSomeDto( T t ) { .... } // Function<T,R>
}

What the :: syntax is doing, is turning your normal method into a Function. A Function takes one argument and returns one. A BiFunction takes two arguments.

To illustrate, this is valid code which compiles, and which prints

ab
[x1, x2, x3]
A123

import java.util.function.BiFunction;

public class Test {
    public static void main( String[] args ) {
        Test test = new Test();
        BiFunction<String,String,String> b = test::bifunc;
        System.out.println( b.apply( "a", "b" ) );
        System.out.println( Stream.of( 1, 2, 3 )
            .map( (i) -> test.bifunc( "x", i.toString() ) )
            .collect( Collectors.toList() ) );
        System.out.println( Stream.of( 1, 2, 3 )
            .map( (i) -> i.toString() )
            .reduce( "A", test::bifunc ) );
    }

    public String bifunc( String one, String two ) {
        return one + two;
    }
}
Related