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(),函数描述符要符合函数式接口的函数描述符。合理的使用能使你的代码更加简洁。

这次,就写这些了。

陆续更新。

猜你喜欢

转载自www.cnblogs.com/zhuyan521/p/10251842.html