Jdk1.8新特性之Lambda表达式
Posted madyanyan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jdk1.8新特性之Lambda表达式相关的知识,希望对你有一定的参考价值。
近期公司的新项目中使用了很多jdk1.8新特性,特来做个小结
一.Lambda表达式的使用
lambda表达式也叫函数式编程 :Lambda需要函数式接口支持,并且接口中的抽象方法只能有一个
函数式接口:接口中只有一个抽象方法的接口,称之为函数式接口。可以使用@FunctionalInterface修饰,该注解可以检查是否是函数式接口。
自己的理解就是可以 将lambda表达式向数据一样传递
直接上代码体会
//原来匿名内部类 @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> ts = new TreeSet<>(com); } //现在的 Lambda 表达式 @Test public void test2() { //比较器 Comparator<Integer> com = (x, y) -> Integer.compare(x, y); TreeSet<Integer> ts = new TreeSet<>(com); }
JDK1.8之前处理需求
1.new集合 2.遍历 3.if判断
//需求:获取工资大于 5000 的员工的信息 public List<Employee> filterEmployeeBySalary(List<Employee> employees) { List<Employee> list = new ArrayList<>(); for (Employee employee : employees) { if (employee.getSalary() >= 5000) { list.add(employee); } } return list; }
可以发现弊端:当需求有变更 新增过滤条件 又需要遍历一遍 if判断 实际需要的代码只有一句if (employee.getAge() > 18) 却要写大量冗余代码 很恶心
//需求:获取年龄大于 18 的员工的信息 public List<Employee> filterEmployeeByAge(List<Employee> employees) { List<Employee> list = new ArrayList<>(); for (Employee employee : employees) { if (employee.getAge() > 18) { list.add(employee); } } return list; }
优化思路:策略模式
1.定义接口 作为过滤条件
public interface MyPredicate<T> { public boolean test(T t); }
2.接口实现 设置过滤条件
public class FilterEmployeeBySalary implements MyPredicate<Employee>{ @Override public boolean test(Employee t) { return t.getSalary() >= 5000; } }
public class FilterEmployeeByAge implements MyPredicate<Employee> { @Override public boolean test(Employee t) { return t.getAge() > 18; } }
3.定义filter方法 传入需要过滤集合,和过滤条件接口
//优化方式一:策略设计模式 public List<Employee> filterEmployees(List<Employee> employees, MyPredicate<Employee> mp) { List<Employee> list = new ArrayList<>(); for (Employee employee : employees) { if (mp.test(employee)) { list.add(employee); } } return list; }
4.测试
@Test public void test4() { List<Employee> list = filterEmployees(employees, new FilterEmployeeBySalary()); for (Employee employee : list) { System.out.println(employee); } System.out.println("---------------------------------"); List<Employee> list2 = filterEmployees(employees, new FilterEmployeeByAge()); for (Employee employee : list2) { System.out.println(employee); } }
使用匿名内部类简化代码
//优化方式二:策略设计模式 + 匿名内部类 @Test public void test5() { List<Employee> list = filterEmployees(employees, new MyPredicate<Employee>() { @Override public boolean test(Employee t) { return t.getSalary() >= 5000; } }); for (Employee employee : list) { System.out.println(employee); } }
使用lambda表达式 更加简洁
//优化方式三:策略设计模式 + Lambda 表达式 @Test public void test6() { List<Employee> list = filterEmployees(employees, (e) -> e.getSalary() >= 5000); list.forEach(System.out::println); }
弊端:每增加一个过滤条件都需要写一份实现类
能不能不写接口和实现类就实现对集合的过滤?答案是肯定的
在JDK1.8中 引入流操作,使用Stream+Lambda表达式 极大简化代码
//优化方式四:Stream API @Test public void test7() { employees.stream() .filter((e) -> e.getSalary() >= 5000) .forEach(System.out::println); System.out.println("---------------------------------------"); employees.stream() .map(Employee::getName) .forEach(System.out::println); }
lambda表达式的基本使用规则:
/** * lambda表达式 * 左侧:Lambda表达式的参数列表 * 右侧:Lambda表达式所执行的功能,即lambda体 * 接口中只能有一个实现类 */ @Test public void test8() { //Consumer接口中只有一个抽象方法,和一个接口默认方法 Consumer<String> con = (x) -> System.out.println("Yan:" + x); con.accept("我是YanYan啊"); } @Test public void test9() { //lambda体中有多条语句,必须使用大括号 Comparator<Integer> com = (x, y) -> { System.out.println("Comparator接口"); return x.compareTo(y); }; com.compare(1, 2); }
//原来匿名内部类 @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> ts = new TreeSet<>(com); } //现在的 Lambda 表达式 @Test public void test2() { //比较器 Comparator<Integer> com = (x, y) -> Integer.compare(x, y); TreeSet<Integer> ts = new TreeSet<>(com); }
//Demo1
@FunctionalInterface interface MyFun { Integer getValue(Integer num); } public Integer operation(Integer num, MyFun mf) { return mf.getValue(num); } @Test public void test10() { System.out.println(operation(10, (x) -> x * x)); System.out.println(operation(1, x -> x + x)); }
//Demo2
@FunctionalInterface interface HandleStr { String handle(String str); } public String strHandle(String str, HandleStr hs) { return hs.handle(str); } @Test public void test2() { String str = "zhangyan"; System.out.println( strHandle(str, x -> { //转换成大写 return x.toUpperCase().substring(1, 3); })); }
//Demo3
@FunctionalInterface interface MyFun3<T, R> { R getValue(T t1, T t2); } public void op(Long l1, Long l2, MyFun3<Long, Long> mf) { System.out.println(mf.getValue(l1, l2)); } @Test public void test3() { op(100l,200l,(x,y)-> x+y); op(10l,15l,(x,y)->{ return x*y; }); }
二.JAVA内置四大核心函数式接口
之前我们在使用Lamda表达式中每次都需要自己写一个接口,然后再去自定义接口的实现类
然而,JKD1.8已经为我们定义了四大函数式接口,配合Lambda表达式使用起来非常方便
/** * java内置四大核心函数式接口 * <p> * 1.Consumer<T>消费型接口 无返回值 void accept(T t) * 2.Supplier<T>供给型接口 T get(); * 3.Function<T>函数型接口 R apply(T t) * 4.Predicate<T>断言型接口 用于做判断操作 boolean test(T t) */ public class TestLambda3 { //Consumer<T> @Test public void test1() { happy(10.15, (x) -> System.out.println(x)); } //happy public void happy(double money, Consumer<Double> con) { con.accept(money); } //Supplier<T> 产生指定个数的随机数,存入集合 @Test public void test2() { this.getNumber(10, () -> (int) Math.random() * 100); } public List<Integer> getNumber(int num, Supplier<Integer> sup) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < num; i++) { list.add(sup.get()); } return list; } //Predicate<T> @Test public void test3() { List<String> strList = Arrays.asList("Mike", "Lee", "Yan"); //使用时设置条件 List<String> list = this.filterStr(strList, (x) -> x.length() > 3); list.forEach(System.out::print); } //将满足条件的字符串 存入集合中 public List<String> filterStr(List<String> str, Predicate<String> pre) { List<String> list = new ArrayList<>(); for (String s : str) { if (pre.test(s)) { list.add(s); } } return list; }
三.方法引用和构造器引用
本质上是lambda表达式的另一种表现形式
* 三种语法格式
* 1.对象 :: 实例方法名
*
* 2.类 :: 静态方法名
*
* 3.类 :: 实例方法名
*/
public class TestMethodRef { @Test public void test1() { Consumer<String> consumer = (x)-> System.out.println(x); PrintStream ps = System.out; Consumer<String> son = ps::println; }
@Test public void test2() { Employee emp = new Employee("Yan", 24, ‘男‘, 14000); Supplier<String> sup = emp::getName; /* Supplier<String> sup2 = new Supplier<String>() { @Override public String get() { return emp.getName(); } };*/ // 与上面语句功能相同 Supplier sup2 = ()->emp.getName(); String s = sup.get(); System.out.println(s); } //类 :: 静态方法 @Test public void test3() { Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y); Comparator<Integer> com2 = Integer::compare; } //类 :: 实例方法名 @Test public void test4() { BiPredicate<String, String> bp1 = (x, y) -> x.equals(y); //限制条件:只有当(x, y) -> x.equals(y) 第一个参数x作为参数的调用者,第二个参数y为方法参数时,才可以使用这种方式 //ClassName::method BiPredicate<String, String> bp2 = String::equals; } //构造器引用 ClassName::new @Test public void test5() { Supplier<Employee> sup1 = () -> new Employee(); Employee employee = sup1.get();//接口sup1 调用方法 get() get方法被() -> new Employee() 重写 //调用无参构造器 因为 需要和Supplier get方法中的入参和返回值类型保持一致 Supplier<Employee> sup2 = Employee::new; //如需使用其他构造器则 BiFunction<String, Integer, Employee> bg1 = (x, y) -> new Employee(x, y); System.out.println(bg1.apply("Yan", 23)); //调用有参构造器,取决于BiFunction中的apply方法的入参 BiFunction<String, Integer, Employee> bg2 = Employee::new; } //数组引用 type[] :: new @Test public void test6() { Function<Integer, String[]> fun1 = (x) -> new String[x]; String[] apply = fun1.apply(10); System.out.println(apply); Function<Integer, String[]> fun2 = String[]::new; }
以上是关于Jdk1.8新特性之Lambda表达式的主要内容,如果未能解决你的问题,请参考以下文章