Lambda表达式
Lambda 表达式的基础语法:Java8中引入了一个新的操作符 “->” 该操作符称为箭头操作符或 Lambda 操作符, 箭头操作符将 Lambda 表达式拆分成两部分:
- 左侧:Lambda 表达式的参数列表,参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型
- 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
格式一:无参数,无返回值
匿名类部类的方式实现接口
@Test public void test1(){ int num = 0;//jdk 1.7 前,必须是 final,1.7以后可以不写但还是final类型 Runnable r = new Runnable() { @Override public void run() { System.out.println("Hello World!" + num); } }; Thread t = new Thread(r); t.start(); System.out.println("-------------------------------"); Runnable r1 = () -> System.out.println("Hello Lambda!"); Thread t1 = new Thread(r1); t1.start(); }
格式二:有一个参数,无返回值
()可以省略不写
@Test public void test3(){ Consumer<String> con1 = (x) -> System.out.println(x); con1.accept("bushro1"); Consumer<String> con2 = x -> System.out.println(x); con2.accept("bushro2"); }
格式三:两个以上参数,有返回值
()不能省略
@Test public void test3(){ //Lambda 体中只有一条语句 Comparator<Integer> com1 = (x, y) ->Integer.compare(x, y); //Lambda 体中有多条语句 Comparator<Integer> com2 = (x, y) -> { System.out.println("函数式接口"); return Integer.compare(x, y); }; }
排序使用
List<Employee> emps = Arrays.asList( new Employee(101, "张三", 18, 9999.99), new Employee(102, "李四", 59, 6666.66), new Employee(103, "王五", 28, 3333.33), new Employee(104, "赵六", 8, 7777.77), new Employee(105, "田七", 38, 5555.55) ); @Test public void test3(){ Collections.sort(emps, (e1, e2) -> { if(e1.getAge() == e2.getAge()){ return e1.getName().compareTo(e2.getName()); }else{ return Integer.compare(e1.getAge(), e2.getAge()); } }); //使用lambda表达式排序 Collections.sort(emps, (e1, e2) -> { return Integer.compare(e1.getAge(), e2.getAge()); }); emps.sort(new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { return Integer.compare(o1.getAge(), o2.getAge()); } }); //使用lambda表达式排序 emps.sort((e1,e2)->{ return -Integer.compare(e1.getAge(), e2.getAge()); }); }
Lambda 表达式“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰:可以检查是否是函数式接口
如:对一个数进行运算操作
接口
@FunctionalInterface public interface MyFun { public Integer getValue(Integer num); }
这样我们就不需要为每种运行都写一个方法了。
@Test public void test4(){ Integer num = operation(100, (x) -> x * x); System.out.println(num); System.out.println(operation(200, (y) -> y + 200)); } public Integer operation(Integer num, MyFun mf){ return mf.getValue(num); }
四大内置核心函数式接口
Consumer : 消费型接口
//Consumer<T> 消费型接口 : @Test public void test1(){ happy(10000, (m) -> System.out.println("消费:" + m + "元")); } public void happy(double money, Consumer<Double> con){ con.accept(money); }
Supplier : 供给型接口
需求:产生指定个数的整数,并放入集合中
public static List<Integer> getNumList(int num, Supplier<Integer> sup){ List<Integer> list = new ArrayList<>(); for (int i = 0; i < num; i++) { Integer n = sup.get(); list.add(n); } return list; } //调用 List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100)); for (Integer num : numList) { System.out.println(num); }
Function<T, R> : 函数型接口
例如:处理字符串
public String strHandler(String str, Function<String, String> fun){ return fun.apply(str); } //去除头尾空格 String newStr = strHandler(" aaa ", (str) -> str.trim()); System.out.println(newStr); //截取2-5 String subStr = strHandler("abcdefg", (str) -> str.substring(2, 5)); System.out.println(subStr);
Predicate : 断言型接口
将满足条件的字符串,放入集合中
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; } //找出长度大于3的字符串 List<String> list = Arrays.asList("aaaaaaa", "bbbbbbbb", "cc", "www", "ok"); List<String> strList = filterStr(list, (s) -> s.length() > 3); for (String str : strList) { System.out.println(str); }
Stream Api
Stream是数据渠道,用于操作数据源(集合,数组等)所生成得元素序列。而集合讲得是数据,流讲得是计算。
在Stream操作过程中,可以对数据流做过滤,排序,切片等操作,但是操作之后会产生一个新的流,而数据源则不会发生改变。
- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,它会返回一个持有结果得新Stream
- Stream 操作时延迟执行得,这意味着它们会等到需要结果时才执行。(延迟加载)
三个步骤:创建stream->中间操作->终止操作
流进行了终止操作后,不能再次使用
创建Stream流
@Test public void test1(){ //通过Collection系列集合提供的stream()或者parallelStream() List<String> list=new ArrayList<>(); Stream<String> stream1 = list.stream(); //通过Arrays中的静态方法stream()获取数组流 String em[]=new String[]{"aa","bb"}; Stream<String> stream2 = Arrays.stream(em); //通过Stream类中的静态方法of Stream<String> stream3 = Stream.of("aa", "bb"); }
筛选与切片
- filter——接收 Lambda , 从流中排除某些元素。
- limit——截断流,使其元素不超过给定数量。
- skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
- distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
//内部迭代:迭代操作 Stream API 内部完成 @Test public void test2(){ //所有的中间操作不会做任何的处理 Stream<Employee> stream = emps.stream() .filter((e) -> { return e.getAge() <= 35; }); //只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值” stream.forEach(System.out::println); }
映射
- map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee"); Stream<String> stream = strList.stream() .map(String::toUpperCase); stream.forEach(System.out::println);
/** * <h2>查找所有可用的优惠券模板</h2> * @return {@link CouponTemplateSDK}s */ @Override public List<CouponTemplateSDK> findAllUsableTemplate() { List<CouponTemplate> templates = templateDao.findAllByAvailableAndExpired( true, false); templates.stream().map(CouponTemplate::getExpired) return templates.stream() .map(this::template2TemplateSDK).collect(Collectors.toList()); } /** * <h2>获取模板 ids 到 CouponTemplateSDK 的映射</h2> * @param ids 模板 ids * @return Map<key: 模板 id, value: CouponTemplateSDK> */ @Override public Map<Integer, CouponTemplateSDK> findIds2TemplateSDK( Collection<Integer> ids) { List<CouponTemplate> templates = templateDao.findAllById(ids); return templates.stream().map(this::template2TemplateSDK) .collect(Collectors.toMap( CouponTemplateSDK::getId, Function.identity() )); } /** * <h2>将 CouponTemplate 转换为 CouponTemplateSDK</h2> * */ private CouponTemplateSDK template2TemplateSDK(CouponTemplate template) { return new CouponTemplateSDK( template.getId(), template.getName(), template.getLogo(), template.getDesc(), template.getCategory().getCode(), template.getProductLine().getCode(), template.getKey(), // 并不是拼装好的 Template Key template.getTarget().getCode(), template.getRule() ); }
排序
- sorted()——自然排序
- sorted(Comparator com)——定制排序
List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee"); strList.stream() .sorted() .forEach(System.out::println); System.out.println("------------------------------------"); strList.stream() .sorted((x, y) -> { return -x.compareTo(y); }).forEach(System.out::println);
查找与匹配
- allMatch——检查是否匹配所有元素
- anyMatch——检查是否至少匹配一个元素
- noneMatch——检查是否没有匹配的元素
- findFirst——返回第一个元素
- findAny——返回当前流中的任意元素
- count——返回流中元素的总个数
- max——返回流中最大值
- min——返回流中最小值
Status为Employee中的枚举类
//所有集合中的Status是否为BUSY boolean bl = emps.stream() .allMatch((e) -> e.getStatus().equals(Status.BUSY)); //获取最大值 Integer ger[]=new Integer[]{2,4}; Optional<Integer> max = Arrays.stream(ger).max((o1, o2) -> Integer.compare(o1, o2)); System.out.println(max.get()); //查找集合中大于1的个数 List<Integer> list=new ArrayList<>(); list.add(1); list.add(2); list.add(9); long count = list.stream().filter(e -> e > 1).count(); System.out.println(count);
归约
- reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。
//从第0个开始反复计算 List<Integer> integerList = Arrays.asList(1,2,3); Integer sum = integerList.stream() .reduce(0, (x, y) -> x + y); System.out.println(sum); /** * map+reduce * map取出数据,reduce进行累计 */ Optional<Integer> reduce = emps.stream() .map(e -> e.getAge()) .reduce(Integer::sum); System.out.println(reduce.get());
收集
这个一个比较实用的方法
collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法。
/** * map+collect * 取出数据后转成对应的类型 */ List<String> list1 = emps.stream() .map(Employee::getName) .collect(Collectors.toList()); list1.forEach(System.out::println); //放入map中 Map<Integer, String> collect = emps.stream() .collect(Collectors.toMap(e -> e.getId(), e -> e.getName())); System.out.println(collect.get(105)); //其它类型的 HashSet<String> collect1 = emps.stream() .map(e -> e.getName()) .collect(Collectors.toCollection(HashSet::new));
集合最值操作
//最大工资 Optional<Double> max = emps.stream() .map(Employee::getSalary) .collect(Collectors.maxBy(Double::compare)); System.out.println(max.get()); //工资最小值对象 Optional<Employee> op = emps.stream() .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println(op.get()); //求和 Double sum = emps.stream() .collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(sum); //求平均值 Double avg = emps.stream() .collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(avg); //集合中的数量 Long count = emps.stream() .collect(Collectors.counting()); System.out.println(count);
分组:
public class Main { static List<Employee> emps = Arrays.asList( new Employee(102, "李四", 79, 6666.66, Employee.Status.BUSY), new Employee(101, "张三", 18, 9999.99, Employee.Status.FREE), new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION), new Employee(104, "赵六", 8, 7777.77, Employee.Status.BUSY), new Employee(104, "赵六", 8, 7777.77, Employee.Status.FREE), new Employee(104, "赵六", 8, 7777.77, Employee.Status.FREE), new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY) ); public static void main(String[] args) { Map<Employee.Status, List<Employee>> map = emps.stream() .collect(Collectors.groupingBy(Employee::getStatus)); System.out.println(map); Map<Employee.Status, Map<String, List<Employee>>> map1 = emps.stream() .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> { if(e.getAge() >= 60) return "老年"; else if(e.getAge() >= 35) return "中年"; else return "成年"; }))); System.out.println(map1); }