[关闭]
@zero1036 2017-08-16T08:44:24.000000Z 字数 2385 阅读 1327

Java8函数式编程

Java-Base


lambda表达式

闭包closure

一个lambda表达式通常必然包含3个部分:

如示例:

  1. Function<Integer, Integer> function = (x /*表达式参数*/) ->
  2. //代码块
  3. {
  4. record++; //外部变量
  5. return x + 1;
  6. };

以上例子的逻辑并没有问题,但实际编译不通过,报错record变量要求是final变量或有效的final变量。这是是JDK对lambda表达式的外部变量调用的约束。

约束原理:lambda表达式是一个闭包,闭包会复制外部变量,保留在闭包内部,如果闭包异步执行,即使外部变量在主线程中已经释放,但在表达式内该变量依然能被访问。

例如:

  1. int matches = 0;
  2. for(Path p : files)
  3. new Thread(() -> {if(p中包含某些属性) matches++;}).start(); //非法更改matches的值

变更lambda表达式中的变量不是线程安全的。假设有一系列并发的任务,每个线程都会更新一个共享的计数器。

因此,原则是:lambda表达式不能变更外部变量

补充:final variable比较好理解,有效的final变量如何理解?如下例,List为有效的final变量,一个有效的final变量被初始化后,就永远不会再被复制一个新值的变量,但问题是List是可变对象,如果多线程调用以下function,将会有并发问题。

  1. List<String> list = new ArrayList<>();
  2. Function<Integer, Integer> function = (x) ->
  3. {
  4. list.add("abc"); //list为有效的final变量
  5. ...
  6. };

this关键字

当在lambda表达式中使用this关键字,你会引用创建该lambda表达式的方法的this参数,以下面的代码为例:

  1. public class Application{
  2. public void doWork(){
  3. Runnable runner = () -> {....;System.out.println(this.toString());......};
  4. }
  5. }

表达式this.toString()会调用Application对象的toString()方法,而不是Runnable实例的toString()方法。在lambda表达式中使用this,与在其他地方使用this没有什么不同。lambda表达式的作用域被嵌套在doWork()方法中,并且无论this位于方法的何处,其意义都是一样的。

命名式与函数式的性能对比

待测试


函数式接口 Function interfaces

函数式接口

  1. //匿名类实现
  2. Thread thread1 = new Thread(new Runnable() {
  3. @Override
  4. public void run() {
  5. System.out.println("运行匿名类");
  6. }
  7. });
  8. //lambda表达式实现
  9. //Runnable标识@FunctionalInterface,为函数式接口,编译器会验证该接口是否满足函数式接口的要求,实质类似DotNet的Action
  10. Runnable runnable = () -> System.out.println("运行表达式");
  11. Thread thread = new Thread(runnable);
  12. System.out.println("开始");
  13. thread.start();
  14. thread1.start();

java.util.function新包

可以参看以下例子:

  1. // Function<T, R> -T作为输入,返回的R作为输出
  2. Function<String,String> function = (x) -> {System.out.print(x+": ");return "Function";};
  3. System.out.println(function.apply("hello world"));
  4. //Predicate<T> -T作为输入,返回的boolean值作为输出
  5. Predicate<String> pre = (x) ->{System.out.print(x);return false;};
  6. System.out.println(": "+pre.test("hello World"));
  7. //Consumer<T> - T作为输入,执行某种动作但没有返回值
  8. Consumer<String> con = (x) -> {System.out.println(x);};
  9. con.accept("hello world");
  10. //Supplier<T> - 没有任何输入,返回T
  11. Supplier<String> supp = () -> {return "Supplier";};
  12. System.out.println(supp.get());
  13. //BinaryOperator<T> -两个T作为输入,返回一个T作为输出,对于“reduce”操作很有用
  14. BinaryOperator<String> bina = (x,y) ->{System.out.print(x+" "+y);return "BinaryOperator";};
  15. System.out.println(" "+bina.apply("hello ","world"));
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注