java Lambda表达式的应用步骤

1.lambda表达式

1.1 函数式编程思想概述

      面向对象的思想:

             做一件事,找到一个能解决这个事情的对象,调用对象的方法,完成事情。

    函数式编程的思想:

            只要能获取到结果,谁去做,怎么做都不重要,重视的事结果,不是过程。

1.2 冗余的Runnable代码

      当需要启动一个线程去完成任务时,通常会通过java.lang.Runnable接口定义任务的内容,并且使用java.lang.Thread类来启动该线程。

public class Demo01 {
    public static void main(String[] args) {
        //使用匿名类
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程任务执行!");
            }
        },"线程1").start();
    }
}

      分析:对于Runnable的匿名内部类用法

             (1)Thread类要将Runnable接口作为参数,Runnable接口中的抽象方法run是执行线程任务的核心。

             (2)为了制定run方法的执行体,就要Runnable接口的实现类。

             (3)为了省去在类的定义中的implement的麻烦,就要使用匿名内部类。

             (4)必须覆盖重写run方法的方法名、参数、返回值类型,并且不能写错

       然而,实际上似乎只有run方法的方法体才是我们需要的关键。

1.3 lambda的更优写法

      借助java8的全新语法,Runnable接口的匿名内部类写法可以通过更简单的lambda表达式完成:

public class Demo01 {
    public static void main(String[] args) {
        new Thread(()-> System.out.println("多线程任务执行"),"新线程").start();
    }
}

  1.4 回顾匿名内部类

          在代码中的核心部分为:

()-> System.out.println("多线程任务执行")

         为了更加容易理解lambda表达式,我们先看传统的代码。

  使用实现类:

         要启动一个线程,需要创建一个Thread类对象,并且调用对象的start方法,为了指定线程中执行的内容,需要调用Thread类的构造方法。

            public  Thread(Runnable   target)

       为了获取Runnable接口的实现对象,可以为该接口定义一个实现类RunnableImpl:

public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        System.out.println("多线程任务执行");
    }
}

        然后创建该实现类的对象作为Thread类的构造参数target:

public class Demo03 {
    public static void main(String[] args) {
        RunnableImpl ri=new RunnableImpl();
        new Thread(ri).start();
    }
}

       使用匿名内部类:

            这个RunnableImpl类只是为了实现Runnable接口而存在的,在整个代码中仅仅被用了一次,索引我们可以使用匿名对象的语法,就可以省去定义RunnableImpl类的步骤。

public class Demo03 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多线程任务执行");
            }
        }).start();
    }
}

          使用匿名内部类的优劣处:

               一方面使用匿名内部类 可以帮助我们省去定义实现类的步骤,可以匿名内部类的语法确实复杂。

         语法分析:

             Runnable接口中的只有一个run方法的定义:

                   public  abstract void run():

              该方法:

             (1) 无参数:不需要任何条件就可以执行

              (2)无返回值:该方法不会产生任何结果

               (3)方法体:根剧具体方法的步骤来制定

但是同样的语法体现在lambda表达式中,更加简单:

()-> System.out.println("多线程任务执行")

               (1)前面的一对小括号(),就是run方法的参数(无),代表不需要任何条件。

               (2)中间的一个箭头代表将前面的参数传递给后面的代码。

               (3)后面的输出语句就为run方法的方法体

1.5 lambda表达式的标准格式

        Lambda省去面向对象的条条框框,格式有3个部分组成:

                 (1)一些参数

                 (2)一个箭头

                 (3)一段代码

        Lambda表达式的标准格式;

                  (参数类型  参数名称)  —> { 代码语句 }

       格式说明:

             (1)小括号中的语法和传统方法的参数列表一致:无参数则留空;多个参数用逗号隔开。

             (2)——>  是新引进 的语法格式,代表指向动作。

              (3)大括号内的语法与传统方法体要求基本一致。

        练习:给定一个厨子Cook 接口,内含唯一的抽象方法makeFood ,且无参数、无返回值。如下:

public interface Cook {
    void makefood();
}

         使用lambda表达式完成  

public class Demo04 {
    public static void main(String[] args) {
       invokeCook(()-> System.out.println("吃饭了"));
    }
    private static void invokeCook(Cook cook){
        cook.makefood();
    }
}

        小括号为空,代表Cook接口中makefood抽象方法的参数为空,大括号代表makefood的方法体。

1.6 lambda的参数和返回值

        需求:使用数组存储person对象,对数组的person对象使用Arrays中的sort方法通过年龄进行升序排列。

           java.tuil.Comparator<T>接口中的使用场景代码,其中的抽象方法定义为:

public abstract int compare(T o1, T o2);

          当需要对一个对象数组进行排序时,Arrays.sort方法需要一个Comparator接口实例来指定排序的规则。

     定义一个person对象

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

       传统的代码写法对person对象进行排序:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
public class Demo05 {
    public static void main(String[] args) {
        Person[] arry={
                new Person("路飞",20),
                new Person("索隆",19),
                new Person("山治",21)
        };
        //匿名内部类
        Comparator<Person> comp=new Comparator<Person>(){

            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge()-o2.getAge();
            }
        };
        Arrays.sort(arry,comp);//第二个参数为排序规则,即Comparator接口实例
        for (Person person : arry) {
            System.out.println(person);
        }
    }
}

    代码分析:

            (1)为了排序, Arrays.sort 方法需要排序规则,即Comparator 接口的实例,抽象方法compare 是关键;

             (2)为了指定compare 的方法体,不得不需要Comparator 接口的实现类;

             (3)为了省去定义一个ComparatorImpl 实现类的麻烦,不得不使用匿名内部类;

             (4)必须覆盖重写抽象compare 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;

   实际上,只有参数和方法体才是关键。

       使用lambda表达式进行排序:

import java.util.Arrays;
import java.util.Comparator;
public class Demo05 {
    public static void main(String[] args) {
        Person[] arry={
                new Person("路飞",20),
                new Person("索隆",19),
                new Person("山治",21)
        };
        Arrays.sort(arry,(Person o1, Person o2)->{return o1.getAge()-o2.getAge();});
        for (Person person : arry) {
            System.out.println(person);
        }
    }
}

      1.7 练习 :使用Lambda标准格式(有参有返回值)

           需求:  给定一个计算器Calculator 接口,内含抽象方法calc 可以将两个int数字相加得到和值:

public interface Calculator {
    int calc(int a,int b);
}
public class Demo06 {
    public static void main(String[] args) {
        invokecalc(120,130,(int a,int b)->{
            return a+b;
        });
    }

    private static void invokecalc(int a,int b,Calculator c) {
        int result=c.calc(a,b);
        System.out.println("结果是:"+result);
    }
}

     小括号代表Calculator接口calc抽象方法的参数,大括号带边calc的方法体。

1.8 Lambda 省略格式

      可推导即可省略

           凡是可以通过上下文推导得知的信息就可以省略。例如上式的写法:

    public static void main(String[] args) {
        invokecalc(120,130,(a,b)->a+b);
    }

       省略的规则:

              在lambda表达式的标准格式基础上,使用省略写法的规则为;

              (1)小括号中的参数类型可以省略

            (2)如果小括号中有且只有一个参数,则小括号可以省略。

            (3)如果大括号中有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字、语句分号。

1.9 Lambda表达式的使用前提

           Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:

          (1)使用lambda必须具有接口,并且要求接口中有且仅有一个抽象方法。

               无论是JDK内置的Runnable 、Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一
                时,才可以使用Lambda。

           (2)使用lambda必须具有上下文推断。

                  也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

            注:有且仅有一个抽象方法的接口,称为函数式接口。

 

              

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值