Day2.Lambda表达式 -Java8新特性

Lambda表达式简介

什么是Lambda表达式

Lambda表达式是Java8的一个新特性。说白了,Lambda就是一个匿名函数。

为什么要使用Lambda

之前我们是如何实现一个接口的???

public class Program {

    public static void main(String[] args) {
        //1.使用接口实现类
        Comparator comparator = new MyComparator();

        //2.使用匿名内部类
        Comparator comparator1 = new Comparator() {
            @Override
            public int compare(int a, int b) {
                return a - b;
            }
        };

        //3.使用Lambda表达式
        Comparator comparator2 = (a, b) -> a - b;
    }

}

class MyComparator implements Comparator {

    @Override
    public int compare(int a, int b) {
        return a - b;
    }
}

@FunctionalInterface
interface Comparator {
    int compare(int a, int b);
}

使用Lambda表达式可以对一个接口进行非常简洁的实现。说白了,Lambda表达式就是实现接口用的。

Lambda对接口的要求

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

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

@FunctionalInterFace
修饰函数式接口,函数式接口也就是该接口内只有一个必须要实现的抽象方法。

基础语法

前面提到,Lambda表达式实际上就是一个匿名函数,函数包括:

  • 返回值类型
  • 方法名
  • 参数列表
  • 方法体

匿名函数自然就没有方法名,而且Lambda表达式也不需要返回值类型(可以从接口里面的那一个抽象方法推断出来),所以提供给Lambda表达式参数列表和方法体就够了。

Lambda的基础语法:

        //():用于描述参数列表
        // {}:用来描述方法体
        // ->:Lambda运算符

        //无参无返回
        LambdaNoneReturnNoneParameter lambda1 = () -> {
            System.out.println("hello world");
        };
        lambda1.test();

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

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

        //有返回值 无参数
        LambdaSingleReturnNoneParameter lambda4 = () -> {
            System.out.println("sdas");
            return 100;
        };
        int test = lambda4.test();
        System.out.println(test);

        //有返回值 有参数
        LambdaSingleReturnSingleParameter lambda5 = (int a) -> {
            return 10 * a;
        };
        int test1 = lambda5.test(12);
        System.out.println(test1);

    }

语法精简

 		//语法精简
        //1.参数:
        //在Lambda表达式中,参数的类型可以省略
        //如果要省略的话所有参数都要省略
        LambdaNoneReturnMutipleParameter lambda1 = (a, b) -> {
            System.out.println(a + b);
        };
        lambda1.test(10, 20);


        //2.参数小括号
        //如果参数列表中中参数的数量只有一个,此时小括号可以省略
        LambdaNoneReturnSingleParameter lambda2 = a -> {
            System.out.println("hello world");
        };

        //3.方法大括号
        //如果方法中只有一条语句,大括号可以省略
        //类似与if for语句
        LambdaNoneReturnSingleParameter lambda3 = a -> System.out.println("hello world");


        //4.如果方法体中唯一一个语句是返回语句,则在省略大括号的同时也要省略掉return语句
        LambdaSingleReturnNoneParameter lambda4 = () -> 10;


        //综合练习
        LambdaSingleReturnMutipleParameter lambda5 = (a, b) -> a + b;
        int test = lambda5.test(55, 5);
        System.out.println(test);

语法进阶(方法引用)

public class Syntax3 {

    public static void main(String[] args) {

        //方法引用
        //可以快速的将一个Lambda表达式的实现指向一个已经实现的方法
        //语法: 方法的隶属者::方法名
        //静态方法: 类名::方法名
        //非静态方法: this::方法名
        LambdaSingleReturnSingleParameter lambda1 = a -> change(a);
        
        LambdaSingleReturnSingleParameter lambda2=Syntax3::change;        
    }

    private static int change(int a) {
        return a * 2;
    }
}

构造函数的方法引用
public class Syntax4 {
    public static void main(String[] args) {
        PersonCreater creater=()->new Person();

        //构造方法的方法引用:
        PersonCreater creater1=Person::new;
        creater1.getPerson();

        //倘如想要调用其有参的构造方法
        PersonCreater2 creater2=Person::new;
        Person person = creater2.getPerson("lzh",20);
    }
}

interface PersonCreater{
    Person getPerson();
}
interface PersonCreater2{
    Person getPerson(String name,int age);
}

无论有参 无参的构造函数,写法都是Person::new,调用哪个构造方法是由接口里面的方法决定的。

综合案例

ArrayList排序

Java8为List接口新增了sort(Comparator c)replaceAll()方法。Comparator接口是一个函数式接口。


public class Exercise1 {
    public static void main(String[] args) {
        //需求:在一个ArrayList中有若干个Person对象。将其按年龄降序排序
        ArrayList<Person> list = new ArrayList<Person>();
        list.add(new Person("小明", 12));
        list.add(new Person("lilei", 10));
        list.add(new Person("lili", 10));
        list.add(new Person("miaomiao", 30));
        list.add(new Person("lzh", 80));
        list.add(new Person("ll", 18));
        list.add(new Person("hh", 40));
        list.add(new Person("ww", 1));


        list.sort((o1, o2) -> o1.age - o2.age);
//        Collections.sort();
//        Arrays.sort();
        System.out.println(list);

		//利用流式编程试一下
		list.stream().sorted((o1,o2)->o1.age-o2.age).forEach(System.out::println);

    }
}
不用实现比较接口向TreeSet插入数据

插入到TreeSet集合中的元素一般都要实现Comparable接口。
如果没有实现:
在这里插入图片描述
可以在初始化TreeSet的时候传入一个比较器,这样元素就不需要再实现Comparable接口了。

public class Exercise2 {

    public static void main(String[] args) {
        //TreeSet<Person> set=new TreeSet<>();
        //TreeSet<Person> set=new TreeSet<>(((o1, o2) -> o1.age- o2.age));

        //set的去重规则
        TreeSet<Person> set = new TreeSet<>(((o1, o2) -> {
            if (o1.age >= o2.age) {
                return -1;
            } else {
                return 1;
            }
        }));

        set.add(new Person("小明", 12));
        set.add(new Person("lilei", 10));
        set.add(new Person("lili", 10));
        set.add(new Person("miaomiao", 30));
        set.add(new Person("lzh", 80));
        set.add(new Person("ll", 18));
        set.add(new Person("hh", 40));
        set.add(new Person("ww", 1));

        System.out.println(set);


    }
}

遍历List
  1. Collections.addAll()是个好东西;
  2. 使用Iterable接口中的forEach()来遍历集合很方便,相比于迭代器;
public class Exercise3 {
    public static void main(String[] args) {
        //集合的遍历
        ArrayList<Integer> list = new ArrayList<>();

        //便捷的增加元素
        Collections.addAll(list, 1, 2, 3, 4, 5, 67, 8, 9);

        //将集合中的每一个元素都带入Consumer中的accept()
        //list.forEach(System.out::println);

        //加些自己的逻辑
        list.forEach(ele -> {
            if (ele % 2 == 0) {
                System.out.println(ele);
            }
        });

    }
}

删除集合中的某些满足条件的元素

removeIf()Collection接口里面的方法。

public class Exercise4 {
    public static void main(String[] args) {
        //需求:删除集合中满足条件的集合


        ArrayList<Person> list = new ArrayList<Person>();
        list.add(new Person("小明", 12));
        list.add(new Person("lilei", 10));
        list.add(new Person("lili", 10));
        list.add(new Person("miaomiao", 30));
        list.add(new Person("lzh", 80));
        list.add(new Person("ll", 18));
        list.add(new Person("hh", 40));
        list.add(new Person("ww", 1));

        //删除集合中年龄>20岁的元素


        //使用迭代器实现
/*        ListIterator<Person> iterator = list.listIterator();
        while (iterator.hasNext()) {
            Person next = iterator.next();
            if (next.age > 20) {
                iterator.remove();
            }
        }
        System.out.println(list);*/

        //将集合中的每一个元素都带入到Predicate中的test方法中 如果返回true 就删除
        list.removeIf(ele -> ele.age > 20);
        System.out.println(list);
    }
}

快速的创建线程实例

Runnable也是一个函数式接口,可以使用Lambda表达式实现。

public class Exercise5 {
    public static void main(String[] args) {
        //需求:开辟一个线程

        //Runnable接口是一个函数式接口
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println(i);
            }
        });

        thread.start();

    }
}

闭包

如果我们要在Lambda中使用局部变量,那么这个局部变量必须为常量

小结

  1. Lambda表达式是Java8新增的特性,可以非常简单的实现函数式接口
  2. Lambda表达式的基础语法:()->{} 参数列表 Lambda关键字 方法体;
  3. 语法简化:可以省去参数的类型;
  4. 当参数只有一个时,可以省去参数列表的小括号;
  5. 当方法体内的语句只有一行时,可以省去方法体的大括号;
  6. 当方法体内的语句只有一行且为return时,可以省去大括号和return关键字;
  7. 方法引用与构造方法引用;
  8. 实例:list.sort()排序 向TreeSet中插入元素 list.removeIf()删除元素 list.forEach()遍历 实例化线程;
  9. Lambda中使用到的局部变量一定是常量
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值