Java8方法引用用作Function对象来组合函数

ras*_*cio 34 java lambda java-8 method-reference

Java8中是否有一种方法可以使用方法引用作为Function对象来使用其方法,例如:

Stream.of("ciao", "hola", "hello")
    .map(String::length.andThen(n -> n * 2))
Run Code Online (Sandbox Code Playgroud)

这个问题与之无关Stream,它只是作为例子使用,我想对方法参考有答案

Jon*_*eet 31

您可以编写一个静态方法来执行此操作:

import java.util.function.*;

class Test {
    public static void main(String[] args) {
        Function<String, Integer> function = combine(String::length, n -> n * 2);
        System.out.println(function.apply("foo"));
    }

    public static <T1, T2, T3> Function<T1, T3> combine(
        Function<T1, T2> first,
        Function<T2, T3> second) {
        return first.andThen(second);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以将其放在实用程序类中并静态导入它.

另外,创造出一个简单的静态方法只是返回它给出的函数,编译器的缘故知道你在做什么:

import java.util.function.*;

class Test {
    public static void main(String[] args) {
        Function<String, Integer> function = asFunction(String::length).andThen(n -> n * 2);
        System.out.println(function.apply("foo"));
    }

    public static <T1, T2> Function<T1, T2> asFunction(Function<T1, T2> function) {
        return function;     
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 第二个+1,如果这真的只是为了避免演员(我建议只是`fn(Stream :: length)`) (3认同)

JB *_*zet 22

您可以将其保存到变量中:

Function<String, Integer> toLength = String::length;
Stream.of("ciao", "hola", "hello")
      .map(toLength.andThen(n -> n * 2));
Run Code Online (Sandbox Code Playgroud)

或者你可以使用演员,但它的可读性较差,IMO:

Stream.of("ciao", "hola", "hello")
      .map(((Function<String, Integer>) String::length).andThen(n -> n * 2));
Run Code Online (Sandbox Code Playgroud)


Cla*_*oft 11

您应该能够通过使用强制转换来实现您想要的内联:

Stream.of("ciao", "hola", "hello")
      .map(((Function<String, Integer>) String::length).andThen(n -> n * 2))
Run Code Online (Sandbox Code Playgroud)

编译器只有'类型提示',因此它们实际上并不"转换"对象,也没有实际转换的开销.


或者,您可以使用局部变量来提高可读性:

Function<String, Integer> fun = String::length

Stream.of("ciao", "hola", "hello")
      .map(fun.andThen(n -> n * 2));
Run Code Online (Sandbox Code Playgroud)

可能更简洁的第三种方法是使用实​​用方法:

public static <T, X, U> Function<T, U> chain(Function<T, X> fun1, Function<X, U> fun2)
{
    return fun1.andThen(fun2);
}

Stream.of("ciao", "hola", "hello")
      .map(chain(String::length, n -> n * 2));
Run Code Online (Sandbox Code Playgroud)

请注意,这未经过测试,因此我不知道在这种情况下类型推断是否正常工作.


Zho*_*gYu 7

你也可以使用

Function.identity().andThen(String::length).andThen(n -> n * 2)
Run Code Online (Sandbox Code Playgroud)

问题是,String::length不一定是Function; 它可以符合许多功能界面.它必须在提供目标类型的上下文中使用,并且上下文可以是 - 赋值,方法调用,转换.

如果Function只是为了目标类型而提供静态方法,我们就可以做到

    Function.by(String::length).andThen(n->n*2)

static <T, R> Function<T, R> by(Function<T, R> f){ return f; }
Run Code Online (Sandbox Code Playgroud)

例如,我在功能界面中使用此技术

static <T> AsyncIterator<T> by(AsyncIterator<T> asyncIterator)
Run Code Online (Sandbox Code Playgroud)

语法sugar从lambda表达式或方法引用创建AsyncIterator.

这个方法只返回参数asyncIterator,这似乎有点奇怪.说明:

由于AsyncIterator是一个功能接口,因此可以在3个上下文中通过lambda表达式或方法引用创建实例:

 // Assignment Context
 AsyncIterator<ByteBuffer> asyncIter = source::read;
 asyncIter.forEach(...);

 // Casting Context
 ((AsyncIterator<ByteBuffer>)source::read)
     .forEach(...);

 // Invocation Context
 AsyncIterator.by(source::read)
     .forEach(...);
Run Code Online (Sandbox Code Playgroud)

第3个选项看起来比其他两个更好,这就是这个方法的目的.


Pet*_*rey 5

你可以使用演员

Stream.of("ciao", "hola", "hello")
        .map(((Function<String, Integer>) String::length)
                .andThen(n -> n * 2))
        .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

版画

8
8
10
Run Code Online (Sandbox Code Playgroud)