How to pass argument to class constructor when initialzed thru ::new in Java8

前端 未结 3 768
时光取名叫无心
时光取名叫无心 2021-01-03 00:41

I am using java 8 stream API to perform action on a list of Store objects.

Store takes a String argument and a Mapper

3条回答
  •  独厮守ぢ
    2021-01-03 01:20

    You can't use a method reference for a constructor that needs to receive a free variable, i.e. a variable from the context.

    Please refer to the Java Tutorial, section Method References to find more info about method references.

    You can use a lambda expression instead:

    Mapper mapper = new Mapper();
    
    List actions = 
        names.stream()
            .map(name -> new Store(name, mapper))
            .collect(Collectors.toList());
    

    If, for whatever reason, you insist on using a method reference, you still can, though the solution is more complex and cumbersome. In fact, it's much better from all possible points of view to use a lambda expression instead of the hack I'm introducing below. I'm writing it just to show that method references are good only if you already have a method or constructor whose signature matches the expected one.

    Suppose you declare this helper method:

    public static  Function bindSecond(
            BiFunction biFunction, 
            U free) {
        return t -> biFunction.apply(t, free);
    }
    

    Here I'm are creating and returning a 1-argument function that applies its only one argument to the given bifunction (a 2-argument function), as well as the given free variable. In other words, I'm binding the given free variable to the given bifunction as its second argument.

    In your example, Store::new is actually a bifunction that takes two arguments (name and mapper) and returns a value (the new Store instance), and you are getting that compilation error because Stream.map expects a 1-argument function that takes the element of the stream as its only one parameter.

    The bindSecond helper method actually transforms the given bifunction and free variable into a 1-argument function that matches the signature of the Stream.map method.

    You could use it as follows:

    Mapper mapper = new Mapper();
    
    List actions = 
        names.stream()
            .map(bindSecond(Store::new, mapper))
            .collect(Collectors.toList());
    

    But again, I see no point in using this over a simple lambda expression.

提交回复
热议问题