Java8-01-笔记
Lambda表达式
1、引入案例
-
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到提升。
-
初步感受一下lambda表达式,下面定义的两个TreeSet对象ts1和ts2使用的比较器是一样的。
package com.sunstone.lambda; import org.junit.Test; import java.util.Comparator; import java.util.TreeSet; public class TestLambda { //原来的匿名内部类 @Test public void test1(){ Comparator<Integer> com = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1,o2); } }; TreeSet<Integer> ts1 = new TreeSet<>(com); } //Lambda表达式 public void test2(){ Comparator<Integer> com = (x,y) -> Integer.compare(x,y); TreeSet<Integer> ts2 = new TreeSet<>(com); } }
-
需求:按条件查询对应员工信息
package com.sunstone.lambda; //员工实体类 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 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 + '}'; } }
-
通过下面的两个需求我们能够看出按工资条件查找和按年龄条件查找员工方法相似,代码重复,使用四种方式进行优化。
package com.sunstone.lambda; import org.junit.Test; import java.util.*; public class TestLambda { List<Employee> emps = Arrays.asList( new Employee("小孙",17,5555.55), new Employee("小思",27,3333.33), new Employee("小东",37,9999.99), new Employee("小零",50,7777.77), new Employee("小雪",7,8888.88), new Employee("小豹",60,6666.66) ); //需求1:获取公司中工资大于5000的员工 public List<Employee> filterEmployeeSalary(List<Employee> emps){ List<Employee> list = new ArrayList<Employee>(); for (Employee emp:emps) { if(emp.getSalary()>=5000){ list.add(emp); } } return list; } @Test public void test3(){ List<Employee> list =filterEmployeeSalary(emps); for (Employee employee:list) { System.out.println(employee); } } //需求2:获取公司中年龄小于35的员工 public List<Employee> filterEmployeeAge(List<Employee> emps){ List<Employee> list = new ArrayList<Employee>(); for (Employee emp:emps) { if(emp.getAge()<=35){ list.add(emp); } } return list; } @Test public void test4(){ List<Employee> list =filterEmployeeAge(emps); for (Employee employee:list) { System.out.println(employee); } } }
-
优化方式一:策略设计模式
package com.sunstone.lambda; @FunctionalInterface //函数式接口 意思就是表明这个接口就只有一个抽象方法 public interface MyPredicate<T> { public boolean test(T t); //@111@ }
package com.sunstone.lambda; public class FilterEmployeeForSalary implements MyPredicate<Employee>{ @Override public boolean test(Employee employee) { //@333@ return employee.getSalary()>=5000; } }
package com.sunstone.lambda; public class FilterEmployeeForAge implements MyPredicate<Employee>{ @Override public boolean test(Employee employee) { //@333@ return employee.getAge()<=35; } }
package com.sunstone.lambda; import org.junit.Test; import java.util.*; public class TestLambda { List<Employee> emps = Arrays.asList( new Employee("小孙",17,5555.55), new Employee("小思",27,3333.33), new Employee("小东",37,9999.99), new Employee("小零",50,7777.77), new Employee("小雪",7,8888.88), new Employee("小豹",60,6666.66) ); public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp){ List<Employee> list = new ArrayList<>(); for (Employee employee : emps) { if(mp.test(employee)){ //@222@ list.add(employee); } } return list; } @Test public void test5(){ List<Employee> list1 =filterEmployee(emps, new FilterEmployeeForAge()); //@333@ for (Employee employee:list1) { System.out.println(employee); } List<Employee> list2 =filterEmployee(emps, new FilterEmployeeForSalary()); //@333@ for (Employee employee:list2) { System.out.println(employee); } } }
-
优化方式二:匿名内部类
package com.sunstone.lambda; @FunctionalInterface public interface MyPredicate<T> { public boolean test(T t); //@111@ }
package com.sunstone.lambda; import org.junit.Test; import java.util.*; public class TestLambda { List<Employee> emps = Arrays.asList( new Employee("小孙",17,5555.55), new Employee("小思",27,3333.33), new Employee("小东",37,9999.99), new Employee("小零",50,7777.77), new Employee("小雪",7,8888.88), new Employee("小豹",60,6666.66) ); public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp){ List<Employee> list = new ArrayList<>(); for (Employee employee : emps) { //@222@ if(mp.test(employee)){ list.add(employee); } } return list; } @Test public void test6(){ List<Employee> list1 = filterEmployee(emps, new MyPredicate<Employee>() { @Override public boolean test(Employee employee) { //@333@ return employee.getSalary() >= 5000; } }); for (Employee employee:list1) { System.out.println(employee); } System.out.println("======================="); List<Employee> list2 = filterEmployee(emps, new MyPredicate<Employee>() { @Override public boolean test(Employee employee) { //@333@ return employee.getAge() <= 35; } }); list2.forEach(employee -> System.out.println(employee)); } }
-
优化方式三:Lambda表达式
package com.sunstone.lambda; @FunctionalInterface public interface MyPredicate<T> { public boolean test(T t); //@111@ }
package com.sunstone.lambda; import org.junit.Test; import java.util.*; public class TestLambda { List<Employee> emps = Arrays.asList( new Employee("小孙",17,5555.55), new Employee("小思",27,3333.33), new Employee("小东",37,9999.99), new Employee("小零",50,7777.77), new Employee("小雪",7,8888.88), new Employee("小豹",60,6666.66) ); public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp){ List<Employee> list = new ArrayList<>(); for (Employee employee : emps) { //@222@ if(mp.test(employee)){ list.add(employee); } } return list; } @Test public void test7(){ List<Employee> list1 = filterEmployee(emps, emp -> emp.getSalary() >= 5000);//@333@ list1.forEach(employee -> System.out.println(employee)); System.out.println("======================="); List<Employee> list2 = filterEmployee(emps, emp -> emp.getAge() <= 35); //@333@ list2.forEach(System.out :: println); } }
-
优化方式四:Stream API
package com.sunstone.lambda; import org.junit.Test; import java.util.*; public class TestLambda { List<Employee> emps = Arrays.asList( new Employee("小孙",17,5555.55), new Employee("小思",27,3333.33), new Employee("小东",37,9999.99), new Employee("小零",50,7777.77), new Employee("小雪",7,8888.88), new Employee("小豹",60,6666.66) ); //@111@ Java8内置了四大核心函数式接口 //@222@ stream流中的方法入参是函数式接口的实现类 @Test public void test8(){ emps.stream() .filter(employee -> employee.getSalary() >= 5000) //@333@ .forEach(System.out::println); System.out.println("======================="); emps.stream() .filter(employee -> employee.getAge() <= 35) //@333@ .forEach(System.out::println); } }
2、基本语法
-
Lambda表达式的基本语法:
-
Java8中引入了一个新的操作符
->
,该操作符称为箭头操作符或Lambda操作符,箭头操作符将Lambda表达式拆分成两个部分:- 左侧:Lambda表达式的参数列表
- 右侧:Lambda表达式中所需执行的功能,即Lambda体
- 上联:左右遇一括号省
- 下联:左侧推断类型省
- 横批:能省则省
-
语法格式一:无参数,无返回值
() -> System.out.println("Hello Lambda");
-
语法格式二:有一个参数,无返回值
(x) -> System.out.println(x);
-
语法格式三:若只有一个参数,小括号可以省略不写(不常见)
x -> System.out.println(x);
-
语法格式四:有两个以上的参数,有返回值,并且Lambda体中有多条语句
Comparator<Integer> com = (x,y) -> { System.out.println("Lambda表达式需要函数式接口的支持"); return Integer.compare(x,y); }
-
语法格式五:若Lambda体中只有一条语句,return和{ }都可以省略不写
Comparator<Integer> com = (x,y) -> {return Integer.compare(x,y)}; Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
-
语法格式六:Lambda表达式的参数列表的参数类型可以省略不写,因为JVM编译器通过上下文可以推断出数据类型,即“类型推断”
Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x,y); Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
-
Lambda表达式需要函数式接口的支持
-
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionalInterface修饰。
3、Lambda使用三要素
个人总结Lambda表达式和Stream API的三要素:
-
1,函数式接口(一般函数式接口不需要我们来进行定义,Java8中内置很多的函数式接口)
package com.sunstone.lambda; @FunctionalInterface public interface MyFun { public Integer getValue(Integer num); }
-
2,有方法的入参是函数式接口的实现类,并且该方法内部会使用该实现类(Stream API中的方法内部实现都是这样的)
public Integer operation(Integer num, MyFun mf){ return mf.getValue(num); }
-
3,调用上面的方法时,使用Lambda表达式对函数式接口进行赋值即可(Stream API在调用方法时就是处于这一步,前两步骤人家都做完了)
@Test public void test(){ Integer num = operation(100, x -> x*x); System.out.println(num); System.out.println(operation(200, y -> y+777)); }
大家可以回头看一下引入案例中,四种优化方案代码中被@111@、@222@、@333@所标识的方法是不是和这三要素相对应!!!
等学习完Lambda表达式、函数式接口和Stream API之后,就会知道这三要素总结的重要性!!!
学习一门新技术最起码要明确三点:为什么引入该技术? 怎么用? 什么情况去使用?
4、Lambda表达式练习
-
1,调用Collections.sort()方法,通过定制排序比较两个Employee,进行排序(先按年龄比较,相同则按姓名比较)
Collections工具类的sort方法 : - void sort(List<T> list) 自然排序 - void sort(List<T> list,Comparator<? super T> c) 定制排序
List<Employee> emps = Arrays.asList( new Employee("小孙",17,5555.55), new Employee("小思",27,3333.33), new Employee("小东",37,9999.99), new Employee("小零",50,7777.77), new Employee("小雪",7,8888.88), new Employee("小豹",60,6666.66) ); @Test public void test9(){ Collections.sort(emps, (e1, e2)->{ if(e1.getAge() == e2.getAge()){ return e1.getName().compareTo(e2.getName()); }else{ return Integer.compare(e1.getAge(), e2.getAge()); } }); for(Employee emp:emps){ System.out.println(emp); } }
-
大家如果查看Comparator接口的定义,会发现该接口不止有一个抽象方法compare,还有抽象方法equals,还有一些接口的默认方法。所以上面对函数式接口的说明并不严谨,具体的内容将会在函数式接口文章中指出,并且还会对Comparator接口进行详细讲解说明。
-
2,三要素练习
(1)声明一个函数式接口,接口中声明抽象方法:public String getValue(String str)
(2)声明类TestLambda,类中编写方法strHandler使用接口作为参数
(3.1)将一个字符串转换成大写,并作为方法的返回值
(3.2)将一个字符串的第二个到第四个索引位置截取并输出@FunctionalInterface public interface MyFunction { public String getValue(String str); }
package com.sunstone.lambda; import org.junit.Test; import java.util.*; public class TestLambda { public String strHandler(String str, MyFunction mf){ return mf.getValue(str); } @Test public void test10(){ String upper = strHandler("abcdefg", str -> str.toUpperCase()); System.out.println(upper); System.out.println("======================="); String newStr = strHandler("现在干的事有用吗?", str -> str.subString(2,5)); System.out.println(newStr ); } }