• java8实战二------lambda表达式和函数式接口,简单就好


    一、Lambda

    可以把Lambda表达式理解为简洁地i表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还是一个可以抛出的异常列表。

    听上去,跟我们用的匿名类,匿名方法什么的很像。我们继续看看把。

    第一篇,我们做的事分苹果,这次我们给苹果根据重量来做个Comparator吧。

    先来以前的:

    1  Comparator<Apple> byWeight=new Comparator<Apple> () {
    2             @Override
    3             public int compare(Apple o1, Apple o2) {
    4                 return o1.getWeight ().compareTo (o2.getWeight ());
    5             }
    6         };

    用了lambda:

    1  Comparator<Apple> byWeight=(Apple a1,Apple a2)->a1.getWeight ().compareTo (a2.getWeight ());

    是不是很简单。简单讲一下lambda的格式,由lambda参数、箭头、lambda主体三部分组成;

    其中lambda参数也可以不用写类型,它会根据上下文自己判断类型,后面有例子出现。

    而lambda主题如果像以上表达式只有一句的话,可以不叫{},但有多条语句的话必须加{}。

    二、函数式接口

    1 public interface Pridicate<T>{
    2        boolean test(T t);
    3 }

    类似上面的接口一样,只定义一个方法的接口,我们称之为函数式接口。Runable,Comparator都是一个函数式接口。当然,并不是严格意义上的只有一个方法,还可以有default修饰的默认方法。

    函数式接口的抽象方法的签名基本上就是Lambda表达式的签名,称之为函数描述符。比如,Runable的run()方法,什么也不接收,什么也不返回,Runable可以作为run方法的签名。函数描述符为()->void 。给个栗子!

     1 public class Demo6 {
     2     public static void main(String[] args) {
     3         //old
     4        process (new Runnable () {
     5            @Override
     6            public void run() {
     7                System.out.println ("This is old");
     8            }
     9        });
    10        //new
    11         process (()-> System.out.println ("This is new "));
    12     }
    13     public static void process(Runnable r){
    14         r.run ();
    15     }
    16 }

    我们知道process()方法接收的是一个函数式接口,所以我们直接可以用lambda表达式来表示这个函数式接口,()表示不接受参数,lambda主体不返回参数,

    完成的功能和上面匿名是一样的。我再来个反例!

    1 Predicate<Apple> predicate=(Apple a)->a.getWeight ();
    2 //Bad return type in lambda expression: Integer cannot be converted to boolean

    Apple的getWeight是个Integer返回类型,而,我们需要的是一个boolean类型,所以报错。这里解释一下Predicate等类。

    (1)Predicate<T>定义了一个抽象方法test(),返回boolean值。后面可以用来做filter的条件。

             像上面的反例,加入我在Apple加一个方法

    1  public boolean islight(){
    2         if(this.getWeight ()>4){
    3             return false;
    4         }
    5         return true;
    6     }

    我们就可以写  Predicate<Apple> predicate=(Apple a)->a.islight (); 这样就不会报错。

    java8中常用的函数式接口:

    所谓原始类型转化,其实很容易理解,像IntToDoubleFunction: IntToDoubleFunction i=(int s)->s*1.0; 对传入的s返回double。不用声明泛型,根据字面意思

    int转double。

    此外,lambda其实能根据上下文推断传入参数的类型: IntToDoubleFunction i=s->s*1.0; 因为IntToDoubleFunction的函数描述符式T->R,它自动判断s是int。

    三、方法引用

    上文中我们设计了一个Predicate<Apple>来区分轻重的苹果,我们先来看看方法引用。

    1         Predicate<Apple> predicate=(Apple a)->a.islight ();
    2         //方法引用
    3         Predicate<Apple> predicate1=Apple::islight;

    我们看看,Apple的islight()方法是传入一个Apple,返回一个boolean。函数描述符为Apple->boolean。我们先写个自己的Predicate。

    1 class MyPredicate implements Predicate<Apple>{
    2     @Override
    3     public boolean test(Apple apple) {
    4         if (apple.islight ()){
    5             return true;
    6         }
    7         return false;
    8     }
    9 }

    使用函数式接口的进阶顺序是:(1)自己写实现类,(2) Predicate<Apple> predicate=a->a.islight (); 

                                                        (3) Predicate<Apple> predicate1=Apple::islight;  

    (2)和(3)都是直接用lambda表达式表示Predicate。而(3)中用方法引用,使得代码,更加简洁。

    我们应该注意:我们调的方法是Apple的islight(),函数描述符要符合函数式接口的函数描述符。合理的使用能使你的代码更加简洁。

    这次,就写这些了。

    陆续更新。

  • 相关阅读:
    .net core 2.2, new Bitmap出错 The type initializer for 'Gdip' threw an exception
    瑞萨单片机学习笔记(待续)
    Linux-GitLab安装及汉化
    mysql5.7 ibtmp1文件过大
    #和$的区别
    RTP封装h264
    一个项目同时需要向两个地址推送
    git命令
    echart绘制进度条、仪表盘、各种样式的折线图、饼图、环形图、地图等
    前端在实现类似控制台命令行或者告警信息提示时,需要保持滚动条始终停留在最新的信息位置,也就是最底部
  • 原文地址:https://www.cnblogs.com/zhuyan521/p/10251842.html
Copyright © 2020-2023  润新知