JAVA8核心语法梳理(1)Lambda表达式、函数式接口、方法引用
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] | T | void | accept(T) | 消费型 |
Supplier[T] | void | T | T get() | 供给型 |
Function[T,R] | T | R | R apply(T) | 函数型 |
Predicate[T] | T | boolean | boolean 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、U | void | accept(T,U) |
BiFunction[T,U,R] | T、U | R | R apply(T,U) |
UnaryOperator[T] | T | T | T apply(T) |
BinaryOperator[T] | T、T | T | T apply(T,T) |
ToIntFunction[T] | T | int | int 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前线】获取更多互联网和技术干货,感谢各位支持
上一篇: MySQL的自动提交模式
下一篇: 硬盘安装操作系统详细图文教程