(1)概念:Lambda 是一个匿名函数,我们可以把Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
(2)格式:
- 无参,无返回值。 Runnable runnable=()->System.out.println("hello lambda"); runnable.run()
- 有一个参数 Consumer<String> consumer = (args)->System.out.println(args); consumer.accept("hello world");
- 有一个参数时 参数的括号可以省略。 Consumer<String> consumer = args->System.out.println(args);
- 有两个参数并有返回值。 BinaryOperator<Integer> binaryOperator = (x,y)->{......;return x+y;} 注意:x,y的数据类型不需要必须写,编译器可以推断出来. 类型推断!
- 当lambda体只有一条语句时,{}和return可以省略。 BinaryOperator<Integer> binaryOperator = (x,y)->x+y;
(3)函数式接口:只有一个抽象方法的接口。
1.可以用@FunctionalInterface检查是否是函数式接口。
2.可以使用泛型
@FunctionalInterface
interface IF<T> {
T get(T t);
// void lig();
}
接口作为参数传递lambda表达式
public class Demo { public String getNum(IF<String> i,String str){ return i.get(str); } public static void main(String[] args) { new Demo().getNum(new IF<String>() { @Override public String get(String s) { return s+"_......"; } },"wow.."); } }
java8提供的四大核心接口 :https://www.cnblogs.com/invoker-/p/7709052.html
1、Consumer<T> :消费型接口 void accept(T t);
2、Supplier<T> :供给型接口 T get();
3、Function<T,R> :函数型接口 R apply(T t);
4、Predicate<T> :断言型接口 boolean test(T t);
其他接口:
Function
表示一个方法接收参数并返回结果。
接收单个参数
Interface | functional method | 说明 |
---|---|---|
Function<T,R> | R apply(T t) | 接收参数类型为T,返回参数类型为R |
IntFunction<R> | R apply(int value) | 以下三个接口,指定了接收参数类型,返回参数类型为泛型R |
LongFunction<R> | R apply(long value) | |
Double<R> | R apply(double value) | |
ToIntFunction<T> | int applyAsInt(T value) | 以下三个接口,指定了返回参数类型,接收参数类型为泛型T |
ToLongFunction<T> | long applyAsLong(T value) | |
ToDoubleFunction<T> | double applyAsDouble(T value) | |
IntToLongFunction | long applyAsLong(int value) | 以下六个接口,既指定了接收参数类型,也指定了返回参数类型 |
IntToDoubleFunction | double applyAsLong(int value) | |
LongToIntFunction | int applyAsLong(long value) | |
LongToDoubleFunction | double applyAsLong(long value) | |
DoubleToIntFunction | int applyAsLong(double value) | |
DoubleToLongFunction | long applyAsLong(double value) | |
UnaryOperator<T> | T apply(T t) | 特殊的Function,接收参数类型和返回参数类型一样 |
IntUnaryOperator | int applyAsInt(int left, int right) | 以下三个接口,制定了接收参数和返回参数类型,并且都一样 |
LongUnaryOperator | long applyAsInt(long left, long right) | |
DoubleUnaryOperator | double applyAsInt(double left, double right) |
接收两个参数
interface | functional method | 说明 |
---|---|---|
BiFunction<T,U,R> | R apply(T t, U u) | 接收两个参数的Function |
ToIntBiFunction<T,U> | int applyAsInt(T t, U u) | 以下三个接口,指定了返回参数类型,接收参数类型分别为泛型T, U |
ToLongBiFunction<T,U> | long applyAsLong(T t, U u) | |
ToDoubleBiFunction<T,U> | double appleyAsDouble(T t, U u) | |
BinaryOperator<T> | T apply(T t, T u) | 特殊的BiFunction, 接收参数和返回参数类型一样 |
IntBinaryOperator | int applyAsInt(int left, int right) | |
LongBinaryOperator | long applyAsInt(long left, long right) | |
DoubleBinaryOperator | double applyAsInt(double left, double right) |
Consumer
表示一个方法接收参数但不产生返回值。
接收一个参数
interface | functional method | 说明 |
---|---|---|
Consumer<T> | void accept(T t) | 接收一个泛型参数,无返回值 |
IntConsumer | void accept(int value) | 以下三个类,接收一个指定类型的参数 |
LongConsumer | void accept(long value) | |
DoubleConsumer | void accept(double value) |
接收两个参数
interface | functional method | 说明 |
---|---|---|
BiConsumer<T,U> | void accept(T t, U u) | 接收两个泛型参数 |
ObjIntConsumer<T> | void accept(T t, int value) | 以下三个类,接收一个泛型参数,一个指定类型的参数 |
ObjLongConsumer<T> | void accept(T t, long value) | |
ObjDoubleConsumer<T> | void accept(T t, double value) |
Supplier
返回一个结果,并不要求每次调用都返回一个新的或者独一的结果
interface | functional method | 说明 |
---|---|---|
Supplier<T> | T get() | 返回类型为泛型T |
BooleanSupplier | boolean getAsBoolean() | 以下三个接口,返回指定类型 |
IntSupplier | int getAsInt() | |
LongSupplier | long getAsLong() | |
DoubleSupplier | double getAsDouble() |
Predicate
根据接收参数进行断言,返回boolean类型
interface | functional method | 说明 |
---|---|---|
Predicate<T> | boolean test(T t) | 接收一个泛型参数 |
IntPredicate | boolean test(int value) | 以下三个接口,接收指定类型的参数 |
LongPredicate | boolean test(long value) | |
DoublePredicate | boolean test(double value) | |
BiPredicate<T,U> | boolean test(T t, U u) | 接收两个泛型参数,分别为T,U |
package lambda; import org.junit.Test; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; /** * @autour zdc * @create 2020-03-20-20:48 */ public class _Test1 { @Test public void test() { /* final*/ double num = 1.8; Consumer<String> consumer = str -> System.out.println(str + num); consumer.accept("hello"); } @Test public void test2(){ Supplier<String> supplier = ()->"给你返回个String字符串,因为lambda只有一条语句 不用加{}"; System.out.println(supplier.get()); } @Test public void test3(){ Function<String,Integer> function = str->{ return Integer.parseInt(str); }; System.out.println(function.apply("123")); } @Test public void test4(){ Predicate<String> predicate = str->{ if(str.length()<10) return false; return true; }; System.out.println(predicate.test("2h2eheh3e")); } }
jdk1.7之前 匿名内部类(内部类)引用局部变量,局部变量必须为final 。jdk1.8后 默认会加上final
1.内部类引用外部类局部变量时,外部类的局部变量一定要用final修饰。
因为内部类和外部类的局部变量生命周期不一样,外部类方法执行完该局部变量可能会被释放掉,但该方法中的内部类可能还在执行(如线程),还要使用该变量,所以外部类变量设置为final的,变成常量,使用的时候内部类可以复制一个副本过去,相当于就不使用该局部变量了。
我们还可以从JVM的角度去解释这个现象,在编译期的时候,所有的类都会被编译成Class文件。内部类也会被编译成Class文件。但是上面的例子的内部类编译会和我们所知道的普通类编译方式会有些不同。
大多数的类在编译的时候,需要知道每个方法需要为其所有的局部变量分配多少内存。所以它会去检查方法内定义的变量,从而确定此方法到真正运行的时候需要在栈中开辟多少内存。但这只是计算需要多少内存,真正分配内存是在运行期。
所以当内部类使用外部类的局部变量时,在编译期也会给它分配额外的内存,并给它赋与外部类相等的值,但是此变量已经不是外部的局部变量了。在内存的角度上看,匿名内部类的i实际上不是外部的i,它们使用的内存空间都不同,只是它们的值相同。
其实本质上来说,完全可以当作两个不同的变量去使用,但是Java的设计人员可能想要保持一致性,因为Java的初学者在不了解其中真正的机制的时候,会以为他们就是同一个变量,所以干脆就把变量强制定义为final,这样变量就不能被重新赋值,营造一种他们是同一个变量的“假象”。
2.内部类引用外部类的成员变量时,成员变量不一定要用final修饰,因为它不需要像上面说的那样要需在栈中重新开辟一个空间,而是内部类持有外部类的引用,可以使用外部类类名.this.变量名的方式。
体会lambda时,感悟到,我们可以先使用函数接口作为参数放进到一个函数中,函数的具体实现到我们使用lambda实现该函数接口上再用到。很灵活。
(4)方法引用 注意 函数式接口的泛型(抽象方法的参数类型和返回值类型)要和方法名的参数列表和返回值类型一致
若Lambda体中的内容已经有方法实现了,可以使用方法引用。--lambda表达式的另外一种表现形式。
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
public static String getName(){ return "zdc"; } public String getNameNotStatic(){ return "zdc"; } @Test public void test5(){ Consumer<String> consumer = str-> System.out.println(str); //对象::实例方法 Consumer<String> consumer1 = System.out::println; //泛型 与 调用方法返回值类型一致 sout(string!!!) //类名::静态方法 Supplier<String> supplier = _Test1::getName; //对象::实例方法名 _Test1 test1 = new _Test1(); Supplier<String> supplier2 = test1::getNameNotStatic; //类名::实例方法 (遵守规则 第一个参数是实例方法的调用者,第二个参数是实例方法的参数时才可以使用。) BiPredicate<String,String> biPredicate = String::equals; BiPredicate<String,String> biPredicate1 = (x,y)->x.equals(y); }
(5)构造器引用 类名::new 调用构造器的参数列表要和函数式接口中抽象方法的参数列表保持一致。
@Test public void test6(){
Supplier<Person> supplier = ()->new Person();
Supplier<Person> supplier1 = Person::new;
Person person = supplier1.get();
BiFunction<String,Integer,Person> biFunction = (x,y)->new Person(x,y);
BiFunction<String,Integer,Person> biFunction1 = Person::new;
Person zzz = biFunction1.apply("zzz", 83);
} class Person{ private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } 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; } }
(6)数组引用
@Test public void test7(){ Function<Integer,String[]> function = x->new String[x]; Function<Integer,String[]> function1 = String[]::new; String[] strings = function1.apply(100); }