Java8——Lambda表达式

为什么使用Lamdba表达式

我来举一个范例就知道了

使用匿名内部类

    public void test1(){
        Comparator com = new Comparator() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o2,o1);
            }
        };
    }

上面那么多的代码其实就一句话有用Integer.compare(o2,o1);

使用Lambda表达式

   public void test2(){
        Comparator com = (o1, o2) -> Integer.compare(o1, o2);
    }

是不是很方便了。但可能也会有人觉得并没有什么太大的简便。那么下面再给出一个例子来引入Lambda表达式。
创建Employee类,有name、age、salary三个属性

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

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

    @Override
    public String toString() {
        return "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary;
    }
}
  • 需求1:获取员工年龄大于35的员工信息

我们模拟一下数据库,所以准备一个List集合

//Arrays.asList 将数组转换成集合
List employees = Arrays.asList(
    new Employee("张三",18,9999.99),
    new Employee("李四",38,5555.55),
    new Employee("王五",50,6666.66),
    new Employee("赵六",16,3333.33),
    new Employee("田七",8,7777.77)
);

既然来了需求那我们就要开发呀

  /**
     * 获取员工年龄大于35的员工信息
     * @param list
     * @return
     */
    public List findEmployeesByAge(Listlist){
        Listemps = new ArrayList<>();
        for(Employee emp : list){
            if(emp.getAge() > 35){
                emps.add(emp);
            }
        }
        return emps;
    }

并且来波开发自测

 @Test
    public void test3(){
        List employeesByAge = findEmployeesByAge(employees);
        for (Employee employee : employeesByAge) {
            System.out.println(employee);
        }
    }

输出结果
name='李四', age=38, salary=5555.55
name='王五', age=50, salary=6666.66

完美!!!美滋滋。完成任务

  • 需求2:获取公司中工资大于5000的员工信息
 public List findEmployeesBySalary(Listlist){
        Listemps = new ArrayList<>();
        for(Employee emp : list){
            if(emp.getSalary() > 5000){
                emps.add(emp);
            }
        }
        return emps;
    }

你写完之后发现,特么...就改了个方法名和判断条件,聪明的你发现这代码不能这么写。为什么不能这么写呢!如果你牛逼的客户**,突然又来了一个需求,获取年龄大于20的,薪资大于3000的。你第一个想到的是将判断条件提取为参数,你有推翻了这种想法,你觉得这样不够灵活。突然,你想到了设计模式。

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

创建查询行为的接口

public interface MyPredicate {
    public boolean test();
}

并创建相关的实现类代表不同的行为: (分别是年龄> 35和工资> 5000的 )

//获取员工年龄大于35的员工信息
public class FindEmployeesByAge implements MyPredicate{
    @Override
    public boolean test(Employee emp) {
        return emp.getAge() > 35;
    }
}


//获取公司中工资大于5000的员工信息
public class FindEmployeesBySalary implements MyPredicate{
    @Override
    public boolean test(Employee emp) {
        return emp.getSalary() > 5000;
    }
}

给外部提供一个通用方法

public List filterEmployees(Listlist,MyPredicatemp){
    Listemps = new ArrayList<>();
    for(Employee emp : list){
        if(mp.test(emp)){  //重点代码
            emps.add(emp);
        }
    }
    return emps;
}

写了这么久自测一下

  @Test
   public void test4(){
       List employees = filterEmployees(this.employees, new FindEmployeesByAge());
       for (Employee employee : employees) {
           System.out.println(employee);
       }
   }

输出结果
name='李四', age=38, salary=5555.55
name='王五', age=50, salary=6666.66

如果想要测试工资大于5000的员工信息,只需要换掉 filterEmployees(this.employees, new FindEmployeesByAge())中的FindEmployeesByAgeFindEmployeesBySalary

优化二:匿名内部类

好处:不需要创建接口的具体的实现类(但还是需要MyPredicate接口和filterEmployees()方法):

  @Test
    public void test5(){
        List employees = filterEmployees(this.employees, new MyPredicate() {
            @Override
            public boolean test(Employee employee) {
                return employee.getAge() >= 18;
            }
        });
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
输出结果
name='张三', age=18, salary=9999.99
name='李四', age=38, salary=5555.55
name='王五', age=50, salary=6666.66

优化三:Lambda表达式

哈哈哈,优化优化就回到了开头那个例子(*^▽^*),Lambda表达式省去匿名内部类的没用的代码,提高了代码的整洁性和可读性(注需要那个filterEmployees方法)

 @Test
    public void test6(){
        List employees = filterEmployees(this.employees, (e) -> e.getAge() > 15);
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
输出结果
name='张三', age=18, salary=9999.99
name='李四', age=38, salary=5555.55
name='王五', age=50, salary=6666.66
name='赵六', age=16, salary=3333.33

优化四:使用Stream API

使用该方式,不需要我们上面所创建的所有方法,包括接口、实现类。当然数据还是要的。

  @Test
    public void test7(){
        employees.stream()
                .filter((e) -> e.getAge() > 35)
                .forEach(System.out::println);
    }
输出结果
name='李四', age=38, salary=5555.55
name='王五', age=50, salary=6666.66

Lambda表达式基础语法

Java8中引入了一个新的操作符,"->",该操作符称为箭头操作符或者Lambda操作符,箭头操作符将Lambda表达式拆分成两部分:

  • 左侧: Lambda表达式的参数列表,也就是接口中抽象方法的参数列表
  • 右侧: Lambda表达式中所需要执行的功能(即:Lambda体),对应的是对抽象方法的实现
    注:Lambda表达式需要函数式接口的支持。所谓函数式接口就是接口中只能有一个抽象方法

基础语法

  • 语法格式一:无参数,无返回值
  @Test
    public void test1(){

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("普通 Runnable");
            }
        };
        runnable.run();

        System.out.println("=============我是分割线=============");

        Runnable runnable1 = () -> System.out.println("Lambda Runnable");System.out.println("Lambda Runnable");
        runnable1.run();
    }

输出
普通 Runnable
=============我是分割线=============
Lambda Runnable
  • 语法格式二:一个参数、无返回值(参数列表中有且只有一个参数,那么小括号可以省略不写)

    @Test
    public void test2(){
        Consumer con = (x) -> System.out.println(x);
    //Consumer con = x -> System.out.println(x);
        con.accept("NiuBi Class");
    }
  • 语法格式三: 多个参数,有返回值,Lambda体只有一条语句(大括号和return可以省略)
   @Test
    public void test3(){
       Comparator com = (x,y) -> Integer.compare(x, y);
    }
  • 语法格式四:多个参数,有返回值,Lambda体有多条语句(要用大括号括起来,并且要写上return)
@Test
  public void test4(){
        Comparatorcom = (x,y) -> {
            System.out.println("函数式接口");
            return Integer.compare(x,y);
        };
}
  • 语法格式五:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,这过程称之为"类型推断",例如:(Integer x,Integer y ) -> Integer.compare(x,y); 可以简写成(x,y) -> Integer.compare(x,y);

函数式接口

  • 接口中只有一个抽象方法的接口称为函数式接口
  • 使用注解@FunctionlInterface来检查是否是函数式接口
    需求: 对一个数进行+-*/的运算:
    函数式接口:
@FunctionalInterface
public interface MyFun {
    Integer getValue(Integer num);
}

通用方法:

 public Integer operation(Integer num,MyFun mf){
        return mf.getValue(num);
    }

测试:

 @Test
    public void test5(){
        System.out.println(this.operation(100,(x) -> x * x ));
    }

四大内置函数式接口

我们发现,如果使用Lambda还要自己写一个接口的话太麻烦,所以Java8提供四大内置函数式接口,只有一小部分比较特殊得情况需要我们自己去定义函数式接口

  • Consumer 消费型接口 void accept(T t); :对类型为T的对象应用操作
  • Supplier 供给型接口 T get(); :返回类型为T的对象
  • Function 函数型接口 R apply (T t);:对类型为T的对象应用操作,并返回结果,结果是R类型的对象
  • Predicate 断言形接口 boolean test(T t);:确定类型为T的对象是否满足某约束,并返回boolean值
    image.png

Consumer 消费型接口 void accept(T t);

@Test
    public void test1() {
       //例子1
        happy(1000,(x)->System.out.println("你在我这消费了" + x + "元"));
        //例子2
        List list = Arrays.asList("1", "2", "3");
        list.forEach((obj) -> System.out.println(obj));
    }

Supplier 供给型接口 T get();

需求: 产生指定个数的整数,并放入集合中

@Test
   public void test2(){
       List numList = getNumList(5, () -> (int) (Math.random() * 100));
       numList.forEach((obj)->System.out.println(obj));
   }

    public List getNumList(int num, Supplier sup){
        ArrayList list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Integer value = sup.get();
            list.add(value);
        }
        return list;
    }

Function 函数型接口 R apply (T t);

 @Test
    public void test3(){
        //去掉空格
        System.out.println(strHandler("    gongj   ",(str) -> str.trim()));
        //转换大小写
        System.out.println(strHandler("gongj", (str) -> str.toUpperCase()));
    }

    private String strHandler(String str, Function fun){
        return fun.apply(str);
    }

Predicate 断言形接口 boolean test(T t);

@Test
    public void test4(){
        List list = Arrays.asList("gongj", "yuanj", "xdd");
        System.out.println( filterStr(list,(str) -> str.length() > 3));
    }
    //判断长度>3的字符串
    public List filterStr(List strs, Predicate pre){
        ArrayList arrayList = new ArrayList<>();
        for (String str : strs) {
            if(pre.test(str)){
                arrayList.add(str);
            }
        }
        return arrayList;
    }

其他类型的函数式接口

image.png

https://blog.csdn.net/zxzxzx0119/article/details/82392396
https://blog.csdn.net/rubulai/article/details/88899892

你可能感兴趣的:(Java8——Lambda表达式)