由于Java是面向对象的开发语言,所以很多功能函数都是通过传递基本类型的变量或者传递对象变量来进行数据交互的,从Java8开始支持Lambda表达式,可以在功能函数上传递方法或者代码块。
Lambda表达式
- 如果有返回值,返回值类型会在上下文推断出来,不需声明
- 只在几个分支有返回值是语法错误
// 参数,箭头,一个表达式
(String first, String second) -> first.length()-second.length()
// 参数,箭头,{多个语句}
(first, second) -> {
// 形参不用写,可以从上下文推断出来
int result = (-1) * (first.length() - second.length());
return result;
}
// 无参数,仅保留,箭头,表达式
new Thread(() -> {
.....
}).start();
// 一个形参,可省略括号,保留箭头,表达式
x -> {
x++;
};
函数式接口
- 函数式接口是一个接口,符合Java接口的定义
- 只包含一个抽象方法的接口
- 可以包含其他的default方法、static方法、private方法
- 由于只有一个未实现的方法,所以Lambda表达式可以自动填充上这个没有实现的方法
- 采用Lambda表达式,可以自动创建出一个嵌套类的对象,然后使用。
// Lambda表达式
Comparator<String> c = (String first, String second) -> first.length() - second.length();
// 匿名内部类
Comparator<String> c = new Comparator<String>() {
public int compare(String first, String second) {
return first.length() - second.length();
}
};
Lambda表达式(匿名内部类)自动称为接口方法的实现。
注意:使用Lambda表达式不会产生额外的嵌套类的class文件出来。而使用匿名内部类会产生一个class文件
自定义函数式接口
public class Demo1 {
public static void main(String[] args) {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
// 从这里可以看出来Lambda表达式可以创建一个对象出来
StringChecker evenLength = s -> {
if (s.length() % 2 == 0) {
return true;
} else {
return false;
}
};
for (String p : planets) {
if (evenLength.test(p)) {
System.out.println(p);
}
}
}
}
// @FunctionalInterface检查该接口是否只有一个未实现的方法
@FunctionalInterface
interface StringChecker {
// 接口中只有未实现的方法
public boolean test(String s);
}
- 只带一个未实现的方法,内容简单
- 大量重复性的函数式接口,使得源码膨胀
- 系统自带的函数式接口
- 涵盖大量常用功能,可以重复使用,位于java.util.function包中
系统自带的函数式接口
接口 | 参数 | 返回值 | 示例 |
---|---|---|---|
Predicate<T> | T | Boolean | 接收一个参数返回一个布尔值 |
Consumer<T> | T | void | 接收一个参数,没有返回值 |
Function<T, R> | T | R | 接收一个参数,返回一个值 |
Supplier<T> | None | T | 无参数,返回一个值 |
Predicate接口
public static void main(String[] args) {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
Predicate<String> oddLength = s -> s.length() % 2 == 0 ? false : true;
for (String p : planets) {
if (oddLength.test(p)) {
System.out.println(p);
}
}
}
Consumer接口
public static void main(String[] args) {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
Consumer<String> printer = s -> System.out.println("Planet : " + s);
for (String p : planets) {
printer.accept(p);
}
}
Supplier接口
public static void main(String[] args) {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
Supplier<String> planetFactory = () -> planets[ (int) Math.floor(Math.random() * 8)];
for (int i = 0; i < 5; i++) {
System.out.println(planetFactory.get());
}
}
Function接口
public static void main(String[] args) {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
Function<String, String> upper = s -> { return s.toUpperCase(); };
for (String p : planets) {
System.out.println(upper.apply(p));
}
}
方法引用
- Lambda表达式支持传递现有的类库函数
- Class::staticMethod, 如Math::abs方法
- Class::instanceMethod, 如String::compareToIgnoreCase方法
- Object::instanceMethod,如System.out::println方法
- 支持this::instanceMethod调用
- 支持super::instanceMethod调用
- Class::new, 调用某类构造函数,支持单个对象构建
- Class[]::new,调用某类构造函数,支持数组对象构建
public static void main(String[] args) {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
// 将数组中的字符串按字母排序, 双冒号表示方法引用::
Arrays.sort(planets, String::compareToIgnoreCase);
System.out.println(Arrays.toString(planets));
}
类::静态方法 (Class::staticMethod)
public class Demo3 {
public static void main(String[] args) {
double a = -5.3;
// Class::staticMethod
double b = worker(Math::abs, a);
System.out.println(b);
double c = worker(Math::floor, a);
System.out.println(c);
}
public static double worker(NumFunction nf, double num) {
return nf.calculate(num);
}
}
interface NumFunction {
double calculate(double num);
}
类::非静态方法 (Class::instanceMethod)
public static void main(String[] args) {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
// 将数组中的字符串按字母排序, 双冒号表示方法引用::
Arrays.sort(planets, String::compareToIgnoreCase);
System.out.println(Arrays.toString(planets));
}
- String::compareToIgnoreCase方法引用(这个方法引用比较特殊)
- 第一个参数将变成方法的执行体
- String::compareToIgnoreCase等价于 (x,y) -> x.compareToIgnoreCase(y);
对象::非静态方法 (Object::instanceMethod)
- 如System.out.println方法
- System.out::println等价于x -> System.out.println(x);
public class Demo3 {
public static void main(String[] args) {
String a = "abc";
worker(System.out::println, a);
}
public static void worker(NumFunction nf, String str) {
nf.exec(str);
}
}
interface NumFunction {
public void exec(String str);
}
对象::非静态方法(支持this指针)
public class Demo3 {
public static void main(String[] args) {
Demo3 demo3 = new Demo3();
demo3.test();
}
public void test() {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
// this::lengthCompare调用的是本类的lengthCompare方法
Arrays.sort(planets, this::lengthCompare);
System.out.println(Arrays.toString(planets));
}
public int lengthCompare(String first, String second) {
return first.length() - second.length();
}
}
对象::非静态方法(支持super指针)
public class Demo3 extends Father {
public static void main(String[] args) {
Demo3 demo3 = new Demo3();
demo3.test();
}
public void test() {
String[] planets = new String[] {
"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"
};
// 本类继承了father类,调用的的father类中的lengthCompare
Arrays.sort(planets, super::lengthCompare);
System.out.println(Arrays.toString(planets));
}
}
class Father {
public int lengthCompare(String first, String second) {
return first.length() - second.length();
}
}
Class::new
public class Demo4 {
public static void main(String[] args) {
// 由于Supplier是无参数有返回值的,所以可以看作是一个Bean工厂
Supplier<Person> s = Person::new;
// 获取Bean对象
Person p = s.get();
System.out.println(p.getName());
}
}
class Person {
private String name;
private int age;
public Person() {
this.name = "Tang";
this.age = 13;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
Class[]::new (数组对象的创建)
public class Demo4 {
public static void main(String[] args) {
// 创建数组对象
IntFunction<int[]> intArray = int[]::new;
// 数组长度为10
int[] nums = intArray.apply(10);
Function<Integer, Person[]> personArray = Person[]::new;
Person[] persons = personArray.apply(5);
System.out.println(persons);
}
}
class Person { }
Lambda表达式的应用
- 类似于匿名方法,一个没有名字的方法
- 被赋值后,可以看作是一个函数式接口的实例(对象)
- 但是Lambda表达式没有存储目标类型的信息
IntOperation iop = x -> x * 2;
DoubleOperation dop = x -> x * 2;
interface IntOperation {
int Operation(int i);
}
interface DoubleOperation {
double operation(double i);
}
IntOperation iop = x -> x * 2;由于变量名是IntOperation类型所以它的Lambda表达式会自动填充interface IntOperation接口的Operation方法
Lambda表达式
- 重载调用,依据重载的规则和类型参数推断出Lambda表达式调用哪个方法
public class Demo1 {
public static void main(String[] args) {
// 由于该Lambda表达式有返回值,所以调用的是<T> T invoke(Callable<T> c)
// 这个方法
String str = invoke(() -> "function exec");
System.out.println(str);
}
public static void invoke(Runnable r) {
System.out.println("void invoke function exec");
r.run();
}
public static <T> T invoke(Callable<T> c) {
System.out.println("<T> T invoke function exec");
return c.call();
}
}
interface Runnable {
void run();
}
interface Callable<V> {
V call();
}
运行结果:
<T> T invoke function exec
function exec
调用上面案例中的无返回值方法
public static void main(String[] args) {
invoke(() -> { });
}
Lambda表达式的this指代
- 表达式中的this,就是创建这个表达式的方法的this的参数
public class Demo1 {
private String name = "Demo1 class name";
public static void main(String[] args) {
new Demo1().test();
}
public void test() {
// 该Lambda表达式虽然实现的是StringOperation接口中的operation方法
// 当Lambda表达式中的this.name调用的是本类中的name
StringOperation obj = () -> System.out.println(this.name);
obj.operation();
}
}
interface StringOperation {
String name = "StringOperation class name";
public void operation();
}
运行结果:
Demo1 class name
Lambda表达式与接口方法的关系
- Lambda表达式是填充接口的一个抽象方法
- 为了推出Lambda表达式,从JDK8开始支持的接口有默认方法 / 静态方法 / 私有方法
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Tang");
list.add("huang");
// JDK8Lambda表达式的遍历输出
// 与list.forEach((str) -> System.out.println(str) );
// 等价,Lambda表达式中的str是有List<String>中的String推断出来的
list.forEach(System.out::println);
// JDK5支持的for-earch
for (String s : list) {
System.out.println(s);
}
}