Lambda

函数式编程语言操纵代码片段就像操作数据一样容易。 虽然 Java 不是函数式语言,但 Java 8 Lambda 表达式和方法引用 (Method References) 允许你以函数式编程。

 

新旧对比

通过下面的案例引入匿名内部类, lambda表达式, 方法引用, 作出对比

 

// functional/Strategize.java
interface Strategy {
  String approach(String msg);
}

class Soft implements Strategy {
  public String approach(String msg) {
    return msg.toLowerCase() + "?";
  }
}

class Unrelated {
  static String twice(String msg) {
    return msg + " " + msg;
  }
}

public class Strategize {
  Strategy strategy;
  String msg;
  Strategize(String msg) {
    strategy = new Soft();      // [1] 在 Strategize 中,Soft 作为默认策略,在构造函数中赋值。
    this.msg = msg;
  }

  void communicate() {
    System.out.println(strategy.approach(msg));
  }

  void changeStrategy(Strategy strategy) {
    this.strategy = strategy;
  }

  public static void main(String[] args) {
    Strategy[] strategies = {
      new Strategy() {               // [2]创建一个匿名内部类,代码显得比较冗余
        public String approach(String msg) {
          return msg.toUpperCase() + "!";
        }
      },
      msg -> msg.substring(0, 5), // [3]Java8的 Lambda表达式。由箭头 -> 分隔开参数和函数体,
                                    箭头左边是参数,箭头右侧是从Lambda返回的表达式,即函数体。
                                    这实现了与定义类、匿名内部类相同的效果,但代码少得多。
                                        
      Unrelated::twice // [4]Java 8 的方法引用,由 :: 区分。
                         在 :: 的左边是类或对象的名称,在 :: 的右边是方法的名称,但没有参数列表
    };
    Strategize s = new Strategize("Hello there");
    s.communicate();
    for(Strategy newStrategy : strategies) {
      s.changeStrategy(newStrategy); // [5] 在使用默认的 Soft strategy 之后,
                                       我们逐步遍历数组中的所有 Strategy,
                                      并使用changeStrategy()方法将每个Strategy放入变量s中
      s.communicate(); // [6]每次调用 communicate() 都会产生不同的行为,
                       具体取决于此刻正在使用的策略代码对象。我们传递的是行为,而非仅数据
    }
  }
}

 

output:

 

hello there?

HELLO THERE!

Hello

Hello there Hello there

 

Lambda表达式


带有参数变量的表达式,是一段可以传递的代码,可以被一次或多次执行

是一种精简的字面写法,其实就是把匿名内部类中“一定”要做的工作省略掉,然后由JVM通过推导把简化的表达式还原

 

格式:  (parameters参数) -> expression表达式或方法体

 

paramaters:

类似方法中的形参列表,这里的参数是函数式接口里的参数

 

-> 

可理解为“被用于”的意思

 

方法体:

可以是表达式也可以代码块,是函数式接口里方法的实现

如果负责运算的代码无法用表达式表示,可以使用编写方法实现

但必须用{}包围并按需明确使用 return语句

 

 

// functional/LambdaExpressions.java
interface Description {
  String brief();
}

interface Body {
  String detailed(String head);
}

interface Multi {
  String twoArg(String head, Double d);
}

public class LambdaExpressions {

    //当只用一个参数,可以不需要括号 ()
  static Body bod = h -> h + " No Parens!"; // [1]

    //正常情况使用括号 () 包裹参数,
    //为了保持一致性,也可以使用括号 ()包裹单个参数,虽然这种情况并不常见。
  static Body bod2 = (h) -> h + " More details"; // [2]。 
                                                      
                                                    
    //如果没有参数,则必须使用括号 () 表示空参数列表
  static Description desc = () -> "Short info"; // [3]
    
    //对于多个参数,将参数列表放在括号 () 中
  static Multi mult = (h, n) -> h + n; // [4]

    /**到目前为止,所有 Lambda 表达式方法体都是单行。 
     该表达式的结果自动成为 Lambda 表达式的返回值,在此处使用 return 关键字是非法的。 
     这是 Lambda 表达式缩写用于描述功能的语法的另一种方式。
   */
    
    //如果在 Lambda 表达式中确实需要多行,则必须将这些行放在花括号中。 
    //在这种情况下,就需要使用 return。
  static Description moreLines = () -> { // [5]
    System.out.println("moreLines()");
    return "from moreLines()";
  };

  public static void main(String[] args) {
    System.out.println(bod.detailed("Oh!"));
    System.out.println(bod2.detailed("Hi!"));
    System.out.println(desc.brief());
    System.out.println(mult.twoArg("Pi! ", 3.14159));
    System.out.println(moreLines.brief());
  }
}

 

output:

Oh! No Parens!

Hi! More details

Short info

Pi! 3.14159

moreLines()

from moreLines()

 

posted @ 2020-07-08 10:27  你在谁的风景里a  阅读(262)  评论(0编辑  收藏  举报