目录java
为何使用Lambda表达式?数据库
Lambda 是一个匿名函数,咱们能够把Lambda表达式理解为是一段能够传递的代码。能够写出更简洁、高效的代码。
设计模式
咱们先来看一段匿名内部类的代码 使用Lambda表达式后的样子api
//匿名内部类 Comparator<Integer> com = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }; TreeSet<Integer> treeSet = new TreeSet<>(com); //使用了Lambda式后的匿名内部类 Comparator<Integer> com = (x,y) -> Integer.compare(x, y); TreeSet<Integer> treeSet = new TreeSet<>(com);
准备工做: 建立一个Employee 实体类数组
public class Employee { private String name; private Integer age; private Double salary; private Status status; //get\set\equals\hashcode方法 ````````````` ````````````` public enum Status{ FREE,BUSY,VACATION; } }
接下来假设咱们有一个需求: 获取公司员工年龄大于等于35的员工信息app
那么咱们可能须要这么干dom
public class TestLambda { List<Employee> list = Arrays.asList( new Employee("张三", 18, 9999.99), new Employee("李四", 38, 5555.99), new Employee("王五", 50, 6666.99), new Employee("赵六", 16, 3333.33), new Employee("田七", 8, 7777.77) ); //传统方式 @Test public void test1(){ List<Employee> empList = filterEmployeeByAge(list); for (Employee e:empList) { System.out.println(e); } } public List<Employee> filterEmployeeByAge(List<Employee> list){ List<Employee> emps = new ArrayList<>(); for(Employee e:list){ if(e != null && e.getAge() >= 35) emps.add(e); } return emps; } }
而后来了第二个需求:获取工资大于的5000的员工,而此时原来的方法可能被别的方法引用着ide
因此咱们又这么干,新加了一个方法知足第二个需求函数
public List<Employee> filterEmployeeBySalary(List<Employee> list){ List<Employee> emps = new ArrayList<>(); for(Employee e:list){ if(e != null && e.getSalary() >= 5000) emps.add(e); } return emps; }
那么如今有一个问题,若是接下来有第3、第四或第五个需求,咱们须要建立第3、第4、第五个方法么优化
这好像是一件十分愚蠢的事
因此接下来咱们使用策略模式来作一次优化 , 那这跟Lambda表达式有半毛钱关系么,别急,耐心看下去
public interface MyPredicate<T> { public boolean test(T t); } public class FilterEmployeeByAge implements MyPredicate<Employee>{ @Override public boolean test(Employee t) { return t == null ? false:t.getAge() >= 35; } } public class TestLambda { List<Employee> list = Arrays.asList( new Employee("张三", 18, 9999.99), new Employee("李四", 38, 5555.99), new Employee("王五", 50, 6666.99), new Employee("赵六", 16, 3333.33), new Employee("田七", 8, 7777.77) ); @Test public void test2(){ List<Employee> empsList = filterEmployee(list,new FilterEmployeeByAge()); for(Employee e:empsList){ System.out.println(e); } } //优化方式一:策略设计模式 public List<Employee> filterEmployee(List<Employee> list,MyPredicate<Employee> mp){ List<Employee> emps = new ArrayList<>(); for (Employee e:list) { if(mp.test(e)){ emps.add(e); } } return emps; } }
不知道你们看明白了没有,若是我有新的需求,我只须要去改变,个人实现接口就能够了,无需建立新的方法
可是有人可能会说,好麻烦呀,我每次想用一次filterEmployee方法去完成不一样的需求,我就务必要建立一个新的接口实现类,并且实现类中,还就一个方法,一点也不可爱
好的,接下来咱们这么干,使用匿名内部类
@Test public void test3(){ //匿名内部类 List<Employee> empsList = filterEmployee(list,new MyPredicate<Employee>() { @Override public boolean test(Employee t) { return t == null ? false:t.getSalary() < 5000 ; } }); for(Employee em:empsList){ System.out.println(em); } } //优化方式二:策略设计模式 public List<Employee> filterEmployee(List<Employee> list,MyPredicate<Employee> mp){ List<Employee> emps = new ArrayList<>(); for (Employee e:list) { if(mp.test(e)){ emps.add(e); } } return emps; }
接下来你们应该想到了点什么,匿名内部类 到 Lambda
@Test public void test4(){ List<Employee> empsList = filterEmployee(list,(e) -> e == null ? false:e.getSalary() < 5000 ); empsList.forEach(System.out::println); }
Lambda表达式的基础语法: Java8中引入了一个新的操做符 "—>" 该操做符称为箭头操做符 或 Lambda操做符,箭头操做符将Lambda表达式 拆分红两个部分
左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能 即Lambda体
语法格式一:无参数,无返回值
Runnable ru = () -> System.out.println("实现Runnable的接口的Lambda");
ru.run();
语法格式二:有一个参数,且无返回值
Consumer
co = (x) -> System.out.println(x); co.accept("呵呵");
语法格式三: 若只有一个参数,小括号可使用不写
x -> System.out.println(x);
语法格式四: 有两个以上的参数,有返回值,而且Lambda体中有多条语句
Comparator
com = (x,y) -> { System.out.println("函数式接口");
return Integer.compare(x,y);
};
语法格式五: Lambda体中只有一条语句,return和大括号能够省略不写
Comparator
com = (x,y) -> Integer.compare(x,y); 语法格式六: Lambda 表达式的参数列表的数据类型能够省略不写,由于JVM能够推断出,数据类型,即类型推断
Comparator
com = (Integer x,Integer y) -> Integer.compare(x,y); 注:数据类型要么全写 要么全不写
函数式接口:接口中只有一个抽象方法的接口,成为函数式接口,可使用注解 @FunctionalInterface修饰
能够检查是不是函数式接口
Java8内置的四大函数式接口
Consumer<T> : 消费型接口 void accept(T t);
Supplier<T> : 供给型接口 T get();
Function<T, R> :函数式接口 R apply(T t);
Predicate<T> : 断言型接口 boolean test(T t);
public class TestLambda3 { // Consumer<T> 消费型接口 @Test public void test1() { happy(10000, x -> System.out.println("我今天花了" + x + "元")); } public void happy(double money, Consumer<Double> con) { con.accept(money); } // Supplier<T> 供给型接口 @Test public void test2() { List<Integer> numList = getNumList(10,() -> (int)(100*Math.random())); for(Integer i:numList){ System.out.println(i); } } // 需求:产生指定个数的整数 放到集合中 public List<Integer> getNumList(int num, Supplier<Integer> sup) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < num; i++) { Integer e = sup.get(); list.add(e); } return list; } //Functional<T> 函数式接口 @Test public void test3(){ String string = strHandler(" 我前面后面都有空格额 ",(str) -> str.trim()); System.out.println(string); } //需求:用于处理字符串 public String strHandler(String str,Function<String, String> fuc){ return fuc.apply(str); } //Predicate<T> 断言型接口 @Test public void test4(){ List<String> list = Arrays.asList("Hello","hi","Apple","zoo","beautiful"); List<String> result = filterStr(list, (str) -> str.length() > 3); for(String s:result){ System.out.println(s); } } //需求:将知足条件的字符串放入集合 public List<String> filterStr(List<String> list,Predicate<String> pre){ List<String> strList = new ArrayList<>(); for(String str:list){ if(pre.test(str)){ strList.add(str); } } return strList; } }
固然还有其余函数式接口
(一)、方法引用: 若Lambda 体中的内容有方法已经实现了,咱们可使用 "方法引用",(能够理解方法引用为Lambda的另外一种表现形式)
主要有三种语法格式:
对象 : : 实例方法名
类 : : 静态方法名
类 : : 实例方法名
注意:
①.Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致
②.若 Lambda 参数列表中的第一个参数是 实例方法的调用者,而第二个参数是实例方法的参数时,可使用ClassName : : methodName
(二)、构造器引用:
格式: ClassName : : New
注意: 须要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致!
(三)、数组引用
格式: Type[ ]::new
public class TestMethodRef { //对象::实例方法名 @Test public void test1(){ Consumer<String> con = (x) -> System.out.println(x); PrintStream ps = System.out; Consumer<String> con1 = ps::println; Consumer<String> con2 = System.out::println; con2.accept("abcd"); } //对象::实例方法名 @Test public void test2(){ Employee emp = new Employee(); Supplier<String> sup = () -> emp.getName(); Supplier<String> sup1 = emp::getName; } //类::静态方法名 @Test public void test3(){ Comparator<Integer> com = (x,y) -> Integer.compare(x, y); Comparator<Integer> com1 = Integer::compare; } //类::实例方法名 @Test public void test4(){ BiPredicate<String, String> bp = (x,y) -> x.equals(y); BiPredicate<String, String> bp1 = String::equals; } //构造器引用 @Test public void test5(){ Supplier<Employee> sup = () -> new Employee(); //构造器引用方式 调用哪一个构造器取决于 接口的参数类型 Supplier<Employee> sup2 = Employee::new; Employee employee = sup2.get(); System.out.println(employee); } //数组引用 @Test public void test6(){ Function<Integer, String[]> fun = (x) -> new String[x]; String[] strs = fun.apply(10); System.out.println(strs.length); Function<Integer, String[]> fun2 = String[]::new; String[] apply = fun2.apply(20); System.out.println(apply.length); } }
简介:
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另一个则是 Stream API(java.util.stream.*)。
Stream 是 Java8 中处理集合的关键抽象概念,它能够指定你但愿对集合进行的操做,能够执行很是复杂的查找、过滤和映射数据等操做。
使用Stream API 对集合数据进行操做,就相似于使用 SQL 执行的数据库查询。也可使用 Stream API 来并行执行操做。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式
流(Stream) 究竟是什么?
是数据渠道,用于操做数据源(集合、数组等)所生成的元素序列.
“集合讲的是数据,流讲的是计算!”
注意:
①.Stream 本身不会存储元素
②.Stream 不会改变源对象。相反它们会返回一个持有对象的结果
③.Stream 操做是延迟执行的,这意味着它们会等到须要结果的时候才会执行
Stream的三个操做步骤
1. 建立 Stream
2. 中间操做
3. 终止操做
public class TestStreamAPI { //建立Stream @Test public void test1(){ //1.能够经过 Collection 系列集合提供的stream() 或 parallelStream() List<String> list = new ArrayList<>(); Stream<String> stream1 = list.stream(); //2.经过 Arrays 中的静态方法 stream() 获取数组流 Employee[] emps = new Employee[10]; Stream<Employee> stream2 = Arrays.stream(emps); //3.经过 Stream 类中的静态方法 of() Stream<String> stream3 = Stream.of("aa","bb","cc"); //4.建立无限流 //迭代 Stream<Integer> stream4 = Stream.iterate(0, (x) -> x+2); //stream4.forEach(System.out::println); //生成 Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println); } }
public class TestStreamAPI { List<Employee> employees = Arrays.asList( new Employee("张三", 18, 9999.99), new Employee("李四", 38, 5555.99), new Employee("王五", 50, 6666.99), new Employee("王五", 50, 6666.99), new Employee("王五", 50, 6666.99), new Employee("赵六", 16, 3333.33), new Employee("田七", 8, 7777.77) ); /** * 筛选与切片 * filter-接收 Lambda, 从流中排除某些元素。 * limit-截断流,使其元素不超过给定数量 * skip(n) - 跳过元素,返回了一个扔掉了前 n 个元素的流.若流中元素不足n个,则返回一个空流.与limit互补 * distinct-筛选,跳过流所生成元素的 hashCode() 和 equals() 去除重复元素 * -此方法务必须要重写equals 和 hashcode 方法 */ @Test public void test2(){ //中间操做:不会执行任何操做 Stream<Employee> stream = employees.stream().filter((e) -> { System.out.println("Stream API的中间操做"); return e.getAge() > 20; }); //终止操做:一次执行所有内容,即"惰性求值" stream.forEach(System.out::println); } @Test public void test3(){ employees.stream().filter((e) -> { System.out.println("短路"); return e.getSalary() > 3000; }).limit(2).forEach(System.out::println); } @Test public void test4(){ employees.stream().filter(e -> e.getSalary() >3000).skip(2).forEach(System.out::print); } @Test public void test5(){ employees.stream().filter((e) -> e.getSalary() > 5000).skip(2).distinct().forEach(System.out::println); } }
public class TestStreamAPI2 { List<Employee> employees = Arrays.asList( new Employee("张三", 18, 9999.99), new Employee("李四", 38, 5555.99), new Employee("王五", 50, 6666.99), new Employee("王五", 50, 6666.99), new Employee("王五", 50, 6666.99), new Employee("赵六", 16, 3333.33), new Employee("田七", 8, 7777.77) ); /** * 映射: * map - 接收Lambda,将元素转换成 其余形式或提取信息.接收一个函数做为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素 * flatMap - 接收一个函数做为参数,将流中的每一个值都换成另外一个流,而后把全部流,链接成一个新流 */ @Test public void test2(){ List<String> list = Arrays.asList("aa","bb","cc","dd","ee"); // list.stream().map((str) -> str.toUpperCase()).forEach(System.out::println); employees.stream().map(e -> e.getName()).forEach(System.out::println); System.out.println("--------------------------------------"); Stream<Stream<Character>> stream = list.stream().map(TestStreamAPI2::filterCharacter); stream.forEach(sm -> sm.forEach(System.out::print)); System.out.println("\n--------------------------------------"); Stream<Character> stream2 = list.stream().flatMap(TestStreamAPI2::filterCharacter); stream2.forEach(System.out::print); } public static Stream<Character> filterCharacter(String str){ List<Character> list = new ArrayList<>(); for(Character ch:str.toCharArray()){ list.add(ch); } return list.stream(); } /** * 排序 * sorted-天然排序(Comparable) * sorted(Comparable com)-定制排序(Comparator) */ @Test public void test3(){ List<String> list = Arrays.asList("ccc","aaa","bbb","ddd"); list.stream().sorted().forEach(System.out::println); System.out.println("----------------------------"); employees.stream().sorted((e1,e2) -> { if(e1.getAge().equals(e2.getAge())){ return e1.getSalary().compareTo(e2.getSalary()); }else{ return e1.getAge().compareTo(e2.getAge()); } }).forEach(System.out::println);; } }
/** * * 终止操做 * */ public class TestStreamAPI3 { List<Employee> employees = Arrays.asList( new Employee("张三", 18, 9999.99,Status.BUSY), new Employee("李四", 38, 5555.99,Status.FREE), new Employee("王五", 50, 6666.99,Status.VACATION), new Employee("王五", 50, 6666.99,Status.BUSY), new Employee("王五", 50, 6666.99,Status.BUSY), new Employee("赵六", 16, 3333.33,Status.FREE), new Employee("田七", 8, 7777.77,Status.VACATION) ); /** * 查找与匹配 * allMatch-检查是否匹配全部元素 * anyMatch-检查是否至少匹配一个元素 * noneMatch-检查是否没有匹配元素 * findFirst-返回第一个元素 * findAny-返回当前流中的任意元素 * count-返回流中元素的总个数 * max-返回流中最大值 * min-返回流中最小值 */ @Test public void test1(){ //检查全部员工是否 都为忙碌状态 boolean allMatch = employees.stream().allMatch(e -> e.getStatus().equals(Status.BUSY)); System.out.println(allMatch); //检查是否有一个员工为忙碌状态 boolean anyMatch = employees.stream().anyMatch(e -> e.getStatus().equals(Status.BUSY)); System.out.println(anyMatch); //检查是否 没用员工处于忙碌状态 boolean noneMatch = employees.stream().noneMatch(e -> e.getStatus().equals(Status.BUSY)); System.out.println(noneMatch); //查询 工资排在首位的 员工 Optional<Employee> findFirst = employees.stream().sorted((e1,e2) -> -Double.compare(e1.getSalary(), e2.getSalary())).findFirst(); System.out.println(findFirst.get()); //查找任意 一个处于空闲状态的员工 Optional<Employee> findAny = employees.parallelStream().filter(e -> e.getStatus().equals(Status.FREE)).findAny(); System.out.println(findAny.get()); //查询员工的个数 long count = employees.stream().count(); System.out.println(count); //查询 拿最大工资的员工 Optional<Employee> max = employees.stream().max((e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary())); System.out.println(max.get()); //查询最小的工资数 Optional<Double> minSalary = employees.stream().map(Employee::getSalary).min(Double::compare); System.out.println(minSalary); } /** * 归约: reduce(T identity, BinaryOperator)/reduce(BinaryOperator) * -能够将流中元素反复结合起来获得一个值 */ @Test public void test2() { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6); // 有起始值 全部不可能为空 故返回值为Integer Integer sum = list.stream().reduce(0, (x, y) -> (x + y)); System.out.println(sum); System.out.println("------------------------"); Optional<Double> salarySum = employees.stream().map(Employee::getSalary).reduce(Double::sum); System.out.println(salarySum.get()); } /** * 收集 collect-将流转换成其余形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 */ @Test public void test3() { List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList()); list.forEach(System.out::println); System.out.println("------------------------"); Set<String> set = employees.stream().map(Employee::getName).collect(Collectors.toSet()); System.out.println("------------------------"); HashSet<String> hashSet = employees.stream().map(Employee::getName) .collect(Collectors.toCollection(HashSet::new)); hashSet.forEach(System.out::print); } @Test public void test4(){ //总数 Long count = employees.stream().collect(Collectors.counting()); System.out.println(count); System.out.println("-------------------------------"); //平均值 Double avg = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(avg); //总和 Double sum = employees.stream().collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(sum); //最大值 Optional<Employee> max = employees.stream().collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println(max.get()); //最小值 Optional<Double> min = employees.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare)); System.out.println(min.get()); } //分组 @Test public void test5(){ //单级分组 Map<Status, List<Employee>> map = employees.stream().collect(Collectors.groupingBy(Employee::getStatus)); System.out.println(map); //多级分组 Map<Status, Map<String, List<Employee>>> map2 = employees.stream().collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy(e -> { if(((Employee)e).getAge() < 18){ return "未成年"; }else{ return "成年"; } }))); System.out.println(map2); } //分区 @Test public void test6(){ Map<Boolean, List<Employee>> part = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 8000)); System.out.println(part); } @Test public void test7(){ DoubleSummaryStatistics doubleSummaryStatistics = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println(doubleSummaryStatistics.getSum()); System.out.println(doubleSummaryStatistics.getAverage()); System.out.println(doubleSummaryStatistics.getMax()); } }