Java8新特性->Lambda表达式

Java8新特性

目录

Java8新特性

Lambda表达式

0、首先我们说说为什么叫Lambda表达式:

1、为什么引入Lambda表达式?

2、Lambda表达式语法:

3、函数式接口

Lambda表达式

0、首先我们说说为什么叫Lambda表达式:

Lambda,为什么叫这个名字呢,在没有计算机的年代,某个逻辑学家想要形式化地表示能有效计算机地数学函数。于是用了λ(Lambda)来标记参数。

1、为什么引入Lambda表达式?

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码。

可以写出更加简洁、更加灵活的代码。作为一种更加紧凑的代码风格,使得Java语言表达能力得到了提升。

首先我们回顾以下匿名内部类

public class LambdaTest01 {
​
    //原来的匿名内部类
    @Test
    public void test01(){
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //核心
                return Integer.compare(o1,o2);
            }
        };
        TreeSet<Integer> treeSet = new TreeSet<>(comparator);
    }
​
    //那么我们接下来看看Lambda表达式的语法,这下是不是就可以感受到Lambda的强大与便捷了
    @Test
    public void test2(){
        Comparator<Integer> comparator = (o1,o2) -> Integer.compare(o1,o2);
        TreeSet<Integer> treeSet  = new TreeSet<>(comparator);
    }
}

我们接着往下看

例如: 定义一个比较器来完成排序的功能: 如果想按照长度而不是默认的字典进行排序,可以想sort方法传入一个Comparator对象:

 class LengthComparator implements Comparator<String>{
        //compare方法并不是立即调用。实际上,在数组完成排序之前,sort方法会一直调用compare方法,只要元素的顺序不正确就会重新排列元素。将比较元素所需的代码段放在
            //sort方法中,这个代码将与其余的排序逻辑集成
    public int compare(String first,String second){return first.length)-second.length()};
            }
            ...
            Arrarys.sort(strings,new LengthComparator());

Java是一门面向对象语言,必须new一个对象,new出来的对象的类需要有一个方法包含所需要的代码。 在Java中,编写类似的API处理实现了某个特定的接口的类对象,这种API使用可能不怎么方便。

下面我们有一个需求:获取当前公司中员工年龄大于35的员工信息

    
    List<Employee> employees = Arrays.asList(
            new Employee("zs",18,10000.99),
            new Employee("ls",18,14000.66),
            new Employee("zl",13,30000.55),
            new Employee("ww",39,10020.77),
            new Employee("qq",49,22000.33)
    );
    //需求:获取当前公司中员工年龄大于35的员工信息
    @Test
    public void test03(){
        List<Employee> list = filterEmployees(employees);
        for (Employee employee:list){
            System.out.println(employee);
        }
    }
​
    public List<Employee> filterEmployees(List<Employee> list){
        List<Employee> employees = new ArrayList<>();
        for (Employee employee:list){
            if (employee.getAge()>=35){
                employees.add(employee);
            }
        }
        return employees;
    }

 

增加需求:获取当前公司员工工资大于15000

    
//增加需求:获取当前公司员工工资大于15000
    @Test
    public void test04(){
        List<Employee> list = filterEmployees2(employees);
        for (Employee employee:list){
            System.out.println(employee);
        }
    }
​
    public List<Employee> filterEmployees2(List<Employee> list){
        List<Employee> employees = new ArrayList<>();
        for (Employee employee:list){
            if (employee.getSalary()>=15000 && employee.getAge()>=35){
                employees.add(employee);
            }
        }
        return employees;
    }

 

这两个需求的给我们的直观的问题就是代码冗余,除了核心逻辑的地方有区别之外,其他都是重复代码。

接下来介绍一下优化以上代码的方法:

首先创建一个MyPredicate接口

public interface MyPredicate<T> {
    public boolean test(T t);
}

创建接口的实现类FilterEmployeeByAge

public class FilterEmployeeByAge implements MyPredicate<Employee>{
    @Override
    public boolean test(Employee employee) {
        return employee.getAge()>=35;
    }
}
​

优化方式一:策略设计模式

    //以mypredicate的方式进行过滤
    public List<Employee> filterEmployees3(List<Employee> list,MyPredicate<Employee> myPredicate){
        List<Employee> employees = new ArrayList<>();
        for (Employee employee:list){
            if (myPredicate.test(employee)){
                employees.add(employee);
            }
        }
        return employees;
    }

进行测试

    @Test
    public void test05(){
        List<Employee> employees = filterEmployees3(this.employees, new FilterEmployeeByAge());
        for (Employee employee:employees){
            System.out.println(employee);
        }
    }

 

优化方式二、匿名内部类

    //优化方式二:匿名内部类
    @Test
    public void test6(){
        List<Employee> employees = filterEmployees3(this.employees, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getSalary() <= 15000;
            }
        });
        for (Employee employee: employees){
            System.out.println(employee);
        }
    }

优化方式三、Lambda

    //优化方式三、Lambda
    @Test
    public void test07(){
        List<Employee> list = filterEmployees3(this.employees, (item) ->
                item.getSalary() <= 15000
        );
        list.forEach(System.out::println);
    }

优化方式四、stram流

    //优化方式四、stream流
    @Test
    public void test08(){
        employees.stream()
                .filter((item)->item.getSalary()>=5000)
                .limit(2)
                .forEach(System.out::println);
    }

运行效果:

 

2、Lambda表达式语法:

Java8中引入了一个新的操作符"->"该操作符称为箭头操作符或者是Lambda操作符

箭头操作符将Lambda拆分成两部分:

左侧:Lambda表达式的参数列表

右侧:Lambda表达式中所需要执行的功能,即Lambda 体

语法格式一:无参数,无返回值

()->System.out.println("Hello");

语法格式二:有一个参数,并且无返回值

(x)->System.out.println(x);

语法格式三:若只有一个参数,小括号可以省略不写,无返回值

x->System.out.println(x);

语法格式四:有两个以上的参数,并且Lambda体中有多条语句,并且有返回值

Comparator<Integer> com = (x,y) -> {

System.out.prinln("函数接口");

return Integer.compare(x,y);

};

语法格式五:若Lambda体中,只有一条语句的话,return和大括号都可以省略不写

Comparator<Integer> com = (x,y) -> Integer.compare(x,y);

语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为Jvm编译器可以通过上下文推断出数据类型,即“类型推断”

语法总结:

左右遇一括号省

左侧推断类型省

回到上面的例子,比较两个字符串长短问题: first.length()-second.length() 转换为Lambda表达式即为:

//以下式子可以看成λfirst.λsecond.first.length()-second.length()
(String first , String second)->first.length() - second.length()

如果代码要完成的计算无法放在一个表达式中,就可以像写方法一样,把这些代码放在{}中,并包含显示的return语句。例如:

    (String first,String second) ->{
        if (first.length()<second.length()) return -1;                              
        else if (first.length()>second.length()) return -1;                         
        else return 0;                                                              
    }                       

即使lambda表达式没有参数,仍然要提供空括号,就如同无参方法一样: () -> {for(int i=100;i>=0;i--)System.out.println(i);}

3、函数式接口

Lambda表达式需要"函数式接口"的支持

什么是函数式接口呢:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionalInterface修饰(检查是否是函数式接口)

                        

接下来可能会有一个疑问:为什么函数式接口必须有一个抽象方法。不是接口中所有的方法都是抽象的吗?实际上,接口完全有可能重新声明Object类的方法, 如toString...,这些方法的声明可能会让方法不再是抽象的,而且,接口可以声明非抽象方法。

接下来我们有一个需求:对一个数进行运算

第一步:定义一个接口

@FunctionalInterface
public interface MyFunction {
​
    public Integer getValue(Integer num);
}

第二步:测试

public class LambdaTest02 {
​
    @Test
    public void test01(){
        Integer out = yunsuan(100, (item) -> item * item);
        System.out.println(out);
    }
​
​
    public Integer yunsuan(Integer num,MyFunction myFunction){
        return myFunction.getValue(num);
    }
}
​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值