读书笔记——《Java 8实战》系列之Lambda表达式(二)

转自 http://www.wxueyuan.com/blog/articles/2017/10/16/1508115706213.html

上一篇博客中,我们介绍了Lambda表达式的基本概念以及语法。在本片博客中,我们将继续和大家分享一些关于Lambda表达式的知识。

函数式接口只定义了一个抽象方法,该抽象方法的签名也被称为函数描述符。为了应用不同的Lambda表达式,Java 的库设计师们提供了一些常用的函数式接口,比如我们之前接触到的Comparable,Runnable和Callable。Java 8在此基础上,又增加了几个新的函数接口,接下来我们就一起来了解它们一下。

java.util.function.Predicate

Predicate接口定义了一个名叫test的抽象方法,他接受泛型T的对象,并返回一个Boolean值。看过本系列读书笔记的同学们是不是觉得很眼熟?没错,它和我们在行为参数化博客中自己创建的函数式接口一模一样。当我们需要使用一个传入对象并返回布尔值的表达式时,直接使用它吧。

    @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);

java.util.function.Consumer

Consumer定义了一个accept抽象方法。它接受泛型类型对象T,并没有返回任何值。如果我们需要访问T类型的对象,并对其执行某些操作,我们就可以使用这个接口了

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

    public static <T> void forEach(List<T> list, Consumer<T> c){
        for(T t:list){
            c.accept(t);
        }
    }

    forEach(Arrays.asList(1,2,3,4,5), (Integer i)-> System.out.println(i));

java.util.function.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<R>();
        for(T t: list){
            result.add(f.apply(t));
        }
    }

    List<Integer> list = map(Arrays.asList("hello","world","Jesmin"),(String s) -> s.length());

接下来我们来一起总结一些常用的Lambda的例子以及可以使用的函数式接口。

使用案例Lambda示例对应的函数式接口
布尔表达式(List<String> list) -> list.isEmpty()Predicate<List<String>>
创建对象( ) -> new String()Supplier<String>
消费一个对象( String s ) -> { System.out.println(s);}Consumer<String>
从某个对象中抽取属性( Student s ) -> s.getHeight()Function<Student,Integer>或ToIntFunction<Student>
组合两个值( int a, int b ) -> a*b IntBinaryOperator
比较两个对象( Student s1, Student s2 ) -> s1.getHeight().compareTo(s2.getHeight())Comparator<Student>

迄今为止,我们所介绍的所有Lambda表达式都只用到了其主体中的参数,如使用了学生实例的身高属性

    List<Student> result = filter(students, (Student s) -> s.getHeight()>=180));

但实际上Lambda表达式也允许我们使用自由变量(不允许当作参数,可以在主体中使用外层作用域中定义的变量),如:

    int num = 5;
    Runnable r = () -> System.out.println(num);

Lambda表达式同样能够在主体中使用实例变量和静态变量。但是局部变量必须显式声明为final或事实上为final,换句话说,Lambda表达式主体中使用过的局部变量,不能被再次赋值。

错误示范:

    int num = 5;
    Runnable r = () -> System.out.println(num);
    //此处编译会报错,因为被Lambda表达式主体引用的局部变量num被再次赋值了
    num = 3;
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值