JAVA8核心语法梳理(1)Lambda表达式、函数式接口、方法引用

欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我微信「java_front」一起交流学习

1 文章概述

JAVA13已经面世一段时间了,但是追根溯源一些新特性例如Lambda表达式、函数式接口、StreamAPI首次还在是出现在JAVA8。这些新特性有些开发者使用并不习惯,尤其链式编程感觉没有代码断句,可读性不强。但是JAVA8之所以逐渐流行确实是因为确实有许多优点:

  • 代码优雅
  • 易于并行
  • StreamAPI
  • Optional减少空指针

现在项目代码中越来越多出现JAVA8语法,为了读懂代码也需要我们熟悉JAVA8语法,本文介绍JAVA8如下重要特性,streamAPI我们下一篇文章再详细介绍。

  • Lambda表达式
  • 函数式接口
  • 方法引用

2 Lambda表达式

2.1 基本说明

Lambda表达式本质上是一个匿名函数,我们可以将一个Lambda表达式像参数一样进行传递。

public static void test01() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("公众号JAVA前线");
        }
    }).start();

    /** Lambda表达式 **/
    new Thread(() -> System.out.println("公众号JAVA前线")).start();
}

我们看到Lambda表达式6行代码缩短为1行,代码简洁而优雅,但是仅仅看代码并不好理解,下面我们介绍Lambda语法。

2.2 语法详解

Lambda表达式引入了->箭头操作符,箭头操作符左边指定表达式参数,右表是表达式执行体,下面我们根据参数个数的不同说明Lambda表达式语法。

(1) 无参数
public static void test02_NoParam() {
    Runnable task = () -> System.out.println("公众号JAVA前线");
    new Thread(task).start();
}
(2) 一个参数

单个参数可以不写小括号。假设一个方法参数类是字符串,在写Lambda表达式时并不要显示申明String类型,编译器可以根据上下文推断出类型,这就是类型推断。

import java.util.function.Consumer;

public static void test03_OneParam() {
    Consumer<String> c1 = (str) -> System.out.println(str);
    c1.accept("公众号JAVA前线");
    Consumer<String> c2 = str -> System.out.println(str);
    c2.accept("公众号JAVA前线");
}

上述例子使用了函数式接口Consumer我们后面再讲。

(3) 多个参数

如果Lambda体只有一行代码则花括号和return可以省略

public class Student {
    private int age;
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public static void test04_MultiParam() {
    List<Student> list = new ArrayList<Student>();
    Collections.sort(list, new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> {
        return o1.getAge().compareTo(o2.getAge());
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
}

3 函数式接口

函数式接口特点只包含了一个方法。JAVA8有四大内置函数式接口,其它内置函数式接口,还可以自定义函数式接口。

3.1 四大内置函数式接口

接口名输入类型输出类型核心方法说明
Consumer[T]Tvoidaccept(T)消费型
Supplier[T]voidTT get()供给型
Function[T,R]TRR apply(T)函数型
Predicate[T]Tbooleanboolean test(T)判断型
(1) Consumer

Consumer作为消费型接口输入类型为T,没有输出类型

import java.util.function.Consumer;

public static void testConsumer() {
    Consumer<String> consumer = (str) -> {
        String newStr = "公众号" + str;
        System.out.println(newStr);
    };
    consumer.accept("JAVA前线");
}
(2) Supplier

Supplier作为供给型接口没有输入类型,输出类型为T

import java.util.function.Supplier;

public static void testSupplier() {
    Supplier<String> supplier = () -> {
        return "公众号JAVA前线";
    };
    String result = supplier.get();
    System.out.println(result);
}
(3) Function

Function作为函数型接口输入类型为T,输出类型为R

import java.util.function.Function;

public static void testFunction() {
    Function<String, Integer> function = (str) -> {
        if("公众号JAVA前线".equals(str)) {
            return 1;
        }
        return 0;
    };
    Integer result = function.apply("公众号JAVA前线");
    System.out.println(result);
}
(4) Predicate

Predicate作为判断型接口输入类型为T,输出类型为Boolean

import java.util.function.Predicate;

public static void testPredicate() {
    Predicate<String> predicate = (str) -> {
        if ("公众号JAVA前线".equals(str)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    };
    boolean result = predicate.test("公众号JAVA前线");
    System.out.println(result);
}
3.2 自定义函数接口

FunctionalInterface标识一个自定义函数式接口,我们可以根据需求定义功能强大的函数接口

/**
 * 自定义函数接口
 *
 * @author 公众号JAVA前线
 *
 * @param <T> 输入类型1
 * @param <R> 输入类型2
 * @param <U> 输出类型
 */
@FunctionalInterface
public interface MyInterfaceFunction<T, R, U> {
    public U bizMethod(T t, R r);
}

/**
 * 测试实例
 */
public class Java8_Function {
    public static void testMyFunction() {
        MyInterfaceFunction<String, String, Integer> myFuntion = (str1, str2) -> {
            if ("公众号".equals(str1) && "JAVA前线".equals(str2)) {
                return 1;
            }
            return 0;
        };
        Integer result = myFuntion.bizMethod("公众号", "JAVA前线");
        System.out.println(result);
    }
}
3.3 其它内置函数式接口

在四大内置函数式接口基础上,JAVA8提供了其它内置函数式接口,我们尝试列出一些并选择编写几个代码实例。

接口名输入类型输出类型核心方法
BiConsumer[T,U]T、Uvoidaccept(T,U)
BiFunction[T,U,R]T、URR apply(T,U)
UnaryOperator[T]TTT apply(T)
BinaryOperator[T]T、TTT apply(T,T)
ToIntFunction[T]Tintint apply(T)
(1) BiFunction

BiFunction是Function函数增强版,允许两种输入类型

import java.util.function.BiFunction;

public static void testBiFunction() {
    BiFunction<String, String, Integer> biFunction = (str1, str2) -> {
        if ("公众号".equals(str1) && "JAVA前线".equals(str2)) {
            return 1;
        }
        return 0;
    };
    Integer result = biFunction.apply("公众号", "JAVA前线");
    System.out.println(result);
}
(2) BiConsumer

BiConsumer是Consumer函数增强版本,允许两种输入类型

import java.util.function.BiConsumer;

public static void testBiConsumer() {
    BiConsumer<String, String> biConsumer = (str1, str2) -> {
        System.out.println(str1 + str2);
    };
    biConsumer.accept("公众号", "JAVA前线");
}
(3) BinaryOperator

对类型为T的数据进行二元运算,并返回类型为T的结果

import java.util.function.BinaryOperator;

public static void testBinaryOperator() {
    BinaryOperator<String> biOperator = (str1, str2) -> {
        return str1 + str2;
    };
    String result = biOperator.apply("公众号", "JAVA前线");
    System.out.println(result);
}

4 方法引用

方法引用语法操作符是两个冒号,初看会让人比较费解。本章节我们来分析这个语法。当我们在编写Lambda方法体时,如果方法体的方法已经有现成实现,那么我们可以直接引用这个方法,这就是方法引用,需要注意的是参数列表必须一致。方法引用语法有四类:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法
  • 类::new

4.1 对象::实例方法

public class Student {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public static void test01() {
    Consumer<String> c1 = (x) -> System.out.println(x);
    c1.accept("公众号JAVA前线");

    Consumer<String> c2 = System.out::println;
    c2.accept("公众号JAVA前线");

    Student student = new Student("公众号JAVA前线");
    Supplier<String> s1 = () -> student.getName();
    System.out.println(s1.get());

    Supplier<String> s2 = student::getName;
    System.out.println(s2.get());
}

4.2 类::实例方法

public class Student {
    private int age;
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


public static void test02() {
    BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);
    System.out.println(bp1.test("公众号", "JAVA前线"));
    // 类::实例方法
    BiPredicate<String, String> bp2 = String::equals;
    System.out.println(bp2.test("公众号", "JAVA前线"));

    List<Student> list = new ArrayList<Student>();
    Collections.sort(list, new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
    // 类::实例方法
    Collections.sort(list, Comparator.comparing(Student::getAge));
}

4.3 类::静态方法

public class Student {

    private int age;
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static int compareAge(Student s1, Student s2) {
        return s1.getAge().compareTo(s2.getAge());
    }
}

public static void test03() {
    List<Student> list = new ArrayList<Student>();
    Collections.sort(list, new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
    Collections.sort(list, Comparator.comparing(Student::getAge));
    // 类::静态方法
    Collections.sort(list, Student::compareAge);
}

4.4 类::new

public class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }
}

public static void test04() {
    Function<String, Student> f1 = (str) -> new Student(str);
    System.out.println(f1.apply("公众号JAVA前线"));

    Function<String, Student> f2 = Student::new;
    System.out.println(f2.apply("公众号JAVA前线"));

    Function<Integer, Integer[]> f3 = (num) -> new Integer[num];
    System.out.println(f3.apply(15));

    Function<Integer, Integer[]> f4 = Integer[]::new;
    System.out.println(f4.apply(15));

    Supplier<List<Student>> s1 = () -> new ArrayList<Student>();
    System.out.println(s1.get());

    Supplier<List<Student>> s2 = ArrayList<Student>::new;
    System.out.println(s2.get());
}

5 文章总结

本文我们总结了Lambda表达式,函数式接口,方法引用语法,这些语法相较于传统语法改变不小,一开始并不容易理解,还需要反复实践。下一篇文章我们介绍JAVA8强大的StreamAPI语法请继续关注。

欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我微信「java_front」一起交流学习

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值