Lambda表达式:
- 函数式编程思想:只重视结果不重视过程 和面向对象的思想不同
- Lambda标准格式 格式由3个部分组成:
- 一些参数 一个箭头 一段代码 Lambda表达式的标准格式为:
(参数类型 参数名称) ‐> { 代码语句 }
- 格式说明:
-
小括号内的语法与传统方法参数列表一致
-
无参数则留空;多个参数则用逗号分隔
-
-> 是新引入的语法格式,代表指向动作。 大括号内的语法与传统方法体要求基本一致
new Thread(()-> { System.out.println("多线程任务执行!")}).start();
-
- 省略规则 在Lambda标准格式的基础上,使用省略写法的规则为:
- 小括号内参数的类型可以省略
- 如果小括号内有且仅有一个参,则小括号可以省略
- . 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号
- 一些参数 一个箭头 一段代码 Lambda表达式的标准格式为:
- Lambda的语法非常简洁,完全没有面向对象复杂的束缚 但是需要注意的是:
- 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法 无论是JDK内置的 Runnable 、 Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一 时,才可以使用Lambda(有且只有一个抽象方法的接口叫做是 函数式接口)
- 使用Lambda必须具有上下文推断 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例
函数式接口:
- 概念:有且仅有一个抽象方法的接口 在Java中具体的体现就是Lambda表达式
- 格式:
public interface 接口名称 { 返回值类型 方法名称(可选参数信息); // 其他非抽象方法内容 }
@FunctionalInterface
注解 与 @Override 注解的作用类似,Java 8中专门为函数式接口引入的注解:@FunctionalInterface 强制检查该接口是否确实有且仅有一个抽象方法- 函数式编程:
-
Lambda延迟执行:就是只有在丰富和要求的情况下才能执行 从而提升性能
-
使用Lambda作为参数和返回值:Java中常常使用Lambda表达式来进行匿名内部类的替代品 那么方法的返回值或者是参数 是一个函数式接口的话就能使用Lambda来代替 如:
public class Demo06Comparator { private static Comparator<String> newComparator() { return (a, b) ‐> b.length() ‐ a.length(); } public static void main(String[] args) { String[] array = { "abc", "ab", "abcd" }; System.out.println(Arrays.toString(array)); Arrays.sort(array, newComparator()); System.out.println(Arrays.toString(array)); } }
-
- 常用的函数式接口:主要在
java.util.function
包中被提供Supplier
接口java.util.function.Supplier<T>
接口仅包含一个无参的方法:T get()
用来获取一个泛型参数指定类型的对 象数据 由于这是一个函数式接口 这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据(也就是泛型)-
代码演示:
//定一个方法,方法的参数传递Supplier,泛型使用Integer public static int getMax(Supplier<Integer> sup){ return sup.get(); } public static void main(String[] args) { int arr[] = {2,3,4,52,333,23}; //调用getMax方法,参数传递Lambda int maxNum = getMax(()‐>{ //计算数组的最大值 int max = arr[0]; for(int i : arr){ if(i>max){ max = i; } } return max; }); System.out.println(maxNum); }
-
Consumer
接口java.util.function.Consumer<T>
接口则正好与Supplier
接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定Consumer
接口中包含抽象方法void accept(T t)
,意为消费一个指定泛型的数据-
代码演示:
private static void consumeString(Consumer<String> function) { function.accept("Hello"); } public static void main(String[] args) { consumeString(s ‐> System.out.println(s)); }
-
默认方法:andThen 如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作, 然后再做一个操作,实现组合。而这个方法就是 Consumer 接口中的default方法 andThen 下面是JDK的源代码:先要实现组合 需要使用多个Lambda表达式即可
default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) ‐> { accept(t); after.accept(t); }; }
private static void consumeString(Consumer<String> one, Consumer<String> two) { one.andThen(two).accept("Hello"); } public static void main(String[] args) { //将传入的Hello 先大写打印 在进行小写打印 consumeString( s ‐> System.out.println(s.toUpperCase()), s ‐> System.out.println(s.toLowerCase())); }
-
Predicate
接口 需要对某种类型的数据进行判断 从而得到一个boolean值结果 使用java.util.function.Predicate<T>
接口 接口中包含一个抽象方法:boolean test(T t)
- 代码演示:
private static void method(Predicate<String> predicate) { boolean veryLong = predicate.test("HelloWorld"); System.out.println("字符串很长吗:" + veryLong); } public static void main(String[] args) { //只要传入的字符串的长度大于5就表示字符串很长 method(s ‐> s.length() > 5); }
- 默认方法:进行逻辑判断 就存在着
或 与 非
的关系and
方法- 源码:
default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) ‐> test(t) && other.test(t); }
- 演示:
private static void method(Predicate<String> one, Predicate<String> two) { boolean isValid = one.and(two).test("Helloworld"); System.out.println("字符串符合要求吗:" + isValid); } public static void main(String[] args) { //判断字符串中是否含有H 和W method(s ‐> s.contains("H"), s ‐> s.contains("W")); }
- 源码:
or
方法-
源码:
default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) ‐> test(t) || other.test(t); }
-
演示:
private static void method(Predicate<String> one, Predicate<String> two) { boolean isValid = one.ortwo).test("Helloworld"); System.out.println("字符串符合要求吗:" + isValid); } public static void main(String[] args) { //判断字符串中是否含有H 或者是W method(s ‐> s.contains("H"), s ‐> s.contains("W")); }
-
negate
非-
源码
default Predicate<T> negate() { return (t) ‐> !test(t); }
-
演示
private static void method(Predicate<String> predicate) { boolean veryLong = predicate.negate().test("HelloWorld"); System.out.println("字符串很长吗:" + veryLong); } public static void main(String[] args) { // 只要字符串的长度不小于5就是长 method(s ‐> s.length() < 5); }
-
- 代码演示:
Function
接口java.util.function.Function<T,R>
接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件 后者称为后置条件 抽象方法为:R apply(T t)
根据类型T的参数获取类型R的结果- 代码演示:
private static void method(Function<String, Integer> function) { int num = function.apply("10"); System.out.println(num + 20); } public static void main(String[] args) { // 将字符串10 转成int类型 + 20 输出 method(s ‐> Integer.parseInt(s)); }
- 默认方法:andThen 和Consumer接口中andThen方法 用法一致
-
源码:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) ‐> after.apply(apply(t)); }
-
演示
private static void method(Function<String, Integer> one, Function<Integer, Integer> two) { int num = one.andThen(two).apply("10"); System.out.println(num + 20); } public static void main(String[] args) { // 链式执行两步操作:先将字符串进行解析成int类型 在乘以10 method(str‐>Integer.parseInt(str)+10, i ‐> i *= 10); }
-
- 代码演示: