Lambda
大致说明
个人理解为它是内部类的一种简写,相当于新建了对应接口的实例对象
Lambda样例
public class JavaTest {
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(5, 3, 2, 1, 4);
// 升序排序
Collections.sort(list1, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println(list1); //[1, 2, 3, 4, 5]
System.out.println("--------------------------------------");
List<Integer> list2 = Arrays.asList(5, 3, 2, 1, 4);
// Collections.sort(list2, (Integer o1, Integer o2) -> {return o1 - o2;}); //简写
Collections.sort(list2, (o1, o2) -> o1 - o2); //简写
System.out.println(list2); //[1, 2, 3, 4, 5]
}
}
可以看到Collections.sort(List, Comparator)的Comparator为接口(函数式接口),要使用接口需要实现接口内的抽象方法,这里体现为匿名内部类,而Lambda可以将匿名内部类实例化(接口不能被实例化其实是有一个实现了此接口的匿名内部类实例化暂且叫实例化)简化,也就是对内部类实例化的简写。
Lambda语法格式
(抽象方法的参数)->{抽象方法的实现的方法体}
- ()为接口抽象方法的参数
- ->
- {}为抽象方法的实现的方法体
以Collections.sort(List, Comparator)中的Comparator内部类举例:
public class JavaTest {
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(5, 3, 2, 1, 4);
// 原排序方式
Collections.sort(list1, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
/**
* 原排序方式的sort有两个参数,一个为要排序的list,
* 另一个为Comparator的匿名内部类的实例化对象(接口不能被实例化其实是有一个实现了此接口的匿名内部类实例化暂且叫实例化)
* Lambda简化了Comparator接口的实例化,语法等效与下方的comparator2。
*/
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
};
Collections.sort(list1, comparator);
// Lambda写法
Comparator<Integer> comparator2 = (Integer o1, Integer o2) -> {return o1 - o2;};
Collections.sort(list1, comparator2);
}
}
这里实现的方法为compare(),compare()的参数为(Integer o1, Integer o2),方法体为 {return o1 - o2;}
Lambda语法为:(Integer o1, Integer o2)->{return o1 - o2;},等效于新建了一个对应接口Comparator的实例对象
Lambda语法简化
(Integer o1, Integer o2)->{return o1 - o2;}
(Integer o1, Integer o2):
- 可以省略参数类型说明==>(o1, o2)
- 如果参数只有一个时可以省略(),无参时不能省略
{return o1 - o2;}:
- 方法体内只有一行代码可以省略{}
- 可以省略return
- 可以省略;
==>o1-o2
函数式接口
在上面实现的内部类对应的是接口类,用Lambda简写的接口类中只能有一个抽象方法,其他方法的数量不影响(jdk8以后接口中可以存在默认方法和静态方法)。
对于这种接口java用@FunctionalInterface表明这个接口是函数式接口。(此注解只是起说明作用,只要接口符合只有一个抽象方法这个条件,不管有没有注解都能在内部类时用Lambda)
@FunctionalInterface
public interface TestInterface {
boolean test(int num);
}
public class JavaTest {
public void fun(List<Integer> list, TestInterface testInterface) {
for (Integer i : list) {
if (testInterface.test(i)) {
System.out.println(i);
}
}
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
List<Integer> list = Arrays.asList(5, 3, 2, 1, 4);
// 接口实现方法:判断int是否大于3
javaTest.fun(list, x -> x > 3); //简写
// javaTest.fun(list, (int x) -> {return x > 3;}); //不进行省略
// 内部类写法
// javaTest.fun(list, new TestInterface() {
// @Override
// public boolean test(int num) {
// return num > 3;
// }
// });
}
}
java8中规范的四大函数式接口
四大函数式接口说明
- Consumer :消费型接口 void accept(T t);
- Supplier :供给型接口 T get();
- Function<T,R> :函数型接口 R apply(T t);
- Predicate :断言型接口 boolean test(T t);
四大函数式接口举例
1.Consumer :消费型接口 void accept(T t);代码
public class JavaTest {
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
List<Integer> list = Arrays.asList(5, 3, 2, 1, 4);
javaTest.fun(list, x -> System.out.println("当前Consumer的accept实现为输出传入的参数:" + x)); //简写
// javaTest.fun(list, (Integer x) -> {System.out.println("当前Consumer的accept实现为输出传入的参数:" + x);}); //不进行省略
// 内部类写法
// javaTest.fun(list, new Consumer<Integer>() {
// @Override
// public void accept(Integer integer) {
// System.out.println("当前Consumer的accept实现为输出传入的参数:" + integer);
// }
// });
}
public void fun(List<Integer> list, Consumer<Integer> consumer) {
for (Integer i : list) {
consumer.accept(i);
}
}
}
结果输出:
当前Consumer的accept实现为输出传入的参数:5
当前Consumer的accept实现为输出传入的参数:3
当前Consumer的accept实现为输出传入的参数:2
当前Consumer的accept实现为输出传入的参数:1
当前Consumer的accept实现为输出传入的参数:4
2.Supplier :供给型接口 T get();代码
public class JavaTest {
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
javaTest.fun(() -> Math.random()*100); //简写
// javaTest.fun(() -> { return Math.random()*100;}); //不进行省略
//
// // 内部类写法
// javaTest.fun(new Supplier<Double>() {
// @Override
// public Double get() {
// return Math.random()*100;
// }
// });
}
public void fun(Supplier<Double> supplier) {
System.out.println(supplier.get());
}
}
结果输出:
31.392849957349746
3. Function<T,R> :函数型接口 R apply(T t);代码
public class JavaTest {
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
List<Integer> list = Arrays.asList(5, 3, 2, 1, 4);
javaTest.fun(list, x -> "Function的apply函数参数为:" + x); //简写
// javaTest.fun(list, (Integer x) -> {return "Function的apply函数参数为:" + x;}); //不进行省略
//
// // 内部类写法
// javaTest.fun(list, new Function<Integer, String>() {
// @Override
// public String apply(Integer integer) {
// return "Function的apply函数参数为:" + integer;
// }
// });
}
public void fun(List<Integer> list, Function<Integer, String> function) {
for (Integer i : list) {
System.out.println(function.apply(i));
}
}
}
结果输出:
Function的apply函数参数为:5
Function的apply函数参数为:3
Function的apply函数参数为:2
Function的apply函数参数为:1
Function的apply函数参数为:4
4. Predicate :断言型接口 boolean test(T t);代码
public class JavaTest {
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
List<Integer> list = Arrays.asList(5, 3, 2, 1, 4);
javaTest.fun(list, x -> x > 3); //简写
// javaTest.fun(list, (Integer x) -> {return x > 3;}); //不进行省略
//
// // 内部类写法
// javaTest.fun(list, new Predicate<Integer>() {
// @Override
// public boolean test(Integer integer) {
// return integer > 3;
// }
// });
}
public void fun(List<Integer> list, Predicate<Integer> predicate) {
for (Integer i : list) {
if (predicate.test(i) == true) {
System.out.println(i + "大于3");
}
else {
System.out.println(i + "小于等于3");
}
}
}
}
结果输出:
5大于3
3小于等于3
2小于等于3
1小于等于3
4大于3
方法内部类能访问方法内局部变量,但不能修改
这个感觉本质上为局部内部类/匿名内部类==》这两者都只能访问方法内的局部变量不能修改方法内的局部变量。
https://blog.csdn.net/Chill_Lyn/article/details/102534194
https://www.iteye.com/blog/feiyeguohai-1500108
匿名内部类访问方法成员变量需要加final的原因及证明
public class JavaTest {
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
List<Integer> list = Arrays.asList(5, 3, 2, 1, 4);
int a = 0;
List<Integer> list2 = new ArrayList<Integer>();
//简写
javaTest.fun(list, x -> {
// a = 2; //编译不通过-不能修改方法内局部变量
// list2 = new ArrayList<Integer>(); //编译不通过-不能修改方法内局部变量
System.out.println("访问方法内变量:" + a);
list2.add(2 + x);
return "Function的apply函数参数为:" + x;
});
//不进行省略
// javaTest.fun(list, (Integer x) -> {
a = 2; //编译不通过-不能修改方法内局部变量
list2 = new ArrayList<Integer>(); //编译不通过-不能修改方法内局部变量
//
// System.out.println("访问方法内变量:" + a);
// list2.add(2 + x);
// return "Function的apply函数参数为:" + x;
// });
// 内部类写法
// javaTest.fun(list, new Function<Integer, String>() {
// @Override
// public String apply(Integer integer) {
a = 2; //编译不通过-不能修改方法内局部变量
list2 = new ArrayList<Integer>(); //编译不通过-不能修改方法内局部变量
//
// System.out.println("访问方法内变量:" + a);
// list2.add(2 + integer);
// return "Function的apply函数参数为:" + integer;
// }
// });
System.out.println(list2);
}
public void fun(List<Integer> list, Function<Integer, String> function) {
for (Integer i : list) {
System.out.println(function.apply(i));
}
}
}
结果输出:
访问方法内变量:0
Function的apply函数参数为:5
访问方法内变量:0
Function的apply函数参数为:3
访问方法内变量:0
Function的apply函数参数为:2
访问方法内变量:0
Function的apply函数参数为:1
访问方法内变量:0
Function的apply函数参数为:4
[7, 5, 4, 3, 6]
方法引用
方法引用感觉就像(个人理解):
在实现函数式接口的抽象方法时,正巧某个地方的函数(称为a方法)与这个抽象方法想要实现的效果(称为b方法)一样,也就是我要实现的b方法所要写的语句其实是重复a方法的内容,那我把a方法拿过来直接用不行嘛。
可以通过方法引用来实现上述的效果。
方法引用就是拿别的地方的函数来当作函数式接口的抽象方法的实现方法。
方法引用的分类
类型 | 语法 |
---|---|
静态方法引用 | 类名::静态方法名 |
实例方法引用 | 实例::实例方法名 |
对象方法引用 | 类名::实例方法名 |
构造方法引用 | 类名::new / 类名[]::new |
方法引用的举例
1. 静态方法引用
类名::静态方法名
public class JavaTest {
public static String javaTestApply(Integer o) {
return "apply内容为:" + o;
}
public String fun(Function<Integer, String> function, Integer i) {
return function.apply(i);
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
// Function函数式接口内部类
Function<Integer, String> function = new Function<Integer, String>() {
@Override
public String apply(Integer o) {
return "apply内容为:" + o;
}
};
String funReturn = javaTest.fun(function, 1);
System.out.println(funReturn); //apply内容为:1
// 简写为Lambda
Function<Integer, String> function2 = o -> "apply内容为:" + o;
// Function<Integer, String> function2 = (Integer o) -> {return "apply内容为:" + o;};// 完整Lambda
String funReturn2 = javaTest.fun(function2, 2);
System.out.println(funReturn2); //apply内容为:2
// 方法引用(静态方法引用):Javatest的javaTestApply方法就是我想要的接口抽象方法的实现
Function<Integer, String> function3 = JavaTest::javaTestApply;
String funReturn3 = javaTest.fun(function3, 3);
System.out.println(funReturn3); // apply内容为:3
}
}
2. 实例方法引用
实例::实例方法名
public class JavaTest {
public String javaTestApply(Integer o) {
return "apply内容为:" + o;
}
public String fun(Function<Integer, String> function, Integer i) {
return function.apply(i);
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
// Function函数式接口内部类
Function<Integer, String> function = new Function<Integer, String>() {
@Override
public String apply(Integer o) {
return "apply内容为:" + o;
}
};
String funReturn = javaTest.fun(function, 1);
System.out.println(funReturn); //apply内容为:1
// 简写为Lambda
Function<Integer, String> function2 = o -> "apply内容为:" + o;
// Function<Integer, String> function2 = (Integer o) -> {return "apply内容为:" + o;};// 完整Lambda
String funReturn2 = javaTest.fun(function2, 2);
System.out.println(funReturn2); //apply内容为:2
// 方法引用(实例方法引用):Javatest的javaTestApply方法就是我想要的接口抽象方法的实现
Function<Integer, String> function3 = javaTest::javaTestApply;
String funReturn3 = javaTest.fun(function3, 3);
System.out.println(funReturn3); // apply内容为:3
}
}
3. 对象方法引用
类名::实例方法名==>接口抽象方法第一个参数对象对应的类名:: 接口抽象方法第一个参数对象的方法名
这点写法跟静态方法引用一样,但实际上调用的方法非static,相当于Lamdba表达式调用时,把第一个参数,作为实例再调用方法:
前提:Lambda 参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数。
代码1:接口抽象方法1参
public class Entity {
private String name;
public Entity(String name) {
this.name = name;
}
@Override
public String toString() {
return "Entity{" +
"name='" + name + '\'' +
'}';
}
}
public class JavaTest {
public String fun(Function<Entity, String> function, Entity testEntity) {
return function.apply(testEntity);
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
//原写法,内部类
Entity testEntity = new Entity("内部类");
String resultStr = javaTest.fun(new Function<Entity, String>() {
@Override
public String apply(Entity testEntity) {
return testEntity.toString();
}
}, testEntity);
System.out.println(resultStr); //Entity{name='内部类'}
// Lambda
Entity testEntity2 = new Entity("Lambda");
String resultStr2 = javaTest.fun(o-> o.toString(), testEntity2);
// String resultStr2 = javaTest.fun((Entity o)-> {return o.toString();}, testEntity2); // 完整Lambda
System.out.println(resultStr2); //Entity{name='Lambda'}
// 方法引用
// 抽象方法第一个参数为Entity,抽象方法的实现为Entity的toString方法
Entity testEntity3 = new Entity("方法引用");
String resultStr3 = javaTest.fun(Entity::toString, testEntity3);
System.out.println(resultStr3); //Entity{name='方法引用'}
}
}
代码2:接口抽象方法2参
public class JavaTest {
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
List<Integer> list = Arrays.asList(5, 3, 2, 1, 4);
// 原写法,内部类
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
// Lambda写法
list.sort((o1, o2) -> o1.compareTo(o2));
list.sort((Integer o1, Integer o2) -> {return o1.compareTo(o2);}); //完整Lambda
// 对象方法引用
// 抽象方法第一个参数为Integer,抽象方法的实现为Integer的compareTo方法
//lambda的第一个参数o1 是实例方法compareTo()的调用者
//且lambda的第二个参数o2 是compareTo()的参数
list.sort(Integer::compareTo);
System.out.println(list);
}
}
代码3,接口抽象方法3参
public class Entity {
public String entityFun(Integer i, String j) {
return i + j;
}
}
@FunctionalInterface
public interface InterfaceTest {
String interfaceFun(Entity entity, Integer i, String str);
}
public class JavaTest {
public void javaTestFun(InterfaceTest interfaceTest, Entity entity, String str) {
int i = new Random().nextInt();
String returnStr = interfaceTest.interfaceFun(entity, i, str);
System.out.println(returnStr);
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
Entity entity = new Entity();
// 原写法,内部类
javaTest.javaTestFun(new InterfaceTest() {
@Override
public String interfaceFun(Entity entity, Integer i, String str) {
return entity.entityFun(i, str);
}
}, entity, "内部类"); //==>1207138315内部类
// Lambda
javaTest.javaTestFun((o, i, s) -> o.entityFun(i, s), entity, "Lambda"); //==>805409447Lambda
// javaTest.javaTestFun((Entity o, Integer i, String s) -> {return o.entityFun(i, s);}, entity, 2, "--2"); // 完整Lambda
// 接口抽象方法第一个参数为Entity, 抽象方法的实现为Entity的entityFun方法
javaTest.javaTestFun(Entity::entityFun, entity, "方法引用"); //==>1393022061方法引用
}
}
代码3:接口抽象方法1参
public class Entity {
public int entityFun() {
return 1;
}
}
@FunctionalInterface
public interface InterfaceTest {
int interfaceFun(Entity entity);
}
public class JavaTest {
public void javaTestFun(InterfaceTest interfaceTest, Entity entity) {
interfaceTest.interfaceFun(entity);
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
Entity entity = new Entity();
// 内部类
javaTest.javaTestFun(new InterfaceTest() {
@Override
public int interfaceFun(Entity entity) {
return entity.entityFun();
}
}, entity);
//Lambda
javaTest.javaTestFun(o -> o.entityFun(), entity);
javaTest.javaTestFun((Entity o) -> {return o.entityFun();}, entity); //完整Lambda
//对象方法引用
// 接口抽象方法的第一个参数为Entity,接口的抽象方法实现方法为Entity的entityFun
javaTest.javaTestFun(Entity::entityFun, entity);
}
}
构造方法引用
构造对象(调用的是无参构造方法)
构造对象代码1
public class JavaTest {
public Entity fun(Supplier<Entity> supplier) {
return supplier.get();
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
// 内部类
Entity testEntity = javaTest.fun(new Supplier<Entity>() {
@Override
public Entity get() {
return new Entity();
}
});
System.out.println(testEntity);
// Lambda
Entity testEntity2 = javaTest.fun(()-> new Entity());
// Entity testEntity2 = javaTest.fun(()-> {return new Entity();}); // 完整Lambda
System.out.println(testEntity2);
// 方法引用
Entity testEntity3 = javaTest.fun(Entity::new);
System.out.println(testEntity3);
}
}
构造对象代码2
public class JavaTest {
public List<Integer> fun(Supplier<List<Integer>> supplier) {
return supplier.get();
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
// 内部类
List<Integer> integerList = javaTest.fun(new Supplier<List<Integer>>() {
@Override
public List<Integer> get() {
return new ArrayList<Integer>();
}
});
// Lambda
List<Integer> integerList2 = javaTest.fun(()-> new ArrayList<Integer>());
// List<Integer> integerList2 = javaTest.fun(()-> {return new ArrayList<Integer>();}); // 完整Lambda
// 方法引用
List<Integer> integerList3 = javaTest.fun(ArrayList<Integer>::new);
}
}
4.构造数组
构造数组的抽象方法需要有一个参数来定义数组的长度。
public class Entity {
}
public class JavaTest {
public Entity[] fun(Function<Integer, Entity[]> function, Integer i) {
return function.apply(i);
}
public static void main(String[] args) {
JavaTest javaTest = new JavaTest();
// 内部类
Entity[] entitieArr = javaTest.fun(new Function<Integer, Entity[]>() {
@Override
public Entity[] apply(Integer integer) {
return new Entity[integer];
}
}, 1);
System.out.println(entitieArr.length); //1
// Lambda
Entity[] entitieArr2 = javaTest.fun((o)-> new Entity[o], 2);
// Entity[] entitieArr2 = javaTest.fun((Integer o)-> {return new Entity[o];}, 2); // 完整Lambda
System.out.println(entitieArr2.length); //2
// 方法引用
Entity[] entitieArr3 = javaTest.fun(Entity[]::new, 3);
System.out.println(entitieArr3.length); //3
}
}
https://www.cnblogs.com/jixp/articles/10541947.html
https://blog.csdn.net/qq_37176126/article/details/81273195
https://blog.csdn.net/wenzhi20102321/article/details/79796624
List操作
Lambda学习