JDK8-新特性&Lambda表达式&内置函数式接口&方法引用

目录

1、JDK8-新特性

2、Lambda 表达式

2.1 lambda的由来

2.2 初体验lambda表达式

2.3 lambda表达式的语法

2.4 无参无返回值的Lambda

2.5 有参有返回值

2.6 Lambda表达式的省略写法

2.7 Lambda表达式使用的前提

3. 内置函数式接口

3.1 内置函数式接口的由来

3.2 消费型函数式接口Consumer

3.3 供给型函数式接口---Supplier

3.3 函数型函数式接口---Function,r>

3.4 断言型函数式接口--Predicate

4. 方法引用

4.1 方法引用的由来

4.2 方法引用的类型

4.3 静态方法引用

4.4 实例方法引用

4.5 对象方法引用

4.6 构造方法引用


1、JDK8-新特性

  • Lambda 表达式:Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)
  • 函数式接口:指的是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,这样的接口可以隐式转换为 Lambda 表达式
  • 方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码
  • 默认方法:默认方法就是一个在接口里面有了一个实现的方法
  • Stream API:新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
  • Optional 类:Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
  • Date Time API:加强对日期与时间的处理。
  • Nashorn, JavaScript 引擎:Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

2、Lambda 表达式

2.1 lambda的由来

public class Test01 {
    public static void main(String[] args) {
        //开启一个线程 该构造函数需要传递一个Runnable类型的接口参数
        Thread thread = new Thread(new My());
        thread.start();//开启线程
        //匿名内部类
        Thread thread1=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("通过匿名内部类实现线程任务");
            }
        });
        thread1.start();//开启线程

    }
}
class My implements  Runnable{

    @Override
    public void run() {
        System.out.println("使用实现类来完成------->线程任务");
    }
}

分析:

  1. Thread类需要一个Runnable接口作为参数,其中的抽象方法run方法是用来指定线程任务内容的核心

  2. 为了指定run方法体,不得不需要Runnable的实现类

  3. 为了省去定义一个Runnable 的实现类,不得不使用匿名内部类

  4. 必须覆盖重写抽象的run方法,所有的方法名称,方法参数,方法返回值不得不都重写一遍,而且不能出错,

  5. 而实际上,我们只在乎方法体中的代码.

我们可以使用lambda表达式来完成上面的功能。 

2.2 初体验lambda表达式

  //lambda表达式.
        Runnable runnable1=()->{
            System.out.println("这是lambda表达式完成线程任务");
        };
        Thread thread2=new Thread(runnable1);
        thread2.start();

2.3 lambda表达式的语法

(参数列表)->{}
():参数列表
->:连接符 连接的是参数以及方法体。
{}: 方法体。

2.4 无参无返回值的Lambda

public class Test02 {
    public static void main(String[] args) {
 //主函数调用fun方法。第一种:创建UserService接口的实现类,并创建该实现类对象。
          //第二种: 匿名内部类的方式
//          UserService userService=new UserService() {
//              @Override
//              public void show() {
//                  System.out.println("这是匿名内部类的show方法的实现");
//              }
//          };
//          fun(userService);
          //第三种lambda表达式:--该接口必须为函数式接口
                 UserService userService=()->{
             System.out.println("lambda表示的show方法");
         };
         fun(userService);
    }
    public static void fun(UserService userService){//UserService userService=
        userService.show();
    }
}
//函数式接口-->里面有且仅有一个抽象方法。--只有这种接口才能使用lambda表达式。
interface UserService{
    public void show();
}

2.5 有参有返回值

public class Test03 {
    public static void main(String[] args) {
        List<Person> personList=new ArrayList<>();
        personList.add(new Person("张三",15));
        personList.add(new Person("李四",5));
        personList.add(new Person("王五",65));
        personList.add(new Person("赵六",45));
        personList.add(new Person("田七",35));
        //对集合中的元素按照年龄排序。小到大
        System.out.println(personList);
        //Collections:集合工具类。--匿名内部类
//        Comparator<Person> comparator=new Comparator<Person>() {
//            @Override //如果是0表示相同 大于0表示o1大于02
//            public int compare(Person o1, Person o2) {
//                return o1.getAge()-o2.getAge();
//            }
//        };
//        Collections.sort(personList,comparator);
//        System.out.println(personList);
        Comparator<Person> comparator=(o1,o2)->{ 
            //就是对函数式接口中抽象方法的简写。
          return o1.getAge()-o2.getAge();
        };
          Collections.sort(personList,comparator);
          System.out.println(personList);
    }
}
class Person{
     private String name;
     private Integer age;

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

    public Person() {
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

2.6 Lambda表达式的省略写法

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

  1. 小括号内的参数类型可以省略[]

  2. 如果小括号内有且仅有一个参数,则小括号可以省略

  3. 如果大括号内有且仅有一个语句,可以同时省略大括号,return 关键字及语句分号。

public class Test05 {
    public static void main(String[] args) {
        USB u=(str)-> str.toUpperCase();//lambda表达式:
//        USB u=new USB() {//匿名内部类对接口中抽象方法的个数没有任何要求.
//            @Override
//            public String toUpper(String str) {
//                return null;
//            }
//
//            @Override
//            public String toLower(String str) {
//                return null;
//            }
//        };
        fun(u);
    }
    public static void fun(USB usb){
        String s = usb.toUpper("hello");
        System.out.println(s);
    }
}
interface USB{
    public String toUpper(String str);
//    public String toLower(String str);
}

2.7 Lambda表达式使用的前提

Lambda表达式的语法是非常简洁的,但是Lambda表达式不是随便使用的,使用时有几个条件要特别注意

  1. 方法的参数或局部变量类型必须为接口才能使用Lambda

  2. 接口中有且仅有一个抽象方法(@FunctionalInterface)

3. 内置函数式接口

要想使用lambda表达式它的前提就是必须是函数式接口。

3.1 内置函数式接口的由来

public class Test {

    public static void main(String[] args) {
           Operation o=arr->{
               int sum=0;
               for(int s:arr){
                   sum+=s;
               }
               return sum;
           };
            fun(o);
    }
    public static void fun(Operation operation){
        int[] arr={1,2,3,4};
        int s = operation.getSum(arr);
        System.out.println("数组的和:"+s);
    }
}
@FunctionalInterface
interface Operation{
     public int getSum(int[] arr);
}

分析:

我们知道使用Lambda表达式的前提是需要有函数式接口,而Lambda表达式使用时不关心接口名,抽象方法名。只关心抽象方法的参数列表和返回值类型。因此为了让我们使用Lambda表达式更加的方便,在JDK中提供了大量常用的函数式接口. 大多数无需自己再定义函数式接口,而可以直接使用jdk内置的函数式接口。分成四类

 

3.2 消费型函数式接口Consumer

适合有参数,但是没有返回值的。

public class Test06 {
    public static void main(String[] args) {
        Consumer<Double> c=t->{
            System.out.println("今天洗脚花费:"+t+"元");
        };
        fun(c,200.0);
    }
    public static void fun(Consumer<Double> consumer,Double money){
          consumer.accept(money);
    }
}

3.3 供给型函数式接口---Supplier

无参,需要返回值的接口类。

public class Test06 {
    public static void main(String[] args) {
//        Consumer<Double> c=t->{
//            System.out.println("今天洗脚花费:"+t+"元");
//        };
//        fun(c,200.0);
         Supplier<Integer> s=()-> new Random().nextInt(10);
         fun2(s);
    }
    public static void fun2(Supplier<Integer> supplier){
        Integer a = supplier.get();
        System.out.println("结果:"+a);
    }


    public static void fun(Consumer<Double> consumer,Double money){
          consumer.accept(money);
    }
}

3.3 函数型函数式接口---Function<T,R>

T: 参数的泛型

R:返回值的泛型

public class Test {

    public static void main(String[] args) {
           Function<int[],Integer> o=arr->{
               int sum=0;
               for(int s:arr){
                   sum+=s;
               }
               return sum;
           };
            fun(o);
    }
    public static void fun(Function<int[],Integer> fun){
        int[] arr={1,2,3,4};
        int s = fun.apply(arr);
        System.out.println("数组的和:"+s);
    }
}

3.4 断言型函数式接口--Predicate

T: 参数

boolean:返回值类型 

public class Test06 {
    public static void main(String[] args) {
//        Consumer<Double> c=t->{
//            System.out.println("今天洗脚花费:"+t+"元");
//        };
//        fun(c,200.0);
//         Supplier<Integer> s=()-> new Random().nextInt(10);
//         fun2(s);
//          Function<String,String> fun=t->t.toUpperCase();
//          fun3(fun,"hello world");
          Predicate<String> p=t->t.length()>3;
          fun4(p,"欧阳锋"); //4
    }

    public static void fun4(Predicate<String> predicate,String name){
        boolean test = predicate.test(name);
        System.out.println("是否成年:"+test);
    }

    public static void fun3(Function<String,String> f,String str){
        String apply = f.apply(str);
        System.out.println("结果:"+apply);
    }
    public static void fun2(Supplier<Integer> supplier){
        Integer a = supplier.get();
        System.out.println("结果:"+a);
    }

    public static void fun(Consumer<Double> consumer,Double money){
          consumer.accept(money);
    }
}

4. 方法引用

特殊的lambda表达式,它是对lambda表达式的一种简写方式。

4.1 方法引用的由来

public class Test07 {
    public static void main(String[] args) {
           Consumer<int[]> c=t->{
                int sum=0;
                for(int a:t){
                    sum+=a;
                }
               System.out.println("数组的和:"+sum);
           };
           fun(c);
    }
    public static void fun(Consumer<int[]> consumer){
          int[] arr={1,2,3,4,5};
          consumer.accept(arr);
    }

    //求和方法
    public static void sum(int[] arr){
        int sum=0;
        for(int a:arr){
            sum+=a;
        }
        System.out.println("数组的和:"+sum);
    }
}

如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了:---方法引用。::

public class Test07 {
    public static void main(String[] args) {
//           Consumer<int[]> c=t->{
//                int sum=0;
//                for(int a:t){
//                    sum+=a;
//                }
//               System.out.println("数组的和:"+sum);
//           };
//        Consumer<int[]> c=(t)->Test07.sum(t); //
           Consumer<int[]> c= Test07::sum;
           fun(c);
    }
    public static void fun(Consumer<int[]> consumer){
          int[] arr={1,2,3,4,5};
          consumer.accept(arr);
    }

    //求和方法
    public static void sum(int[] arr){
        int sum=0;
        for(int a:arr){
            sum+=a;
        }
        System.out.println("数组的和:"+sum);
    }
}

4.2 方法引用的类型

4.3 静态方法引用

(args)->类名.静态方法(args).                   类名::staticMethod

当lambda表达式中方法体,只有一条语句,而这条语句是类名.静态方法。而静态方法的参数和lambda的参数一致时。

类名::静态方法

public class Test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(5);
        list.add(2);
        list.add(9);
        list.add(8);
        list.add(3);
       // Comparator<Integer> comparator = (o1,o2)->o1-o2;
       //Comparator<Integer> comparator = (o1,o2)->Integer.compare(o1,o2);
        Comparator<Integer> comparator = Integer::compare;
        Collections.sort(list,comparator);
        System.out.println(list);
    }
}

4.4 实例方法引用

(args) -> inst.instMethod(args)           inst::instMethod

实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用

public class Test1 {
    public static void main(String[] args) {
        //创建一个类对象
        Student student = new Student("芈原",22);
        //通过内置的函数接口,返回对象的名称。
       // Supplier<String> supplier = ()->student.getName(); //使用供给型接口,lambada表达式
        Supplier<String> supplier = student::getName;//实例方法引用
        String s = supplier.get();
        System.out.println(s);
        //观察:lambada表达式中有且仅有一条语句,方法调用语句。 -----实力方法引用特点:()->对象.普通方法()

        //函数型
        Function<Student,String> function = (t)->t.getName();
        String apply = function.apply(student);
        System.out.println(apply);//这里就无法使用方法的引用
    }
}
class Student{
    private String name;
    private Integer age;

    public Student() {
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public Integer getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(Integer age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

4.5 对象方法引用

lambda: (inst,args)->inst.普通方法(args): -------->类名::普通方法        类名::instMethod

若Lambda参数列表中的第一个参数是实例方法的参数调用者,而第二个参数是实例方法的参数时,可以使用对象方法引用。

public class Test2 {
    public static void main(String[] args) {
        //判断两个字符串是否一致
//        BiFunction<String, String, Boolean> biFunction = (t1, t2) -> t1.equals(t2);
//        Boolean apply = biFunction.apply("hello", "hello");
//        System.out.println(apply);

        //观察:符合对象方法引用
        BiFunction<String,String,Boolean> biFunction = String::equals;
        show(biFunction);
    }
    public static void show(BiFunction<String,String,Boolean> biFunction){
        Boolean apply = biFunction.apply("hello", "hell");
        System.out.println(apply);
    }
}

4.6 构造方法引用

(args) -> new 类名(args)------构造方法引用: 类名::new  

public class Test3 {
    public static void main(String[] args) {
//        Supplier<Student> supplier = ()->new Student();//lambada表达式
//        Student student = supplier.get();
//        System.out.println(student);

        //观察:调用的构造函数

//        Supplier<Student> supplier = Student::new;//构造方法引用
//        Student student = supplier.get();
//        System.out.println(student);

       // BiFunction<String,Integer,Student> biFunction = (n,a)->new Student(n,a);
        BiFunction<String,Integer,Student> biFunction = Student::new;
        Student st = biFunction.apply("郭子仪", 61);
        System.out.println(st);
    }
}

总结:

静态方法引用 类名::静态方法 lambda表达式: (参数)->类名.静态方法(参数)

实例方法引用:对象::实例方法 lambda表达式: (参数)->对象.实例方法(参数)

对象方法引用:类名::实例方法 lambda表达式: (参数1,参数2....)->参数1.实例方法(参数2..)

构造方法引用: 类名::new lambda表达式: (参数)->new 类名(参数);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值