JAVA8 Lambda表达式到底优不优雅?

举报
赵KK日常技术记录 发表于 2023/06/29 15:41:58 2023/06/29
【摘要】 今天看到一个关注很久的公众号,作者是一个10年+的程序员,现在自主创业,他原文中是这么说的:多去看看外面的世界,不要把自己封闭在技术的圈子内,这对自己不管是创业还是挣钱,都有莫大的帮助; 个人虽然很同意他的说法,但是带来的问题就是你如何跻身于高端的,创业大佬的,技术大牛的圈子,人家张嘴就是技术潮流,闭嘴就是互联网一线信息,个人还是觉得踏实提升自己,对于投资自己的脑袋这件事深表认同...

今天看到一个关注很久的公众号,作者是一个10年+的程序员,现在自主创业,他原文中是这么说的:多去看看外面的世界,不要把自己封闭在技术的圈子内,这对自己不管是创业还是挣钱,都有莫大的帮助;

       个人虽然很同意他的说法,但是带来的问题就是你如何跻身于高端的,创业大佬的,技术大牛的圈子,人家张嘴就是技术潮流,闭嘴就是互联网一线信息,个人还是觉得踏实提升自己,对于投资自己的脑袋这件事深表认同。


     目前JAVA版本每半年更新已到JAVA12了,虽然工作中用的是JDK1.8,但不用他的特性是不是有点浪费?针对各个版本的新特性,应该1.8是相当稳定,适用性最多,使用率最高的版本,毕竟新版本还有待市场考察。


    那么JAVA8到底有多优雅呢?首先看下都有神马新特性 

请在此添加图片描述

         我们从代码角度体会下JAVA8的好处;


         需求:设计接口实现对对象属性的过滤。


         方案:除去SQL编写方式外,一般我们都会针对接口编程

公共属性:Employee

public class Employee {
    private Integer id;
    private Integer age;
    private Integer salary;
    private String name;
    public Employee(Integer id, Integer age, Integer salary, String name) {
        this.id = id;
        this.age = age;
        this.salary = salary;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", age=" + age +
                ", salary=" + salary +
                ", name='" + name + '\'' +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Employee() {
    }
    public Employee(Integer id, Integer age, Integer salary) {
        this.id = id;
        this.age = age;
        this.salary = salary;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getSalary() {
        return salary;
    }
    public void setSalary(Integer salary) {
        this.salary = salary;
    }

}

         方案一:针对接口编程,定义接口,逻辑放在实现类
public interface MyProduce<T> {

    boolean bySalary(Employee employee);
}
public class MyProduceImpl implements MyProduce<Employee> {
    @Override
    public boolean bySalary(Employee employee) {
        return employee.getSalary()>5000;
    }
}
public class TestJava8 {

        List<Employee> employees= Arrays.asList(
            new Employee(1,20,2000,"张三"),
            new Employee(2,30,28000,"李四"),
            new Employee(3,40,1000,"王五"),
            new Employee(4,50,5000,"赵六")
        );
}

实现过滤工资小于5000的员工

 public List<Employee> filterEmployee(List<Employee> list,MyProduce<Employee> mp) {
        List<Employee> emps = new ArrayList<>();
        for (Employee employee : list) {
            if (employee.getSalary() < 5000) {
                emps.add(employee);
            }
        }
        return emps;
    }
@Test
    public void test1(){
        List<Employee> employees = filterEmployee(this.employees, new MyProduce<Employee>() {
            @Override
            public boolean bySalary(Employee employee) {
                return employee.getSalary() <5000;
            }
        });
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }

方案二:匿名内部类

   @Test
    public void test2(){
        List<Employee> employee = filterEmployee(employees, new MyProduce<Employee>() {
            @Override
            public boolean bySalary(Employee employee) {
                return employee.getSalary() < 5000;
            }
        });
        for (Employee emp : employee) {
            System.out.println(emp);
        }
    }

方案三:Lambda表达式

@Test
    public void test3(){
        List<Employee> employees = filterEmployee(this.employees,(e)->e.getSalary()>5000);
        employees.forEach(System.out::println);
    }

请在此添加图片描述

方案四:Stream流,工资大于5000的前2位员工,打印出员工的名称,不需要任何接口

 @Test
    public void test4(){
        employees.stream()
                 .filter((e)->e.getSalary()>=5000)
                 .limit(2)
                 .forEach(System.out::println);
        employees.stream()
                 .map(Employee::getName)
                .forEach(System.out::println);
        }

请在此添加图片描述

省掉了各种过滤的接口,各种实现方法的调用,且流式调用,要多方便有多方便,要多简洁有多简洁。代码量更少,功能更强大

Lambda表达式

为什么使用 Lambda 表达式

Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

Lambda表达式的语法

Lambda 表达式在Java 8 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:

左侧:指定了 Lambda 表达式需要的参数列表

右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。

请在此添加图片描述

函数式接口:接口中只有一个抽象方法的接口,SAM类型的接口(Single Abstract Method)。定义了这种类型的接口,使得以其为参数的方法,可以在调用时,使用一个lambda表达式作为参数

语法格式:

1.0:无参数无返回值

() ->System.out.println(“Hello”);

2.0:有一个参数无返回值

Consumer<String> con=(x)->System.out.println(“x”);

3.0: 只一个参数无返回值,小括号可以省略不写

习惯上写小括号

4.0:多个参数,有返回值,Lambda体中有多条语句

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

System.out.println(“多条语句”);

return Integer.compare(1,2);

};

5.0:多个参数,有返回值,Lambda体中有一条语句,return 和大括号都可以不写

6.0:Lambda参数列表的类型可以省略不写,JVM可通过向上下文推断数据类型

总结:左右遇一括号省,

      左侧推断类型省,

@FunctionalInterface检查是否是函数式接口

  1. 默认方法与静态方法并不影响函数式接口的契约,可以任意使用

  2. 可以有 Object 中覆盖的方法,也就是 equals,toString,hashcode等方法。

JDK 8之前已有的函数式接口:

        java.lang.Runnable

        java.util.concurrent.Callable

        java.util.Comparator

        java.io.FileFilter

        java.lang.reflect.InvocationHandler  
import java.util.Objects;
/**
 * Represents an operation that accepts a single input argument and returns no
 * result. Unlike most other functional interfaces, {@code Consumer} is expected
 * to operate via side-effects.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #accept(Object)}.
 *
 * @param <T> the type of the input to the operation
 *
 * @since 1.8
 */*表示接受单个输入参数,并返回无返回值。与大多数其他功能接口不同,需要@code consumer*通过副作用操作@FunctionalInterface
public interface Consumer<T> {}

注意事项:

 @Test
    public void test5(){
       int num=8;//????
        Runnable r=new Runnable(){
            @Override
            public void run() {
                System.out.println("Hello:"+"\t"+num);
            }
        };
        r.run();
        Runnable r1= ()-> System.out.println("HELLO:"+"\t"+num);
        r1.run();
    }

在1.8以前局部内部类中应用了一个同级别的局部变量,他应该是final的

请在此添加图片描述

但是为什么java8不需要也能编译通过呢?其实底层他还是final的,我们验证一下

请在此添加图片描述

变量num是来自内部类,需要final或者实际上是final的,说明1.8进行了底层加final;

然后说下网上的关于java8 Lambda表达式的性能问题。搜索结果验证说用了Lambda反而性能下降了,执行foreach时间长了,特别是大数据遍历。还拿了并行代码对比,我觉得要看实际的用途,看看Lambda解决问题的侧重点,lambda写的好可以极大的减少代码冗余,同时可读性也好过冗长的内部类,匿名类。

本身就是侧重于减少代码冗余的,你非得谈性能?

6月最后一天啊,针对于年初计划,执行情况做一下小总结,年初定了年度计划目标,年中,年末做一个检查,5年后回味自己的今天,希望有质的提升

2019年6月30日:

      1.今天是听得到APP历史记录1242条的一天。

请在此添加图片描述

            2.今天是百词斩APP背单词累计的第394天,背单词数4866个

请在此添加图片描述

      3.今天是一年写40篇文章计划的第26篇

好的今天记录就到这里。

请在此添加图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。