@zero1036
2017-08-16T08:44:24.000000Z
字数 2385
阅读 1327
Java-Base
一个lambda表达式通常必然包含3个部分:
如示例:
Function<Integer, Integer> function = (x /*表达式参数*/) ->
//代码块
{
record++; //外部变量
return x + 1;
};
以上例子的逻辑并没有问题,但实际编译不通过,报错record变量要求是final变量或有效的final变量。这是是JDK对lambda表达式的外部变量调用的约束。
约束原理:lambda表达式是一个闭包,闭包会复制外部变量,保留在闭包内部,如果闭包异步执行,即使外部变量在主线程中已经释放,但在表达式内该变量依然能被访问。
例如:
int matches = 0;
for(Path p : files)
new Thread(() -> {if(p中包含某些属性) matches++;}).start(); //非法更改matches的值
变更lambda表达式中的变量不是线程安全的。假设有一系列并发的任务,每个线程都会更新一个共享的计数器。
因此,原则是:lambda表达式不能变更外部变量。
补充:final variable比较好理解,有效的final变量如何理解?如下例,List为有效的final变量,一个有效的final变量被初始化后,就永远不会再被复制一个新值的变量,但问题是List是可变对象,如果多线程调用以下function,将会有并发问题。
List<String> list = new ArrayList<>();
Function<Integer, Integer> function = (x) ->
{
list.add("abc"); //list为有效的final变量
...
};
当在lambda表达式中使用this关键字,你会引用创建该lambda表达式的方法的this参数,以下面的代码为例:
public class Application{
public void doWork(){
Runnable runner = () -> {....;System.out.println(this.toString());......};
}
}
表达式this.toString()会调用Application对象的toString()方法,而不是Runnable实例的toString()方法。在lambda表达式中使用this,与在其他地方使用this没有什么不同。lambda表达式的作用域被嵌套在doWork()方法中,并且无论this位于方法的何处,其意义都是一样的。
待测试
函数式接口
//匿名类实现
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("运行匿名类");
}
});
//lambda表达式实现
//Runnable标识@FunctionalInterface,为函数式接口,编译器会验证该接口是否满足函数式接口的要求,实质类似DotNet的Action
Runnable runnable = () -> System.out.println("运行表达式");
Thread thread = new Thread(runnable);
System.out.println("开始");
thread.start();
thread1.start();
Function<T, R>
: -T作为输入,返回的R作为输出,与DotNet的Function类似Predicate<T>
-T作为输入,返回的boolean值作为输出Consumer<T>
- T作为输入,执行某种动作但没有返回值Supplier<T>
- 没有任何输入,返回T BinaryOperator<T>
-两个T作为输入,返回一个T作为输出,对于“reduce”操作很有用可以参看以下例子:
// Function<T, R> -T作为输入,返回的R作为输出
Function<String,String> function = (x) -> {System.out.print(x+": ");return "Function";};
System.out.println(function.apply("hello world"));
//Predicate<T> -T作为输入,返回的boolean值作为输出
Predicate<String> pre = (x) ->{System.out.print(x);return false;};
System.out.println(": "+pre.test("hello World"));
//Consumer<T> - T作为输入,执行某种动作但没有返回值
Consumer<String> con = (x) -> {System.out.println(x);};
con.accept("hello world");
//Supplier<T> - 没有任何输入,返回T
Supplier<String> supp = () -> {return "Supplier";};
System.out.println(supp.get());
//BinaryOperator<T> -两个T作为输入,返回一个T作为输出,对于“reduce”操作很有用
BinaryOperator<String> bina = (x,y) ->{System.out.print(x+" "+y);return "BinaryOperator";};
System.out.println(" "+bina.apply("hello ","world"));