java8实战之二Lambda表达式

Lambda表达式

总结:

  1. Lambda表达式可以理解为一种匿名函数:它没有名称,但有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常的列表。
  2. Lambda表达式让你可以简洁地传递代码。
  3. 函数式接口就是仅仅声明了一个抽象方法的接口。
  4. 只有在接受函数式接口的地方才可以使用Lambda表达式。
  5. Lambda表达式允许你直接内联,为函数式接口的抽象方法提供实现,并且将整个表达式作为函数式接口的一个实例。
  6. Java 8自带一些常用的函数式接口,放在java.util.function包里,包括Predicate、Function<T,R>、Supplier、Consumer和BinaryOperator等
  7. 为了避免装箱操作,对Predicate和Function<T, R>等通用函数式接口的原始类型特化:IntPredicate、IntToLongFunction等。
  8. 环绕执行模式(即在方法所必需的代码中间,你需要执行点儿什么操作,比如资源分配和清理)可以配合Lambda提高灵活性和可重用性。
  9. Lambda表达式所需要代表的类型称为目标类型。
  10. 方法引用让你重复使用现有的方法实现并直接传递它们。
  11. Comparator、Predicate和Function等函数式接口都有几个可以用来结合Lambda表达式的默认方法。

基本使用

Lambda 的基本语法是:(parameters) -> expression
或(请注意语句的花括号)(parameters) -> { statements; }
示例:

使用案例Lambda示例
布尔表达式(List<String> list) -> list.isEmpty()
创建对象() -> new Apple(10)
消费一个对象(Apple a) -> {System.out.println(a.getWeight());}
从一个对象中选择/抽取(String s) -> s.length()
组合两个值(int a, int b) -> a * b
比较两个对象(Apple a1, Apple a2) ->a1.getWeight().compareTo(a2.getWeight())
函数式接口使用Lambda

举个例子,从一个文件中读取一行所需的模板代码

public static String processFile() throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
            return br.readLine();
        }
    }
1、行为参数化

现在这段代码是有局限的。你只能读文件的第一行。如果你想要返回头两行,甚至是返回使用最频繁的词,该怎么办呢?在理想的情况下,你要重用执行设置和清理的代码,并告诉processFile方法对文件执行不同的操作。这听起来是不是很耳熟?是的,你需要把processFile的行为参数化。你需要一种方法把行为传递给processFile,以便它可以利用BufferedReader执行不同的行为。
传递行为正是Lambda的拿手好戏。那要是想一次读两行,这个新的processFile方法看起来又该是什么样的呢?基本上,你需要一个接收BufferedReader并返回String的Lambda。例如,下面就是从BufferedReader中打印两行的写法:

String result = processFile((BufferedReader br) -> br.readLine() + br.readLine()); 
2、创建一个函数式接口

Lambda仅可用于上下文是函数式接口的情况

@FunctionalInterface
public interface BufferedReaderProcessor {
    String process(BufferedReader b) throws IOException;
}
3、执行一个行为
public static String processFile(BufferedReaderProcessor p) throws
            IOException {
        try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
            return p.process(br);
        }
    }
4、传递 Lambda

现在你就可以通过传递不同的Lambda重用processFile方法,并以不同的方式处理文件了。

String oneLine = processFile((BufferedReader br) -> br.readLine()); 
String twoLines = processFile((BufferedReader br) -> br.readLine() + br.readLine()); 
Java API 中常用的函数式接口
Predicate
@FunctionalInterface
    public interface Predicate<T>{
        boolean test(T t);
    }
    public static <T> List<T> filter(List<T> list, Predicate<T> p) {
        List<T> results = new ArrayList<>();
        for(T s: list){
            if(p.test(s)){
                results.add(s);
            }
        }
        return results;
    }
    Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
    List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
Consumer
@FunctionalInterface
    public interface Predicate<T>{
        boolean test(T t);
    }
    public static <T> void forEach(List<T> list, Consumer<T> c) {
        for (T i : list) {
            c.accept(i);
        }
    }
    forEach(Arrays.asList(1,2,3,4,5), (Integer i) -> System.out.println(i));
Function
@FunctionalInterface
    public interface Function<T, R>{
        R apply(T t);
    }
    public static <T, R> List<R> map(List<T> list,
                                     Function<T, R> f) {
        List<R> result = new ArrayList<>();
        for(T s: list){
            result.add(f.apply(s));
        }
        return result;
    }
List<Integer> l = map(Arrays.asList("lambdas","in","action"),
 (String s) -> s.length());     

Lambdas及函数式接口的例子

使用案例Lambda示例对应的函数式接口
布尔表达式(List<String> list) -> list.isEmpty()Predicate<List<String>>
创建对象() -> new Apple(10)Supplier<Apple>
消费一个对象(Apple a) -> {System.out.println(a.getWeight());}Consumer<Apple>
从一个对象中选择/抽取(String s) -> s.length()Function<String, Integer>或ToIntFunction<String>
组合两个值(int a, int b) -> a * bIntBinaryOperator
比较两个对象(Apple a1, Apple a2) ->a1.getWeight().compareTo(a2.getWeight())Comparator<Apple>或BiFunction<Apple, Apple, Integer>或 ToIntBiFunction<Apple, Apple>
方法引用

方法引用让你可以重复使用现有的方法定义,并像Lambda一样传递它们。在一些情况下,比起使用Lambda表达式,它们似乎更易读,感觉也更自然。
先前:

inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

之后(使用方法引用和java.util.Comparator.comparing):

inventory.sort(comparing(Apple::getWeight)); 

Lambda及其等效方法引用的例子

Lambda等效的方法引用
(Apple a) -> a.getWeight()Apple::getWeight
() -> Thread.currentThread().dumpStack()Thread.currentThread()::dumpStack
(str, i) -> str.substring(i)String::substring
(String s) -> System.out.println(s)System.out::println
复合 Lambda 表达式
比较器复合(比较器链)
inventory.sort(comparing(Apple::getWeight).reversed().thenComparing(Apple::getCountry)); 
谓词复合
Predicate<Apple> redAndHeavyAppleOrGreen = redApple.and(a -> a.getWeight() > 150).or(a -> "green".equals(a.getColor()));

以上就是对 Lambda 表达式的理解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值