Java8新特性---Lambda表达式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/paditang/article/details/79554228

Lambda表达式

Lambda表达式的本质只是一个语法糖,由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。

基本语法:

(parameters -> expression)  
(parameters -> {expression;})

简单例子:

//仅用三行代码完成 排序后输出列表
public static void main(String[] args) {
        List<Integer> integers = Arrays.asList(5, 6, 8, 2, 3, 4, 7, 8, 10);
        Collections.sort(integers, (i1,i2) -> i1.compareTo(i2));
        integers.forEach(i -> System.out.println(i));
    }

为什么使用lambda

应用场景如下:根据不同的策略,选出满足策略条件的苹果进行分类,而策略经常变更。

public interface MatchInterface<T> {

    public boolean match(T t);

}
public class MatchClient {

    public static <T> boolean match(T t, MatchInterface<T> s) {
        return s.match(t);
    }

    public static void main(String[] args) {
        Apple apple = new Apple("red", 150);

        // 匿名类实现
        match(apple, new MatchInterface<Apple>() {
            public boolean match(Apple apple) {
                return "red".equals(apple.getColor());
            }
        });

        // lambda表达式实现
        match(apple,  tmp -> "red".equals(tmp.getColor()));

        match(apple, (Apple tmp) -> {
            return "red".equals(tmp.getColor());
        });
    }
}

如上代码所示,即便使用匿名类的形式,比起lambda表达式的实现还是复杂许多。更别说定义实现类。显然可以看出lambda表达式简洁的特性。但是相较而言,无法复用也是lambda表达式对比实现类的缺陷。然后lambda本身就是针对这种较少使用的场景,因而这也不成问题。

对比匿名类和lambda表达式,很容易看出:

->左边部分是接口抽象方法的参数,而右边是抽象方法的具体实现。

函数式接口

对于一个接口,无论定义了多少个默认方法,只要只定义了一个抽象方法,那么这个接口就是函数式接口。

lambda表达式使用在函数式接口的参数位置,现在我们再回头看示例排序迭代输出代码:

Collections.sort(integers, (i1,i2) -> i1.compareTo(i2));

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
}

public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }

public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

@FunctionalInterface
public interface Comparator<T> { 
      int compare(T o1, T o2);
}

通过lambda表达式实现Comparator接口,达到排序的目的。

integers.forEach(i -> System.out.println(i));

default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

显然这也是对列表的每个元素做accept操作。即输出到控制台。

使用@FunctionalInterface注解可以提前校验接口是否是函数式接口

源码中提供的几个函数式接口:

  • Predicate:接受泛型T对象,返回boolean
  • Consumer:接受泛型T对象,没有返回
  • Function:接受泛型T对象,返回R对象

进一步简洁化

方法引用

如果一个Lambda代表的只是直接调用这个方法,那最好使用名称来调用。

构造三种方法引用:

  • 指向静态方法的方法引用

    (args) -> className.staticMethod(args)
    
    className::staticMethod

    示例代码:

    public class MethodInvokingClient {
    
    public static List<Integer> transformString2Integer(List<String> list, Function<String, Integer> f) {
        List<Integer> nums = new ArrayList<>();
        for (String string : list) {
            nums.add(f.apply(string));
        }
        return nums;
    }
    
    public static void main(String[] args) {
    
        List<String> list = Arrays.asList("1", "3", "5");
    
        transformString2Integer(list, (String s) -> Integer.parseInt(s));
    
        transformString2Integer(list, Integer::parseInt);
    
    }
    }
  • 指向任意类型实例方法的方法引用

    (arg0,rest) -> arg0.instanceMethod(rest)
    
    ClassName::instanceMethod                 //ClassName是arg0的类型

    示例代码:

    public static List<Integer> calculateStringLength(List<String> list, Function<String, Integer> f) {
        List<Integer> nums = new ArrayList<>();
        for (String string : list) {
            nums.add(f.apply(string));
        }
        nums.forEach(i -> System.out.println(i));
        return nums;
    
    }
    
    public static void main(String[] args) {
    
        List<String> list = Arrays.asList("1", "3", "5");
    
        calculateStringLength(list, s -> s.length());
    
        calculateStringLength(list, String::length);
    
    }
  • 指向现有对象的实例方法的方法引用

    (args) -> anotherInstance.instanceMethod(args)
    
    anotherInstance::instanceMethod

    示例代码:

    public static int contais(List<String> list, Function<String, Boolean> f){
        int count = 0;
        for (String string : list) {
            if(f.apply(string)){
                count++;
            }
        }
        return count;
    }
    
    public static void main(String[] args) {
    
        List<String> list = Arrays.asList("1", "3", "5");
        List<String> anotherList = Arrays.asList("1", "4", "5");
    
        contais(list, s -> anotherList.contains(s));
    
        contais(list, anotherList::contains);
    
    }

复合lambda

  • 比较器复合

    List<Integer> integers = Arrays.asList(5, 6, 8, 2, 3, 4, 7, 8, 10);
    Comparator<Integer> com = (i1,i2) -> i1.compareTo(i2);
    integers.sort(com.reversed());
  • 谓词复合

    Apple apple = new Apple("red", 150);
    Predicate<Apple> match = tmp -> "red".equals(tmp.getColor());
    Predicate<Apple> match2 = match.and(tmp -> tmp.getWeight() > 200);
    match2.test(apple);
  • 函数复合

    Function<Integer, Integer> f = x -> x+1;
        Function<Integer, Integer> g = x -> x*2;
        Function<Integer, Integer> h = f.compose(g);
        int r = h.apply(1);
    //结果为3

猜你喜欢

转载自blog.csdn.net/paditang/article/details/79554228