Java8
1.Lambda表达式引入
-
策略设计模式:
实体类Employee
public class Employee { private String name; private int age; private double salary; }定义一个接口MyPredicate
public interface MyPredicate<T> { boolean test(T t); }实现类FilterEmployeeByAge继承MyPredicate
public class FilterEmployeeByAge implements MyPredicate<Employee> { //找出获取员工年龄大于等于35的信息 @Override public boolean test(Employee employee) { return employee.getAge()>=35; } }实现类FilterEmployeeBySalary继承MyPredicate
public class FilterEmployeeBySalary implements MyPredicate<Employee>{ @Override //找出获取员工工资大于等于5000的信息 public boolean test(Employee employee) { return employee.getSalary()>=5000; } }主方法:
//填充数据 List<Employee> employees = Arrays.asList( new Employee("张三",42,1000), new Employee("李四",31,4000), new Employee("王五",25,6000), new Employee("赵柳",35,2000), new Employee("胡杨",40,10000) ); //定义方法 public List<Employee> filterEmployee(List<Employee> list,MyPredicate<Employee> myPredicate){ List<Employee> emps = new ArrayList<>(); for(Employee emp:list){ // 调用接口中的方法 if(myPredicate.test(emp)){ emps.add(emp); } } return emps; } @Test public void test(){ List<Employee> emps = filterEmployee(employees,new FilterEmployeeByAge()); for (Employee emp :emps){ System.out.println(emp); } System.out.println("-----------"); //改变传入参数的实现类 List<Employee> emps2 = filterEmployee(employees,new FilterEmployeeBySalary()); for (Employee emp :emps2){ System.out.println(emp); } } //输出 Employee{name='张三', age=42, salary=1000.0} Employee{name='赵柳', age=35, salary=2000.0} Employee{name='胡杨', age=40, salary=10000.0} ----------- Employee{name='王五', age=25, salary=6000.0} Employee{name='胡杨', age=40, salary=10000.0} -
策略设计模式缺点:每加一个需求需要加实现类
-
解决方法:采用匿名内部类
@Test public void test2(){ List<Employee> emps = filterEmployee(employees, new MyPredicate<Employee>() { @Override public boolean test(Employee employee) { return employee.getSalary()<=5000; } }); for (Employee emp :emps){ System.out.println(emp); } } -
匿名内部类代码冗余,通过Lambda表达式优化
@Test public void test3(){ List<Employee> emps = filterEmployee(employees, (employee)->employee.getSalary()<=5000); emps.forEach(System.out::println); }-
继续优化:接口,方法都不用到 Stream ApI
@Test public void test5(){ employees.stream() .filter((e)->e.getSalary()>=5000) .forEach(System.out::println); }
-
2.Lambda表达式的基础语法
-
1.-> 将Lambda拆成两部分:
左侧:Lambda表达式的参数列表
右侧:Lambda表达式所需要执行的功能。即lanbda体
-
2.语法格式:
-
1.无参数无返回值:() -> System.out.Println("Hello");
@Test public void test(){ int num =0; //jdk1.7之前,必须是final修饰 Runnable r = new Runnable(){ @Override public void run() { System.out.println("Hello"+num); } }; r.run(); System.out.println("-----------------"); Runnable r1 =() -> System.out.println("Hello Lambda"+num); r1.run(); } //输出 Hello0 ----------------- Hello Lambda0 -
2.有1个参数,并且无返回值:
@Test public void test2(){ Consumer<String> con=(x) -> System.out.println(x); con.accept("迷雾神"); } //输出 迷雾神 -
3.若只有一个参数,小括号可以不写:
@Test public void test3(){ //小括号可以不写 Consumer<String> con=x -> System.out.println(x); con.accept("迷雾神"); } -
4.有两个参数,并且Lambda有返回值,并且有多条语句:
@Test public void test4(){ //有多条语句,{}不能省略 Comparator<Integer> com= (x,y)->{ System.out.println("函数式接口"); return Integer.compare(x, y); }; System.out.println(com.compare(10,9)); } -
5.有两个参数,并且Lambda有返回值,只有1条语句:
@Test public void test4(){ //单条语句,return和{}可以省略 Comparator<Integer> com= (x,y)-> Integer.compare(x, y); System.out.println(com.compare(10,9)); } -
6.Lambda的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”。
-
-
3.Lambda 表达式需要“函数式接口“的支持
- 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口
-
4.练习
//employees首先按照年龄排序,年龄相同按照姓名排序 public class LambdaExer { List<Employee> employees = Arrays.asList( new Employee("张三",22,5000), new Employee("李四",32,8000), new Employee("王五",23,7000), new Employee("赵六",32,6000)); @Test public void test1(){ Collections.sort(employees,(e1,e2)->{ if(e1.getAge()==e2.getAge()){ return e1.getName().compareTo(e2.getName()); }else{ return Integer.compare(e1.getAge(),e2.getAge()); } } ); employees.forEach(System.out::println); } }
3.Java8 内置的四大核心函数式接口
-
1.Comsumer : 消费型接口
void accept(T t);
@Test public void test(){ happy(10000,(money)-> System.out.println("买了本书,消费了"+money+"元")); } public void happy(double money , Consumer<Double> con){ con.accept(money); } -
2.Supplier : 供给型接口
T get();
@Test public void test1(){ List<Integer> list=getNumList(10,() -> (int)(Math.random()*100) ); list.forEach(System.out::println); } //需求:产生指定个数的整数,并放入集合中 public List<Integer> getNumList(int num , Supplier<Integer> sup){ List<Integer> list=new ArrayList(); for(int i=0;i<num;i++){ list.add(sup.get()) ; } return list; } -
3.Function<T,R> : 函数型接口
R apply(T t);
@Test public void test2(){ String newStr= strHandler("\t\t\t 迷雾神 哈哈 ",(str) -> str.trim()); System.out.println(newStr); } //需求:用于处理字符串 public String strHandler(String str, Function<String ,String > fun){ return fun.apply(str); } -
4.Predicate : 断言型接口
boolean test(T t);@Test public void test3(){ List<String> list = Arrays.asList("hello","迷雾神","Lambda","aaa"); List<String> newList = filterStr(list,(str)->str.length()>3); newList.forEach(System.out::println); } //需求:满足条件的字符串放入集合中 public List<String > filterStr(List<String > lists, Predicate<String > pre){ List<String> list = new ArrayList(); for(String str:lists){ if(pre.test(str)){ list.add(str); } } return list; } //输出 hello Lambda
4.方法引用
-
1.若Lambda体中的内容有方法已经实现了,可以使用”方法引用“。
-
2.三种语法格式:
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
@Test public void test(){ Consumer<String > con = (x) -> System.out.println(x); con.accept("迷雾神"); //方法引用 PrintStream ps=System.out; Consumer<String > con2 = ps::println; con2.accept("迷雾神2"); } //输出 迷雾神 迷雾神2@Test public void test1(){ Employee emp = new Employee("张三",22,5000); Supplier<String > sup=() -> emp.getName(); System.out.println(sup.get()); // 方法引用 Supplier<Integer > sup1=emp::getAge; System.out.println(sup1.get()); } //输出 张三 22
5.Stream
-
1.Stream的创建
-
1.通过Collection系列集合提供的stream()
List<String> list =new ArrayList<>(); Stream<String> stream = 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); //生成 Stream.generate(()->Math.random());
-
-
2.筛选与切片
- 惰性求值:只有当终止操作执行时,才会去执行中间操作
List<Employee> employees = Arrays.asList( new Employee("张三",42,1000), new Employee("李四",31,4000), new Employee("王五",25,6000), new Employee("赵柳",35,2000), new Employee("胡杨",40,10000) ); @Test public void test(){ //filter employees.stream() .filter((e) -> e.getAge()>30) .forEach(System.out::println); //limit 只取对应的个数 employees.stream() //找到满足的数量后,就不再执行,短路 .filter((e) -> e.getSalary()>=4000) .limit(2) .forEach(System.out::println); //输出 Employee{name='李四', age=31, salary=4000.0} Employee{name='王五', age=25, salary=6000.0} //skip 跳过对应的个数 employees.stream() .filter((e) -> e.getSalary()>=4000) .skip(2) .forEach(System.out::println); //输出 //Employee{name='胡杨', age=40, salary=10000.0} //distinct 去重通过流所生成元素的hashcode()和equals()去除重复元素(要重写hashcode()和equals()) employees.stream() .filter((e) -> e.getSalary()>=4000) .distinct () .forEach(System.out::println); } -
3.映射
-
map—接收Lambda ,将元素转换成其他形式或提取信息。接受一个函数作为参数,
该函数会被应用到每个元素上,并将其映射成一个新的元素。
List<String> list =Arrays.asList("aa","bb","cc","dd"); list.stream() .map((str) -> str.toUpperCase()) .forEach(System.out::println); //输出 AA BB CC DD -
flatMap—接受一个函数作为参数,将流中的每一个值都换成另一个流,然后再把所有流连接成一个流
-
@Test public void test4(){ List<String> list =Arrays.asList("aa","bb","cc","dd"); list.stream() .map(TestStreamApI2::filterStream) .forEach((sm) -> { sm.forEach((x) -> System.out.println(x)); }); list.stream() .flatMap(TestStreamApI2::filterStream) .forEach(System.out::println); } public static Stream<Character> filterStream(String str){ List<Character> list = new ArrayList(); for ( Character ch : str.toCharArray()) { list.add(ch); } return list.stream(); }
-
-
4.排序
-
自然排序 sorted() ----> 自然排序(Comparable)
@Test public void test1(){ List<String> list =Arrays.asList("bb","cc","aa","dd"); list.stream().sorted() .forEach(System.out::println); } -
定制排序(Comparator com) sorted(Comparator )
@Test public void test1(){ employees.stream().sorted((e1,e2) ->{ if(e1.getAge()==e2.getAge()){ return e1.getName().compareTo(e2.getName()); }else { return Integer.compare(e1.getAge(), e2.getAge()); } }).forEach(System.out::println); }
-
-
5.查找与匹配
-
allMatch:是否匹配所有元素
@Test public void test(){ boolean b= employees.stream() .allMatch((e)->e.getStatus().equals(Status.BUSY)); System.out.println(b); } -
anyMatch: 是否至少匹配一个元素
@Test public void test(){ boolean b= employees.stream() .anyMatch((e)->e.getStatus().equals(Status.BUSY)); System.out.println(b); } -
noneMatch: 是否没有匹配所有元素
@Test public void test(){ boolean b= employees.stream(java) .noneMatch((e)->e.getStatus().equals(Status.BUSY)); System.out.println(b); } -
findFirst: 返回第一个元素 (返回值是Optional)
Optional<Employee> first = employees.stream().findFirst(); System.out.println(first.get()); -
fingAny:返回流中的任意元素
Optional<Employee> first = employees.stream().fingAny(); System.out.println(first.get()); -
count: 返回流中元素的总个数
long count = employees.stream().count(); System.out.println(count); -
max: 返回流中元素最大值
employees.stream().map(Employee::getSalary).max(Double::compare); -
min:返回流中元素最小值
employees.stream().map(Employee::getSalary).min(Double::compare);
-
-
归约与收集
-
reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ---- 可以将流中元素反复结合起来,得到一个值
@Test public void test1(){ List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9); Integer sum = list.stream().reduce(0, (x, y) -> x + y); System.out.println(sum); System.out.println("--------"); Optional<Double> reduce = employees.stream() .map(Employee::getSalary).reduce(Double::sum); System.out.println(reduce.get()); } //输出 45 -------- 41100.0 -
collect —将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
@Test public void test2(){ List<String> list = employees.stream() .map(Employee::getName) .collect(Collectors.toList()); list.forEach(System.out::println); } //Collectors工具提供了很多的方法,可以转换成各种集合的方式。@Test public void test3(){ //总数 Long count = employees.stream() .collect(Collectors.counting()); System.out.println(count); //平均值 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> employee = employees.stream() .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println(employee.get()); }分组
@Test public void test4(){ Map<Status, List<Employee>> map = employees.stream()java .collect(Collectors.groupingBy(Employee::getStatus)); }连接
@Test public void test5(){ String str = employees.stream() .map(Employee::getName) .collect(Collectors.joining(",")); System.out.println(str); } //张三,赵六,王五,田七,王八,李四
-