jdk7到jdk8引入了很多新的特性,函数式接口,新的Date API,stream流,lambda表达式,接口默认方法等。在这里主要对函数式接口、lambda表达式、stream流做简单的记录学习。欢迎大家一起学习交流。
函数式接口一句话总结:只有一个抽象方法的接口称为函数式接口。可以用【@FunctionalInterface】注解检验是否是函数式接口,在jvm进行编译的的时候会检查接口是否符合函数式接口规范。
函数式接口的几点特征:
这里就可以解释Comparator为什么是函数式接口。
lambda表达式概念:lambda表达式可以理解为函数式接口的隐式转换,也是函数中的匿名类(闭包)。只有拥有函数式接口才能写lambda表达式。
lambda表达式的常见形式:
1 没有参数的lambda:
private static void testNoParamLambda() { // lambda方式 Runnable noArguments = () -> System.out.println("Hello World"); // 闭包方式 Runnable noArguments = new Runnable() { @Override public void run() { System.out.println("Hello World"); } }; }
这个Lambda表达式不包含参数,使用空括号 () 表示没有参数。Runnable接口也只有一个 run 方法,没有参数,且返回类型为 void
2 单个参数的lambda:
private static void testSingleParamLambda() { // lambda方式 Predicate
predicate = (number) -> number > 2; // 闭包方式 Predicate predicate = new Predicate () { @Override public boolean test(Integer integer) { return integer > 2; } }; } 这个Lambda表达式包含一个参数,参数是Integer,返回值是Predicate,注意Predicate可以理解为是实现函数式接口的匿名内部类的对象。通过predicate这样调用这个方法。
private static void testDoubleParamLambda() { // lambda方式 BinaryOperator
binaryOperator = (s1, s2) -> s1 + "love" + s2; // 闭包方式 BinaryOperator binaryOperator = new BinaryOperator () { @Override public String apply(String s, String s2) { return s + "love" + s2; } }; }
lambda表达式的特点:
lambda表示自定义的函数接口
函数式接口:
/** * @description: 函数式接口 */ @FunctionalInterface public interface FunctionInterface
{ U packStr(T t1, R r2, T t3, R r4); } 测试代码:
private static void testCustomLambda() { // lambda方式 FunctionInterface
functionInterface = (s1, s2, s3, s4) -> "第一个数字是" + s1 + "第二个数字是" + s2 + "第三个数字是" + s3 + "第四个数字是" + s4; System.out.println(functionInterface.packStr(1, 2L, 3, 4L)); // 闭包方式 FunctionInterface functionInterface1 = new FunctionInterface () { @Override public String packStr(Integer s1, Long s2, Integer s3, Long s4) { return "第一个数字是" + s1 + "第二个数字是" + s2 + "第三个数字是" + s3 + "第四个数字是" + s4; } }; }
Stream流简介:
Stream流是jdk8为了更方便对集合类的迭代而产生的,通过Stream流你可以实现对集合的遍历,分组,过滤,排序,集合类型转化,找到集合(主要是list和set)中的极值等等。
Stream流特点:
stream流的很多方法都是和函数式接口有关的。而函数式接口又可以通过lamdba表示。stream和常见的函数式接口有如下配合。
stream的方法 | 函数式接口 | 函数式接口方法 | 方法描述 |
filter | Predicate |
boolean test(T t) | 根据输入的T值得到布尔值,主要用于stream筛选元素 |
allMatch | Predicate |
boolean test(T t) | 根据输入的T值得到布尔值,主要用于stream匹配元素 |
foreach | Consumer |
void accept(T t) | 消费T类型的消息,主要用于stream遍历元素 |
map | Function |
R apply(T t) | 将T类型值转换成R类型值,主要用于stream转换元素 |
sorted | Comparator |
int compare(T o1, T o2) | 根据输入的T、T两值得到int值,主要用于stream排序元素 |
reduce | BinaryOperator | T apply(T t, T u) | BiFunction的特例实现,主要用于stream合并元素 |
@Data
@AllArgsConstructor
public static class Person {
private Integer age;
private String name;
}
private static void testStreamUsage() {
Person a = new Person(10, "A");
Person b = new Person(13, "B");
Person c = new Person(15, "C");
Person d = new Person(18, "D");
// 打印出年纪最大的人的名字
System.out.println(Stream.of(a, c, b, d).max((s1, s2) -> s2.getAge() > s1.getAge() ? -1 : 0).map(Person::getName).orElse("null"));
// 打印出年纪最小的人的名字
System.out.println(Stream.of(a, c, b, d).min((s1, s2) -> s1.getAge() > s2.getAge() ? -1 : 0).map(Person::getName).orElse("null"));
// 按年龄大小(从大到小)打印所有人的名字
Stream.of(a, c, b, d).sorted((s1, s2) -> s2.getAge() > s1.getAge() ? -1 : 0).map(Person::getName).forEach(System.out::println);
}
上述代码演示了stream常见的方法,有兴趣的小伙伴还是要自己实践下。
java Comparator为何是函数式接口?
Java 8 函数式接口 | 菜鸟教程
JDK 8 函数式编程入门 - alfred_zhong - 博客园
Java 函数式编程(Lambda表达式)与Stream API - March On - 博客园
Java8 Stream流 - OKevin - 博客园
[译] 一文带你玩转 Java8 Stream 流,从此操作集合 So Easy - 掘金