你所不知道的Lambda表达式和常用的函数式接口
你所不知道的Lambda表达式和常用的函数式接口
推荐答案
同学,您好!你所不知道的Lambda表达式和常用的函数式接口
一. 什么是Lambda表达式
Lambda表达式是JDK1.8中新增的一种方式,用于替代匿名内部类,该表达式可以让开发人员更加关注于具体需要传递的方法,而不是因为需要传递一个方法而创建一个对象。
二. Lambda表达式
1. 基本语法
Lambda省去⾯向对象的条条框框,格式由3个部分组成:
参数部分
箭头
代码块
比如:(参数类型 参数名称) -> { 代码语句 }
2. 格式说明
⼩括号内的语法与传统⽅法参数列表⼀致:⽆参数则留空;多个参数则⽤逗号分隔;
-> 是新引⼊的语法格式,代表指向动作;
⼤括号内的语法与传统⽅法体要求基本⼀致。
3. Lambda的省略格式
所谓的Lambda表达式的省略原则是:可推导即可省略。
Lambda强调的是“做什么”⽽不是“怎么做”,所以凡是可以根据上下⽂推导得知的信息,都可以省略。
3.1 省略规则
在Lambda标准格式的基础上,使⽤省略写法的规则为:
⼩括号内参数的类型可以省略;
如果⼩括号内有且仅有⼀个参,则⼩括号可以省略;
如果⼤括号内有且仅有⼀个语句,则⽆论是否有返回值,都可以省略⼤括号、return关键字及语句、分号。
4. Lambda的使用前提
Lambda的语法⾮常简洁,完全没有⾯向对象复杂的束缚,但是使⽤时有⼏个问题需要特别注意:
使⽤Lambda必须具有接⼝,且要求接⼝中有且仅有⼀个抽象⽅法。 ⽆论是JDK内置的
Runnable 、 Comparator 接⼝还是⾃定义的接⼝,只有当接⼝中的抽象⽅法存在且唯⼀时,才可以使用Lambda
2. 使⽤Lambda必须具有上下⽂推断。 也就是⽅法的参数或局部变量类型必须为Lambda对应的接⼝
类型,才能使⽤Lambda作为该接⼝的实例。
5. 常用函数式接口
JDK提供了⼤量常⽤的函数式接⼝以丰富Lambda的典型使⽤场景,它们主要在 java.util.function
包中被提供. 常用的函数式接口包括以下四个。
5.1 Supplier接⼝
java.util.function.Supplier 接⼝仅包含⼀个⽆参的⽅法: T get() 。⽤来获取⼀个泛型参数,可以指定类型的对象数据。由于这是⼀个函数式接⼝,这也就意味着对应的Lambda表达式需要“对外提供”⼀个符合泛型类型的对象数据。
5.1.1 基本使用方式如下:
public class SupplierDemo {
// 为了获取一个int类型的数据
private static int getNum(Supplier supplier) {
// get方法 -- 返回一个指定数据类型 T 的数据
return supplier.get();
}
public static void main(String[] args) {
// int num = getNum(new Supplier() {
// @Override
// public Integer get() {
// return 50;
// }
// });
System.out.println(getNum(() -> 50));
// 1. 获取30 60 两个数字中的最大值
// getNum(new Supplier() {
// @Override
// public Integer get() {
// return Math.max(30, 60);
// }
// });
getNum(()->Math.max(30, 60));
// 有一个数组
int[] nums = {1,5,4,8,4,51,2,1,6,8};
// 通过getNum方法获取数组的最大值
// getNum(new Supplier() {
// @Override
// public Integer get() {
// Arrays.sort(nums);
// return nums[nums.length - 1];
// }
// });
int num = getNum(() -> {
Arrays.sort(nums);
return nums[nums.length - 1];
});
System.out.println(num);
}
}
5.2 Consumer接⼝
java.util.function.Consumer 接⼝则正好与Supplier接⼝相反,它不是⽣产⼀个数据,⽽是消费⼀个数据,其数据类型由泛型决定。
Consumer 接⼝中包含抽象⽅法 void accept(T t) ,意思是说消费⼀个执⾏泛型的数据
Consumer 接⼝中包含默认⽅法:andThen
如果⼀个⽅法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,⾸先做⼀个操作, 然后再做另⼀个操作,实现组合。⽽这个⽅法就是 Consumer 接⼝中的default⽅法 andThen
5.2.1 下⾯是JDK的源代码:
default Consumer andThen(Consumer after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
基本使用方式如下:
public class ConsumerDemo {
// 使用一个指定的String类型的数据
private static void useString(Consumer consumer, String string){
consumer.accept(string);
}
private static void useString(Consumer consumer, Supplier supplier) {
consumer.accept(supplier.get());
}
// 返回的Consumer对象的目的 -- 使用accept方法接收参数,传递给first和second使用
private static Consumer andThen(Consumer first, Consumer second){
return new Consumer() {
@Override
public void accept(String s) {
first.accept(s);
second.accept(s);
}
};
}
private static void andThenTest(Consumer first, Consumer second, String string){
// Consumer then = first.andThen(second);
// then.accept(string);
// 前后两个接口对象之间,没有数据上的联系
// 两个接口 分别处理的都是原本的数据
first.andThen(second).accept(string);
System.out.println("---------");
Consumer consumer = andThen(first, second);
consumer.accept(string);
}
public static void main(String[] args) {
// useString(new Consumer() {
// @Override
// public void accept(String s) {
// System.out.println(s.length());
// }
// }, "lambda");
// useString((String s)->{
// System.out.println(s.length());
// }, "lambda");
useString(s->System.out.println(s.length()), "lambda");
// useString(s-> System.out.println(s), "lambda");
// useString(System.out::println, "lambda");
useString(s-> {
System.out.println(s.concat(Integer.valueOf(s.length()).toString()));
System.out.println(s + s.length());
}, "lambda");
useString(s->{
System.out.println(s.length());
},()->{
return "123456oiuytr";
});
andThenTest(s -> System.out.println(s.toUpperCase()),
s->System.out.println(s.substring(0, 3)), "lambda Exp");
}
}
5.3 Predicate接⼝
有时候我们需要对某种类型的数据进⾏判断,从⽽得到⼀个boolean值结果。这时可以使
⽤java.util.function.Predicate接⼝。
Predicate 接⼝中包含⼀个抽象⽅法: boolean test(T t)
该接口也存在三个默认的方法,分别是and 、 or 和negate, 分别表示与 、或 、非三种逻辑处理。
5.3.1 接口代码示例:
public class PredicateDemo {
private static boolean testMethod(Predicate predicate, String s){
// test方法返回一个boolean类型的数据
return predicate.test(s);
}
private static boolean andMethod(Predicate first, Predicate second, String s){
return first.and(second).test(s);
}
private static boolean orMethod(Predicate first, Predicate second, String s) {
return first.or(second).test(s);
}
private static boolean negateMethod(Predicate predicate, String s) {
return predicate.negate().test(s);
}
public static void main(String[] args) {
// 1. 判断一个字符串是否是由txt结尾的
// boolean result = testMethod(new Predicate() {
// @Override
// public boolean test(String s) {
// return s.endsWith("txt");
// }
// }, "newFile");
// boolean result = testMethod((String s)->{
// return s.endsWith("txt");
// }, "newFile");
boolean result = testMethod(s->s.endsWith("txt"), "newFile");
System.out.println(result);
boolean r1 = andMethod(s -> s.length() > 6,
s -> s.startsWith("a"), "asijhgvbnm");
boolean r2 = orMethod(s -> s.length() > 6,
s -> s.equals("abcd"), "asdfghjkl");
boolean r3 = negateMethod(s -> s.endsWith("a"), "asdfghjkl");
System.out.println(r1 + " - " + r2 + " - " + r3);
}
}
5.4 Function接⼝
java.util.function.Function接⼝⽤来根据⼀个类型的数据得到另⼀个类型的数据,前者称为前置条件,后者称为后置条件。
Function 接⼝中最主要的抽象⽅法是: R apply(T t) ,根据类型T的参数获取类型R的结果。
Function接⼝中有⼀个默认的andThen⽅法,⽤来进⾏组合操作。
5.4.1 基本使用方式如下
public class FunctionDemo {
private static void applyMethod(Function function, String s){
Integer apply = function.apply(s);
System.out.println("从字符串" + s + "中获取的integer类型数据是:" + apply);
}
private static Function andThen(Function first, Function second){
// T = String; R = Integer; V=Boolean
// String --> Boolean
return new Function() {
@Override
public Boolean apply(String s) {
// String --> Integer
Integer apply = first.apply(s);
// Integer --> Boolean
Boolean apply1 = second.apply(apply);
return apply1;
}
};
}
private static void andThenMethod(Function first, Function second, String s){
Function then = first.andThen(second);
// 因为andThen方法在实现的时候 前面一个的结果给后面一个处理
// 前者T R --> 后者 R V ==> T --> V
Boolean apply = then.apply(s);
System.out.println(apply);
System.out.println("------");
Function function = andThen(first, second);
Boolean b = function.apply(s);
System.out.println(b);
}
public static void main(String[] args) {
// applyMethod(new Function() {
// @Override
// public Integer apply(String s) {
// return s.indexOf("a");
// }
// }, "fashjkl");
// applyMethod((String s)->{
// return s.indexOf("a");
// }, "fashjkl");
applyMethod(s->s.indexOf("a"), "fashjkl");
andThenMethod(s-> s.length(),
i -> i > 20, "sadfghjkl;");
// andThenMethod(String::length,
// i -> i > 20, "sadfghjkl;");
}
}
现在你学会Lambda表达式怎么用了吗?