Java的预定义函数式接口
java.util.function
包是JDK 8中的一个新包,包含40多个预定义的函数式接口,这些接口使编写Lambda表达式更容易。下表给出了一些预定义函数式接口。
函数式接口 | 说明 |
---|---|
Function | 为一个函数建模,该函数接收一个参数并返回一个结果。结果类型可不同于任何参数类型 |
BiFunction | 为一个函数建模,该函数接收两个参数并返回一个结果。结果类型可不同于任何参数类型 |
UnaryOperator | 表示一个操作数上的运算,该操作数返回的结果的类型与操作数的类型相同。可将UnaryOperator看作返回值与参数类型相同的Function。事实上,UnaryOperator是Function的子接口 |
BinaryOperator | 表示两个操作数上的运算,返回结果必须和操作数的类型相同 |
Predicate | 一个函数,它接收一个参数并根据该参数的值返回true或false |
Supplier | 表示结果的提供者 |
Consumer | 一种操作,它接收一个参数,但不返回任何结果 |
Function-接收1个参数并返回一个结果
<T> –函数输入的类型
<R> –函数结果的类型,结果类型可不同于参数类型
Function-例1
public static void main( String[] args )
{
Function<Integer, Double> milesToKms =
(input) -> 1.6 * input;
int miles = 3;
double kms = milesToKms.apply(miles);
System.out.printf("%d miles = %3.2f kilometers\n",
miles, kms);
}
Function-例2-用方法作为参数
/**
* 转换功能
* @param convertFunction 转换函数
* @param inputData 输入数据
* @param <INPUT_TYPE>
* @param <RETURN_TYPE>
* @return
*/
public static <INPUT_TYPE, RETURN_TYPE> RETURN_TYPE convert(Function<INPUT_TYPE, RETURN_TYPE> convertFunction, INPUT_TYPE inputData){
return convertFunction.apply(inputData);
}
将方法作为参数:
Double milesToKmsResult = convert((input) -> 1.6 * input, 3);
比如:
public static void main( String[] args )
{
int miles = 3;
double kms = convert((input) -> 1.6 * input, 3);
System.out.printf("%d miles = %3.2f kilometers\n",
miles, kms);
}
BiFunction-接收2个参数并返回一个结果
为一个函数建模,该函数接收两个参数并返回一个结果。结果类型可不同于任何参数类型
BiFunction<Float, Float, Float> area =
(width, length) -> width * length;
float width = 7.0F;
float length = 10.0F;
float result = area.apply(width, length);
System.out.println(result);
UnaryOperator-一个参数一个返回类型相同
表示一个操作数上的运算,该操作数返回的结果的类型与操作数的类型相同。可将UnaryOperator看作返回值与参数类型相同的Function。事实上,UnaryOperator是Function的子接口。
BinaryOperator-两个参数一个返回类型都相同
表示两个同类型操作数上的运算,返回结果必须和操作数的类型相同
Predicate-接收一个参数返回布尔值
例子:定义一个Predicate,用于计算输入字符串,如果字符串中的每个字符都是数字,则返回true。
Predicate<String> numbersOnly = (input) -> {
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if ("0123456789".indexOf(c) == -1) {
return false;
}
}
return true;
};
System.out.println(numbersOnly.test("12345")); // true
System.out.println(numbersOnly.test("100a")); // false
Supplier-表示结果的提供者
例一:
private static String getString(Supplier<String> stringSupplier) {
return stringSupplier.get();
}
public static void main( String[] args )
{
String msgA = "Hello ";
String msgB = "World ";
System.out.println(
getString(() -> msgA + msgB)
);
}
例二:定义一个Supplier,用于返回一个随机数(一位数),并使用for循环打印5个随机数。
Supplier<Integer> oneDigitRandom = () -> {
Random random = new Random();
return random.nextInt(10);
};
for (int i = 0; i < 5; i++) {
System.out.println(
oneDigitRandom.get());
}
Supplier也有专门的变体,如DoubleSupplier(返回一个Double)、IntSupplier和LongSupplier等。
Consumer-接收一个参数,但不返回任何结果
accepts a single input argument and returns no result
接收一个参数,但不返回任何结果
例子一:打印水果列表
在jdk内对Consumer的典型使用:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
有一个需要打印的水果列表,可以通过调用forEach方法来实现这一点
List<String> fruits = Arrays.asList("Apple", "Banana");
// 使用Lambda表达式
fruits.forEach((name) -> System.out.println(name));
另外,因为System.out是系统创建的一个现有对象,所以可以使用对System.out上println方法的方法引用:
fruits.forEach(System.out::println);
例子二:接收一个字符串并将其以中心对齐方式打印出来。
// 辅助用
Function<Integer, String> spacer = (count) -> {
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < count; i++) {
sb.append(" ");
}
return sb.toString();
};
int lineLength = 60; // 每行的字符数
Consumer<String> printCentered =
(input) -> {
int length = input.length();
String spaces = spacer.apply(
(lineLength - length) / 2);
System.out.println(spaces + input);
};
printCentered.accept("A lambda expression a day");
printCentered.accept("makes you")
printCentered.accept("look smarter");
这个Consumer,它接收一个字符串,并在该字符串前面加上一定数量的空格后打印它。每一行的最大字符数为60,通过调用一个名为spacer的Function来获得空格。Consumer的accept方法的实现由下面的Lambda表达式给出:
(input) -> {
int length = input.length();
String spaces = spacer.apply(
(lineLength - length) / 2);
System.out.println(spaces + input);
}
函数spacer返回指定的空格数,其定义为:
Function<Integer, String> spacer = (count) -> {
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < count; i++) {
sb.append(" ");
}
return sb.toString();
};
该函数使用了一个for循环,该循环每次向StringBuilder上添加一个空格,共添加count个空格,其中count是函数的参数。当循环退出时,该函数返回StringBuilder的字符串表示形式。
运行后控制台上将输出下面的内容:
A lambda expression a day
makes you
look smarter
另有BiConsumer接口类,该类与Consumer的区别是可以接受2个参数。
相关接口类有:
类名 | 描述 |
---|---|
IntConsumer | 接受单个int型参数的Consumer操作 |
DoubleConsumer | 接受单个double型参数的Consumer操作 |
LongConsumer | 接受单个long型参数的Consumer操作 |
ObjIntConsumer | 接受2个int型参数的Consumer操作,不支持andThen方法 |
ObjDoubleConsumer | 接受2个double型参数的Consumer操作,不支持andThen方法 |
ObjLongConsumer | 接受2个long型参数的Consumer操作,不支持andThen方法 |