searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

深入理解java8新特性

2023-02-24 03:13:30
14
0

关于java8新特性的理解

·速度更快  

·代码更少(增加了新的语法Lambda表达式)--核心

·Stream API   --- 核心

·便于并行

·最大化减少空指针异常Optional


Lambda表达式--匿名函数(一段可以传递的代码)

为什么需要Lambda表达式?

·在过去的Java中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法

·同时,在JavaScript中,函数的参数可以是一个函数,返回值也可以是另一个函数,这种情况十分常见,JavaScript是一门非常典型的函数式语言

 我们可以看下关于匿名内部类使用lambda表达式和之前的对比

 

//原来的匿名内部类
public void test1() {
    Comparator<Integer> com = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };
    TreeSet<Integer> ts = new TreeSet<>(com);
}

//Lambda表达式
public void test2() {
    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
    TreeSet<Integer> ts = new TreeSet<>(com);
}
 

 可以看到使用Lambda表达式后代码的简洁性和可读性都得到了提高

 

接下来我们通过一个实例来更近一步了解lambda表达式

定义一个员工实体类,我们的需求是通过不同的条件来过滤得到员工信息

public class Employee {
    private String name;
    private int age;
    private double salary;

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Employee() {
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

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

//向集合中添加元素
List<Employee> employees = Arrays.asList(
        new Employee("张三", 18, 6000),
        new Employee("李四", 21, 2000),
        new Employee("孙悟空", 35, 8000),
        new Employee("猪八戒", 40, 100000),
        new Employee("唐僧", 55, 3000),
        new Employee("孙悟饭", 18, 7000)

);
//需求:获取当前公司中员工年龄大于35的员工信息
public List<Employee> filterEmployee(List<Employee> list) {
    List<Employee> emps = new ArrayList<>();

    for (Employee emp : list) {  //遍历list 如果大于35 就存入 emps
        if (emp.getAge() >= 35) {
            emps.add(emp);
        }
    }
    return emps;
}
//需求:获取员工工资大于5000的员工信息
public  List<Employee> filterEmployee2(List<Employee> list){
    List<Employee> emps = new ArrayList<>();

    for (Employee emp : list) {  //遍历list 如果大于35 就存入 emps
        if (emp.getSalary() >= 5000) {
            emps.add(emp);
        }
    }
    return emps;
}
可以看到,这样的代码十分冗余,而且耦合度过高,我们的本质要面向接口编程,
在一般情况下我们使用设计模式来进行代码优化(本例中使用策略模式)

首先定义一个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;
    }
}
定义接口的实现类FilterEmployeeBySalary 
public class FilterEmployeeBySalary implements MyPredicate<Employee> {
    @Override
    public boolean test(Employee employee) {
        return employee.getSalary() >= 5000;
    }
}

具体实现方法
//优化方式一  俩个参数  一个所有员工信息的集合   一个条件判断的集合
public List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> mp) {
    List<Employee> emps = new ArrayList<>();
    for (Employee employee : list
    ) {
        if (mp.test(employee)) {
            emps.add(employee);
        }
    }
    return emps;
}
//测试方法
@Test
public void Test4() {
    List<Employee> list = filterEmployee(employees, new FilterEmployeeByAge());
    for (Employee employee : list
    ) {
        System.out.println(employee);
    }

    List<Employee> list2 = filterEmployee(employees, new FilterEmployeeByAge());
    for (Employee employee : list2
    ) {
        System.out.println(employee);
    }
}
1.我们可以看到,在具体实现中代码量减少,而且符合了开闭原则(对修改关闭,对扩展开放),
如果需要增加新的需求,只需要新增接口的实现类即可。
2.实际上,我们可以看到这种优化方式的缺点:就是每次新增需求都需要定义新的实现类,有些多余,
实际上我们可以继续优化,通过使用匿名内部类来减少代码
 
//优化方式2 匿名内部类
@Test
public void test5() {
    List<Employee> list = filterEmployee(employees, new MyPredicate<Employee>() {
        @Override
        public boolean test(Employee employee) {
            return employee.getSalary() <= 5000;
        }
    });
    for (Employee employee : list
    ) {
        System.out.println(employee);
    }
}
1.我们可以看到,匿名内部类的本质就是在客户端(测试方法)中直接创建接口的实现类,
省去了单独创建实现类的麻烦。
2.但是实际上匿名内部类的写法依然代码冗余,可读性较低,我们可以采用lambda表达式来进一步优化
 
//优化方式三 lambda 表达式
@Test
public void test6() {
    List<Employee> list = filterEmployee(employees, (e) -> e.getSalary() <= 5000);
    list.forEach(System.out::println);
}
1.实际上,lambda表达式本真就是匿名函数,又进一步简化了匿名内部类的写法,这里的箭头个人感觉与JavaScript中一样,
毕竟JavaScript是典型的函数式语言,但是无论是匿名内部类还是lambda表达式,都只是在客户端中进行了优化,
就是省去了单独创建实现类的工作,将单独创建实现类改为了在客户端(测试方法)中创建。
2.但是本质上他们都需要依赖filterEmployee(List<Employee> list, MyPredicate<Employee> mp)方法来完成需求,
我们采用stream可以直接完成需求
 
//优化方式4 Stream
@Test
public void test7() {
    employees.stream()
            .filter((e) -> e.getSalary() >= 5000)
            .forEach(System.out::println);
}


通过 流Stream这种新的集合运算和表达的高阶抽象,使用效果叹为观止,极大的简化了代码,
引用官方的一句话,Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

0条评论
0 / 1000
嘎嘎嘎嘎
15文章数
0粉丝数
嘎嘎嘎嘎
15 文章 | 0 粉丝
原创

深入理解java8新特性

2023-02-24 03:13:30
14
0

关于java8新特性的理解

·速度更快  

·代码更少(增加了新的语法Lambda表达式)--核心

·Stream API   --- 核心

·便于并行

·最大化减少空指针异常Optional


Lambda表达式--匿名函数(一段可以传递的代码)

为什么需要Lambda表达式?

·在过去的Java中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法

·同时,在JavaScript中,函数的参数可以是一个函数,返回值也可以是另一个函数,这种情况十分常见,JavaScript是一门非常典型的函数式语言

 我们可以看下关于匿名内部类使用lambda表达式和之前的对比

 

//原来的匿名内部类
public void test1() {
    Comparator<Integer> com = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };
    TreeSet<Integer> ts = new TreeSet<>(com);
}

//Lambda表达式
public void test2() {
    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
    TreeSet<Integer> ts = new TreeSet<>(com);
}
 

 可以看到使用Lambda表达式后代码的简洁性和可读性都得到了提高

 

接下来我们通过一个实例来更近一步了解lambda表达式

定义一个员工实体类,我们的需求是通过不同的条件来过滤得到员工信息

public class Employee {
    private String name;
    private int age;
    private double salary;

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Employee() {
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

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

//向集合中添加元素
List<Employee> employees = Arrays.asList(
        new Employee("张三", 18, 6000),
        new Employee("李四", 21, 2000),
        new Employee("孙悟空", 35, 8000),
        new Employee("猪八戒", 40, 100000),
        new Employee("唐僧", 55, 3000),
        new Employee("孙悟饭", 18, 7000)

);
//需求:获取当前公司中员工年龄大于35的员工信息
public List<Employee> filterEmployee(List<Employee> list) {
    List<Employee> emps = new ArrayList<>();

    for (Employee emp : list) {  //遍历list 如果大于35 就存入 emps
        if (emp.getAge() >= 35) {
            emps.add(emp);
        }
    }
    return emps;
}
//需求:获取员工工资大于5000的员工信息
public  List<Employee> filterEmployee2(List<Employee> list){
    List<Employee> emps = new ArrayList<>();

    for (Employee emp : list) {  //遍历list 如果大于35 就存入 emps
        if (emp.getSalary() >= 5000) {
            emps.add(emp);
        }
    }
    return emps;
}
可以看到,这样的代码十分冗余,而且耦合度过高,我们的本质要面向接口编程,
在一般情况下我们使用设计模式来进行代码优化(本例中使用策略模式)

首先定义一个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;
    }
}
定义接口的实现类FilterEmployeeBySalary 
public class FilterEmployeeBySalary implements MyPredicate<Employee> {
    @Override
    public boolean test(Employee employee) {
        return employee.getSalary() >= 5000;
    }
}

具体实现方法
//优化方式一  俩个参数  一个所有员工信息的集合   一个条件判断的集合
public List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> mp) {
    List<Employee> emps = new ArrayList<>();
    for (Employee employee : list
    ) {
        if (mp.test(employee)) {
            emps.add(employee);
        }
    }
    return emps;
}
//测试方法
@Test
public void Test4() {
    List<Employee> list = filterEmployee(employees, new FilterEmployeeByAge());
    for (Employee employee : list
    ) {
        System.out.println(employee);
    }

    List<Employee> list2 = filterEmployee(employees, new FilterEmployeeByAge());
    for (Employee employee : list2
    ) {
        System.out.println(employee);
    }
}
1.我们可以看到,在具体实现中代码量减少,而且符合了开闭原则(对修改关闭,对扩展开放),
如果需要增加新的需求,只需要新增接口的实现类即可。
2.实际上,我们可以看到这种优化方式的缺点:就是每次新增需求都需要定义新的实现类,有些多余,
实际上我们可以继续优化,通过使用匿名内部类来减少代码
 
//优化方式2 匿名内部类
@Test
public void test5() {
    List<Employee> list = filterEmployee(employees, new MyPredicate<Employee>() {
        @Override
        public boolean test(Employee employee) {
            return employee.getSalary() <= 5000;
        }
    });
    for (Employee employee : list
    ) {
        System.out.println(employee);
    }
}
1.我们可以看到,匿名内部类的本质就是在客户端(测试方法)中直接创建接口的实现类,
省去了单独创建实现类的麻烦。
2.但是实际上匿名内部类的写法依然代码冗余,可读性较低,我们可以采用lambda表达式来进一步优化
 
//优化方式三 lambda 表达式
@Test
public void test6() {
    List<Employee> list = filterEmployee(employees, (e) -> e.getSalary() <= 5000);
    list.forEach(System.out::println);
}
1.实际上,lambda表达式本真就是匿名函数,又进一步简化了匿名内部类的写法,这里的箭头个人感觉与JavaScript中一样,
毕竟JavaScript是典型的函数式语言,但是无论是匿名内部类还是lambda表达式,都只是在客户端中进行了优化,
就是省去了单独创建实现类的工作,将单独创建实现类改为了在客户端(测试方法)中创建。
2.但是本质上他们都需要依赖filterEmployee(List<Employee> list, MyPredicate<Employee> mp)方法来完成需求,
我们采用stream可以直接完成需求
 
//优化方式4 Stream
@Test
public void test7() {
    employees.stream()
            .filter((e) -> e.getSalary() >= 5000)
            .forEach(System.out::println);
}


通过 流Stream这种新的集合运算和表达的高阶抽象,使用效果叹为观止,极大的简化了代码,
引用官方的一句话,Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

文章来自个人专栏
java开发
2 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
1
1