在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

利用java8新特性实现类似javascript callback特性

2017-2-7 13:41| 发布者: zhangjf| 查看: 432| 评论: 0

摘要: Java8的新特性之一,就是首次引入了函数式编程Lambda表达式,按oracle的说法,是为了引导java向函数式编程的方向发展。 在JDK1.8中,多了一个包,java.util.function,这里主要用到了这个包下面的两个接口:ConsumerT ...

Java8的新特性之一,就是首次引入了函数式编程Lambda表达式,按oracle的说法,是为了引导java向函数式编程的方向发展。

在JDK1.8中,多了一个包,java.util.function,这里主要用到了这个包下面的两个接口:

  1. Consumer<T> //Represents an operation that accepts a single input argument and returns no result.
  2. Function<T,R> //Represents a function that accepts one argument and produces a result.
复制代码

要解释清楚这个问题,首先得从lambda表达式说起

(x,y)->doSomethingWith(x,y);

这句话就是一个lambda表达式的例子;"->"是Java8新定义的一个操作符,操作符左边代表lambda表达式接收的参数,这里它接收了两个参数,x和y;表达式右边是函数操作,也就是对这两个变量执行某种操作。如x+y,x*y等。

简单的解释了一下java8的lambda表达式,接下来进入正题:

在java8中,function包下面的所有接口都描述了一种预定义的lambda表达式类型,换句话说,就是可以通过声名接口类型的变量为lambda赋值,从而达到函数参数化的目的,这样说可能比较抽象,看代码

  1. public class LambdaDemo {
  2. public static void adapter(Function<String, String> function) {
  3. String message = "Hello World";
  4. System.out.println(function.apply(message));
  5. }
  6. public static void main(String[] args) {
  7. Function<String, String> function1 = (str) -> {
  8. return str.toUpperCase();
  9. };
  10. Function<String, String> function2 = (str) -> {
  11. return str.toLowerCase();
  12. };
  13. adapter(function1);
  14. adapter(function2);
  15. }
  16. }
复制代码

仔细体会上面的代码,函数adaper这里表示对字符串进行某种适配并将它打印出来,而具体的适配方式是通过参数传过来的,我们来看看运行结果:

  1. HELLO WORLD
  2. hello world
复制代码

和预期的完全一样,如果你能看懂上面的代码,我相信你已经基本明白了java8的函数式接口用法。

下面我针对上面提到的两个接口做一下解释:

所有的接口都是泛型定义的,泛型的作用在于类型推断,也就是说你指定了lambda的类型,那么他接收的参数的类型就是确定的,编译器就可以推断lambda的类型。事实上,在“->”运算符左边括号内的参数都是“匿名”的,你既无需考虑它们的引用,也无需事先声名它们,它们只在当前lambda表达式内作用,并且类型已经确定。再深入思考一点,如果你熟悉接口重载,你可能觉得这和泛型一样,是一块语法糖,事实上并非如此,Oracle为了引导java向函数式编程的方向发展,放弃了简单的接口重载,而是通过动态编译实现的。

再说说这两个接口的区别:

Consumer 中文译作“消费者”,它通过接口下的accept方法,接收唯一的参数,并执行操作;参数和调用该方法的上下文是无关的,也就是说对变量执行的操作不影响原上下文中的变量;

Function 接口则可以通过调用apply方法返回一个值,从而供之后调用。

要解释清楚这一问题,还得靠代码:

  1. public class ContextDemo {
  2. public static String transform(String str) {
  3. return str.concat(" World");
  4. }
  5. public static void main(String[] args) {
  6. Function<String, String> function = (str) -> {
  7. return transform(str);
  8. };
  9. Consumer<String> consumer = (str) -> {
  10. str = transform(str);
  11. };
  12. String msg = "Hello";
  13. System.out.println(msg);
  14. consumer.accept(msg);
  15. System.out.println(msg);
  16. msg = function.apply(msg);
  17. System.out.println(msg);
  18. }
  19. }
复制代码

运行结果:

  1. Hello
  2. Hello
  3. Hello World
复制代码

可见,Consumer并没有影响到它的上下文,它用的参数是变量的“副本”;而不是变量的指针。

接下来说说类似js中的callback();

对于一项功能,如果我们能够提供多个参数,我们倾向于使用函数或者方法来实现;但是如果我们需要用到多个参数,由于函数至多只有一个返回值,所以此时采用方法的思想我们需要多个函数或者方法,这时最简单的就是将方法传过去,而不用返回,类似的场景在JS中非常常见

  1. function doSomething(callback){
  2. var a = 1;
  3. var b = 2;
  4. callback(a,b);
  5. }
  6. doSomething(function(a,b){
  7. alert(a + b);
  8. });
复制代码

jQuery Ajax方法中success场景下的data就是一个典型的callback,现在java也可以实现类似的效果,从而提高代码重用率

  1. public class CallbackDemo {
  2. public static void main(String[] args) {
  3. sayHello((msg) -> {
  4. System.out.println(msg);
  5. });
  6. sayHello((msg) -> {
  7. System.out.println(msg.toUpperCase());
  8. });
  9. sayHello((msg) -> {
  10. System.out.println(msg.replaceAll("o", "0"));
  11. });
  12. }
  13. public static void sayHello(Consumer<String> callback) {
  14. String msg = "Hello World";
  15. callback.accept(msg);
  16. }
  17. }
复制代码

运行结果如下:

  1. Hello World
  2. HELLO WORLD
  3. Hell0 W0rld
复制代码

初来乍到,有错误还望批评指正。

来自: http://my.oschina.net/u/2541538/blog/538400

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-9 10:43

Copyright 2015-2025 djqfx

返回顶部