java8实战:Lambda 表达式

Java 8 Lambda 表达式

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。

lambda表达式是一段可以传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为。

语法

lambda 表达式的语法格式如下:

expression = (variable) -> action
  • variable: 这是一个变量,一个占位符。像x,y,z,可以是多个变量。
  • action: 这里我称它为action, 这是我们实现的代码逻辑部分,它可以是一行代码也可以是一个代码片段

可以看到Java中lambda表达式的格式:参数、箭头、以及动作实现,当一个动作实现无法用一行代码完成,可以编写
一段代码用 {} 包裹起来。

 编写一个线程用Lambda表达式可以简单实现如下:

Runnable r = () -> System.out.println("do something.");

 这代码看起来很酷,你可以看到我们用()和->的方式完成了这件事,这是一个没有名字的函数,也没有人和参数,再简单不过了。使用 -> 将参数和实现逻辑分离,当运行这个线程的时候执行的是->之后的代码片段,且编译器帮助我们做了类型推导;这个代码片段可以是用 {} 包含的一段逻辑。

lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

lambda表达式可以包含多个参数,例如

int sum = (x, y) -> x + y;

这时候我们应该思考这段代码不是之前的x和y数字相加,而是创建了一个函数,用来计算两个操作数的和。
后面用int类型进行接收,在lambda中为我们省略去了return。

public class Java8Tester {
   public static void main(String args[]){
      Java8Tester tester = new Java8Tester();

      // 类型声明
      MathOperation addition = (int a, int b) -> a + b;

      // 不用类型声明
      MathOperation subtraction = (a, b) -> a - b;

      // 大括号中的返回语句
      MathOperation multiplication = (int a, int b) -> { return a * b; };

      // 没有大括号及返回语句
      MathOperation division = (int a, int b) -> a / b;

      System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
      System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
      System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));

      // 不用括号
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);

      // 用括号
      GreetingService greetService2 = (message) ->
      System.out.println("Hello " + message);

      greetService1.sayMessage("Runoob");
      greetService2.sayMessage("Google");
   }

   interface MathOperation {
      int operation(int a, int b);
   }

   interface GreetingService {
      void sayMessage(String message);
   }

   private int operate(int a, int b, MathOperation mathOperation){
      return mathOperation.operation(a, b);
   }
}

函数式接口

 函数式接口是只有一个方法的接口,用作lambda表达式的类型。前面写的例子就是一个函数式接口,来看看jdk中的Runnable源码

@FunctionalInterface
public interface Runnable {

    public abstract void run();
}

 这里只有一个抽象方法run,实际上你不写public abstract也是可以的,在接口中定义的方法都是public abstract的。同时也使用注解 @FunctionalInterface告诉编译器这是一个函数式接口,当然你不这么写也可以,标识后明确了这个函数中只有一个抽象方法,当你尝试在接口中编写多个方法的时候编译器将不允许这么干。

java8函数式接口分类

接口 参数 返回值 类型 示例
Consumer T void 消费型接口 输出一个值
Supplier None T 供给型接口 工厂方法
Function T R 函数型接口 获取List对象的名字
Predicate T boolean 断言型接口 你成年了吗

 伟大的jdk设计者为我们准备了java.util.function包如下图:
这里写图片描述

默认方法

 在Java语言中,一个接口中定义的方法必须由实现类提供实现。但是当接口中加入新的API时,
实现类按照约定也要修改实现,而Java8的API对现有接口也添加了很多方法,比如List接口中添加了sort方法。如果按照之前的做法,那么所有的实现类都要实现sort方法,JDK的编写者们一定非常抓狂。幸运的是我们使用了Java8,这一问题将得到很好的解决。

 在Java8种引入新的机制,支持在接口中声明方法同时提供实现。这令人激动不已,你有两种方式完成:
1. 在接口内声明静态方法
1. 指定一个默认方法。

我们来看看在JDK8中上述List接口添加方法的问题是如何解决的:

default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

Lambda 表达式实践

下面写个简单的实例,体验下四种函数式接口的使用姿势:

package java8.examples;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class FunctionInterfaceDemo {

    @FunctionalInterface
    interface Predicate<T> {
        boolean test(T t);
    }

    public static boolean dePredicate(int age, Predicate<Integer> predicate) {
        return predicate.test(age);
    }

    //消费型接口示例
    public static void donation(Integer money, Consumer<Integer> consumer){
        consumer.accept(money);
    }

    //供给型接口示例
    public static List<Integer> supply(Integer num, Supplier<Integer> supplier){
        List<Integer> resultList = new ArrayList<Integer>()   ;
        for(int x = 0; x < num; x++)
            resultList.add(supplier.get());
        return resultList ;
    }

    //函数型接口
    public static Integer convert(String str, Function<String, Integer> function) {
        return function.apply(str);
    }

    //断言型接口
    public static List<String> filter(List<String> fruit, Predicate<String> predicate){
        List<String> f = new ArrayList<>();
        for (String s : fruit) {
            if(predicate.test(s)){
                f.add(s);
            }
        }
        return f;
    }

    public static void main(String[] args) {
        boolean isAdult = dePredicate(20, x -> x >= 18);
        System.out.println(isAdult);

        //消费型接口示例
        donation(1000, money -> System.out.println("好心的XX为lx捐赠了"+money+"元")) ;

        //供给型接口示例
        List<Integer> list = supply(10,() -> (int)(Math.random()*100));
        list.forEach(System.out::println);

        //函数型接口
        Integer value = convert("28", x -> Integer.parseInt(x));

        //断言型接口
        List<String> fruit = Arrays.asList("香蕉", "哈密瓜", "榴莲", "火龙果", "水蜜桃");
        List<String> newFruit = filter(fruit, (f) -> f.length() == 2);
        System.out.println(newFruit);
    }
}

猜你喜欢

转载自blog.csdn.net/Pengjx2014/article/details/79259855