Java8 方法引用用作函数对象以组合函数
Java8 method reference used as Function object to combine functions
在 Java8 中有没有一种方法可以将方法引用用作 Function
对象来使用其方法,例如:
Stream.of("ciao", "hola", "hello")
.map(String::length.andThen(n -> n * 2))
此问题与Stream
无关,仅作为示例,希望得到有关方法参考的答案
你可以这样写:
Stream.of("ciao", "hola", "hello").map(String::length).map(n -> n * 2);
您可以将其保存到变量中:
Function<String, Integer> toLength = String::length;
Stream.of("ciao", "hola", "hello")
.map(toLength.andThen(n -> n * 2));
或者您可以使用强制转换,但它的可读性较差,IMO:
Stream.of("ciao", "hola", "hello")
.map(((Function<String, Integer>) String::length).andThen(n -> n * 2));
您应该能够通过使用强制转换实现您想要的内联:
Stream.of("ciao", "hola", "hello")
.map(((Function<String, Integer>) String::length).andThen(n -> n * 2))
编译器只有 'type hints',所以它们实际上 'cast' 对象并且没有实际转换的开销。
或者,您可以使用局部变量提高可读性:
Function<String, Integer> fun = String::length
Stream.of("ciao", "hola", "hello")
.map(fun.andThen(n -> n * 2));
第三种可能更简洁的方法是使用实用方法:
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));
请注意,这还没有经过测试,因此我不知道在这种情况下类型推断是否正确。
您可以使用强制转换
Stream.of("ciao", "hola", "hello")
.map(((Function<String, Integer>) String::length)
.andThen(n -> n * 2))
.forEach(System.out::println);
打印
8
8
10
您可以编写一个静态方法来执行此操作:
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);
}
}
然后您可以将其放入实用程序 class 并静态导入。
或者,创建一个更简单的静态方法,只是 returns它所提供的函数,以便编译器知道你在做什么:
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;
}
}
您也可以使用
Function.identity().andThen(String::length).andThen(n -> n * 2)
问题是,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; }
中使用了这个技巧
static <T> AsyncIterator<T> by(AsyncIterator<T> asyncIterator)
Syntax sugar to create an AsyncIterator from a lambda expression or a method reference.
This method simply returns the argument asyncIterator
, which seems a little odd. Explanation:
Since AsyncIterator is a functional interface, an instance can be created by a lambda expression or a method reference, in 3 contexts:
// Assignment Context
AsyncIterator<ByteBuffer> asyncIter = source::read;
asyncIter.forEach(...);
// Casting Context
((AsyncIterator<ByteBuffer>)source::read)
.forEach(...);
// Invocation Context
AsyncIterator.by(source::read)
.forEach(...);
The 3rd option looks better than the other two, and that's the purpose of this method.
我们可以使用reduce
函数将多个函数合二为一
public static void main(String[] args) {
List<Function<String, String>> normalizers = Arrays.asList(
str -> {
System.out.println(str);
return str;
},
String::toLowerCase,
str -> {
System.out.println(str);
return str;
},
String::trim,
str -> {
System.out.println(str);
return str;
});
String input = " Hello World ";
normalizers.stream()
.reduce(Function.identity(), (a, b) -> a.andThen(b))
.apply(input);
}
输出:
Hello World
hello world
hello world
在 Java8 中有没有一种方法可以将方法引用用作 Function
对象来使用其方法,例如:
Stream.of("ciao", "hola", "hello")
.map(String::length.andThen(n -> n * 2))
此问题与Stream
无关,仅作为示例,希望得到有关方法参考的答案
你可以这样写:
Stream.of("ciao", "hola", "hello").map(String::length).map(n -> n * 2);
您可以将其保存到变量中:
Function<String, Integer> toLength = String::length;
Stream.of("ciao", "hola", "hello")
.map(toLength.andThen(n -> n * 2));
或者您可以使用强制转换,但它的可读性较差,IMO:
Stream.of("ciao", "hola", "hello")
.map(((Function<String, Integer>) String::length).andThen(n -> n * 2));
您应该能够通过使用强制转换实现您想要的内联:
Stream.of("ciao", "hola", "hello")
.map(((Function<String, Integer>) String::length).andThen(n -> n * 2))
编译器只有 'type hints',所以它们实际上 'cast' 对象并且没有实际转换的开销。
或者,您可以使用局部变量提高可读性:
Function<String, Integer> fun = String::length
Stream.of("ciao", "hola", "hello")
.map(fun.andThen(n -> n * 2));
第三种可能更简洁的方法是使用实用方法:
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));
请注意,这还没有经过测试,因此我不知道在这种情况下类型推断是否正确。
您可以使用强制转换
Stream.of("ciao", "hola", "hello")
.map(((Function<String, Integer>) String::length)
.andThen(n -> n * 2))
.forEach(System.out::println);
打印
8
8
10
您可以编写一个静态方法来执行此操作:
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);
}
}
然后您可以将其放入实用程序 class 并静态导入。
或者,创建一个更简单的静态方法,只是 returns它所提供的函数,以便编译器知道你在做什么:
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;
}
}
您也可以使用
Function.identity().andThen(String::length).andThen(n -> n * 2)
问题是,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; }
中使用了这个技巧
static <T> AsyncIterator<T> by(AsyncIterator<T> asyncIterator)
Syntax sugar to create an AsyncIterator from a lambda expression or a method reference.
This method simply returns the argument
asyncIterator
, which seems a little odd. Explanation:Since AsyncIterator is a functional interface, an instance can be created by a lambda expression or a method reference, in 3 contexts:
// Assignment Context
AsyncIterator<ByteBuffer> asyncIter = source::read;
asyncIter.forEach(...);
// Casting Context
((AsyncIterator<ByteBuffer>)source::read)
.forEach(...);
// Invocation Context
AsyncIterator.by(source::read)
.forEach(...);
The 3rd option looks better than the other two, and that's the purpose of this method.
我们可以使用reduce
函数将多个函数合二为一
public static void main(String[] args) {
List<Function<String, String>> normalizers = Arrays.asList(
str -> {
System.out.println(str);
return str;
},
String::toLowerCase,
str -> {
System.out.println(str);
return str;
},
String::trim,
str -> {
System.out.println(str);
return str;
});
String input = " Hello World ";
normalizers.stream()
.reduce(Function.identity(), (a, b) -> a.andThen(b))
.apply(input);
}
输出:
Hello World
hello world
hello world