【Java8新特性 之Lambda】对接口的简单实现

一、Lambda简介

1.什么是Lambda?

Lambda是java8添加的一个新特性,说白了,Lambda就是一个匿名函数

2.为什么要使用Lambda?

使用Lambda可以对一个接口进行非常简洁的实现

问题来了:对接口的实现,我们可以写一个实现类或者匿名内部类来实现接口,为什么要用Lambda呢?下面我们来做个对比
补充:匿名内部类

public class program {
    public static void main(String[] args) {
        //方式1:接口实现类
        Comparator c = new MyComparator();
        //方式2:匿名内部类
        Comparator c1 = new Comparator() {
            @Override
            public int compare(int a, int b) {
                return a-b;
            }
        };
        //方式3:Lambda实现接口
        Comparator c2 = ((a, b) -> a-b);
    }
}

//第一种方式,接口实现类
class  MyComparator implements Comparator{
    @Override
    public int compare(int a, int b) {
        return a-b;
    }
}
//这个接口对两个int值数据进行对比
interface Comparator{
    int compare(int a,int b);
}

3.Lambda对接口的要求

虽然可以使用Lambda对某些接口进行简单的实现,但是并不是所有的接口都可以用Lambda表达式来实现。要求:接口中定义的必须要实现的抽象方法只能是一个

Java8对接口加了一个新特性:default

我们可以使用default对接口中的方法进行修饰,那么被default修饰的方法可以在接口中有一个默认实现的,你的实现类可以去实现它,也可以不去实现它,这个对我们的Lambda是没有影响的

4.@FunctionalInterface
修饰函数式接口的。函数式接口:接口中的抽象方法只有一个

@FunctionalInterface
interface Comparator{
    int compare(int a,int b);
}
二、Lambda基本语法

Lambda 表达式基础语法 :参数列表+方法体
():参数列表
{}:用来描述方法体 ->:Lambda运算符 读作:goes to

我们在讲Lambda语法之前,我们先自定义多个不同类型的接口,分别用Lambda来实现,分析不同的情况,结合这些接口来看看Lambda的语法

定义接口:

//1、无参无返回
public interface LambdaNoneReturnNoneParameter {
    void test();
}

//2.无返回值 单个参数
public interface LambdaNoneReturnSingleParameter {
    void test(int n);
}

//3.无返回值 多个参数
public interface LambdaNoneReturnMutipleParameter {
    void test(int a,int b);
}

//4.有返回值,没有参数
public interface LambdaSingleReturnNoneParameter {
    int test();
}

// 5.有返回值 单个参数
public interface LambdaSingleReturnSingleParameter {
    int test(int a);
}
//6.有返回值, 多参数
public interface LambdaSingleReturnMutipleParameter {
    int test(int a,int b);
}

Lambda来实现上述接口:

/**
 * 1.Lambda 表达式基础语法
 * 参数列表+方法体
 ():参数列表    {}:用来描述方法体   ->:Lambda运算符 读作:goes to
 */
public class Syntax1 {
    public static void main(String[] args) {
        //1.无返回 无参
        LambdaNoneReturnNoneParameter lambda1 = ()->{
            System.out.println("hello");
        };
        lambda1.test();//hello

        //2.无返回, 单个参数
        LambdaNoneReturnSingleParameter lambd2 = (int a)->{
            System.out.println(a);
        };
        lambd2.test(10);//10

        //3.无返回值多个参数
        LambdaNoneReturnMutipleParameter lambd3 = (int a,int b)->{
            System.out.println(a+" "+b);
        };
        lambd3.test(10,20);// 10 20

        //4.有返回 无参
        LambdaSingleReturnNoneParameter lambd4 = ()->{
            System.out.println("hello");
            return 100;
        };
        int re = lambd4.test();
        System.out.println(re);//100

        //5.有返回 单一参数
        LambdaSingleReturnSingleParameter lambd5 = (int a)->{
            return a*2;
        };
        int re1 = lambd5.test(10);
        System.out.println(re1);//20

        //6.有返回值 多个参数
        LambdaSingleReturnMutipleParameter lambd6 = (int a,int b)->{
            return a+b;
        };
        int re2 = lambd6.test(1,2);
        System.out.println(re2);
    }
}
三、Lambda基本语法精简
        //4.有返回 无参
        LambdaSingleReturnNoneParameter lambd4 = ()->{
            System.out.println("hello");
            return 100;
        };
        int re = lambd4.test();
        System.out.println(re);//100
        //5.有返回 单一参数
        LambdaSingleReturnSingleParameter lambd5 = (int a)->{
            return a*2;
        };
        int re1 = lambd5.test(10);
        System.out.println(re1);//20

        //6.有返回值 多个参数
        LambdaSingleReturnMutipleParameter lambd6 = (int a,int b)->{
            return a+b;
        };
        int re2 = lambd6.test(1,2);
        System.out.println(re2);

我们分析下上面这部分,我们看到每个方法的实现部分都有:return返回值;为什么呢?因为我们在定义接口的时候定义了抽象方法,返回值类型不是void,那么方法在结束的就必须返回结果。
我们单纯的看上面的Lambda表达式,它没有在任何地方定义返回值类型,之所以方法的实现部分需要返回值类型,因为我们接口中抽象方法定义的,抽象方法不仅定义了返回值类型,还定义了参数列表,所以我们就可以对其精简:

import tulun.Lambda.LambdaNoneReturnSingleParameter;
import tulun.Lambda.LambdaSingleReturnMutipleParameter;
import tulun.Lambda.LambdaSingleReturnNoneParameter;

public class Syntax2 {
    public static void main(String[] args) {
          //语法精简
          //1.参数
          //由于接口的抽象方法定义了参数的类型和数量,所以在Lambda表达式中,参数类型可以省略
          //备注:如果需要省略参数类型,要么都省略,要么都别省略

        //6.有返回值 多个参数
        LambdaSingleReturnMutipleParameter lambd6 = (a,b)->{
            return a+b;
        };
        int re2 = lambd6.test(1,2);
        System.out.println(re2);

        //2.参数小括号
        //如果参数列表只有一个参数,则小括号可以省略
        
        LambdaNoneReturnSingleParameter lambd2 =  a->{
            System.out.println(a);
        };
        lambd2.test(10);//10
        
        //3.方法大括号
        //如果说方法体中只有一条语句,则大括号可以省略
        LambdaNoneReturnSingleParameter lambd3 =  a-> System.out.println(a);
        lambd2.test(10);//10
        
        //4.如果说方法体中唯一的一条语句是返回语句,则大括号可以省略,同时要省略return
        LambdaSingleReturnNoneParameter lambd4 = ()-> 10;
        
        
        LambdaSingleReturnMutipleParameter lambd5 = (a,b)->a+b;
    }
}
四、Lambda进阶

1.方法引用
可以快速的将一个Lambda表达式的实现指向一个已经实现的方法
语法: 方法的隶属者:方法名

package tulun.Lambda.Syntax;

import tulun.Lambda.LambdaSingleReturnSingleParameter;

public class Syntax3 {
    public static void main(String[] args) {
        //方法引用:
        //可以快速的将一个Lambda表达式的实现指向一个已经实现的方法
        //语法:  方法的隶属者:方法名
        //注意:参数数量和类型一定要和接口中定义的方法一致  返回值类型也要和接口中定义的方法一致
        
        //LambdaSingleReturnSingleParameter lambd1 = a -> a+=2;
       // LambdaSingleReturnSingleParameter lambd2 = a -> a+=2;
        
        LambdaSingleReturnSingleParameter lambda1 = a->change(a);
        //方法引用
        LambdaSingleReturnSingleParameter lambda2 = Syntax3::change;
        
    }
    public static int change(int a){
        return a*=2;
    }
}

2.构造方法的引用

先创建一个People类

public class Person {
    String name;
    int age;
    //无参构造
    public Person() {
        System.out.println("无参构造");
    }
    //有参构造
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("有参构造");
    }
}

构造方法的引用表示:

public class Syntax4 {
    public static void main(String[] args) {

        PersonCreater creater = ()-> new Person();

        //构造方法的引用
        PersonCreater creater1 = Person::new;

        //测试
        Person a = creater1.getPerson();//无参构造

        PersonCreater2 creater2 = Person::new;
        Person b = creater2.getPerson2("x",1);//有参构造
    }
}
//需求:
interface PersonCreater{
    Person getPerson();
}
interface  PersonCreater2{
    Person getPerson2(String name,int age);
}
五、Lambda表达式综合练习

1、ArrayList排序

/**
 * 集合排序
 * 题目:已知一个Arraylist中存有若干个Person对象,按照年龄降序
 */
public class exercise1 {
    public static void main(String[] args) {
        ArrayList<People> list = new ArrayList<>();
        list.add(new People("小明",10));
        list.add(new People("小磊",14));
        list.add(new People("小花",3));
        list.add(new People("小美",1));
        //排序
        list.sort((o1, o2) -> o2.age-o1.age);
        System.out.println(list);
    }
}
//定以People类
class People{
    String name;
    int age;

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

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

分析上述这条代码:

 list.sort((o1, o2) -> o2.age-o1.age);

上面这行代码,查看源码知道sort的参数是一个Comparator类型的对象:

 public void sort(Comparator<? super E> c) {

Comparator是一个接口,其中只有一个方法需要被实现,就是compare方法:所以实际上我们是写了一个内部类

 int compare(T o1, T o2);

那么如果是没有lambda之前是什么样呢,我们看一下:

 //Lambda
        list.sort((o1, o2) -> o2.age-o1.age);
        //内部类
        list.sort(new Comparator<People>() {
            @Override
            public int compare(People o1, People o2) {
                return o2.age-o1.age;
            }
        });

可以看出lambda的强大了吧!
2、TreeSet排序

public class exercise2 {
    public static void main(String[] args) {
        /**
         * 使用Lambda表达式来实现Comparator接口,并实例化一个TreeSet对象················
         */
        TreeSet<Person> list = new TreeSet<>((o1, o2) -> o2.age-o1.age);
        list.add(new Person("小明",10));
        list.add(new Person("小磊",14));
        list.add(new Person("小花",3));
        list.add(new Person("小美",1));
        System.out.println(list);
    }
}

3、集合遍历 forEach

public class exercise3 {
    public static void main(String[] args) {
        //集合遍历
        ArrayList<Integer> list =  new ArrayList<>();

        Collections.addAll(list,1,2,3,4,5,6);
        //将集合中的每一个元素都加入到该方法accept中

        list.forEach(System.out::println);

        //输出集合中所有的偶数
        list.forEach(ele->{
            if (ele %2 ==0){
                System.out.println(ele);
            }
        });
    }
}

4、删除集合中满足条件的元素 removeIf

public class exercise4 {
    public static void main(String[] args) {
        ArrayList<Person> list = new ArrayList<>();
        list.add(new Person("小明",10));
        list.add(new Person("小磊",14));
        list.add(new Person("小花",3));
        list.add(new Person("小美",1));

        //删除集合age>10的

        //将集合中的每一个元素都带入test方法中,如果满足返回值true,则删除元素
        list.removeIf(ele->ele.age>10);
        System.out.println(list);
    }
}

5、开辟线程

public class exercise5 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            for (int i = 0;i<10;i++){
                System.out.println(i);
            }
        });
        t.start();
    }
}
六、系统内置函数式接口
import java.util.function.*;
public class FunctionalInterface {
    public static void main(String[] args) {
        //系统内置函数式接口
        
       //Predicate<T>  参数T 返回值boolean
              // IntPredicate   int   boolean
              //LongPredicate  long  boolean
               // DoublePredicate  double  boolean
        //Consumer<T>  参数T   返回值void
       //Function<T,R> 参数T 返回值R
        //Supplier<T>   参数 无  返回值 T
        //UnaryOperator 参数T 返回值T
        //BinaryOperator<T, U, R>  参数T T  返回值T
        // BiFunction<T, U, R>   参数 T U  返回值 R
        //BiPredicate<T ,U>  参数T ,U   返回值boolean
        //BiConsumer<T U> 参数T,U 返回值void
    }
}
七、Lambda表达式闭包问题

什么是闭包?

举例1:
(JDK 1.8)

public class Closuredemo {
    public static void main(String[] args) {
        int n = getnum().get();
        System.out.println(n);//10
    }
    private static Supplier<Integer> getnum(){
         int num = 10;
         return()-> num;
    };
}

我们知道Lambda表达式: return()-> num; 可以看做一个匿名方法,我们在这个方法中引用到了getnum()里面的一个局部变量,那么这个就是一个闭包,我们用Lambda表达式这个匿名方法把这个局部变量包围起来了

我们运行程序输出10,看起来没有错,理所应当;但是我们知道方法里面的局部变量在方法执行结束,它的生命周期也会结束,被销毁,可为什么我们的getnum()方法执行结束了,但是num还在呢,不在的话,我们肯定接收不到返回值,输出没结果

由此我们得到一个结论:闭包可以提升局部变量的生命周期,在方法运行结束时,该变量不会被销毁

注意:

public class Closuredemo {
    public static void main(String[] args) {
      int a = 10;

        Consumer<Integer> c = ele->{
            //System.out.println(a);
            System.out.println(a++);
        };
        c.accept(a);
    }
}

运行上述代码 会出现如下错误:

java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量

结论:闭包中引用的局部变量一定是常量,默认的被final修饰

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值