函数式接口(Functional Interfaces):如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。同时,引入了一个新的注解:@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口。这个注解是非必须的,只要接口只包含一个方法的接口,虚拟机会自动判断,不过最好在接口上使用注解 @FunctionalInterface 进行声明。在接口中添加了 @FunctionalInterface 的接口,只允许有一个抽象方法,否则编译器也会报错。
@FunctionalInterface public interface FunctionInterfaceDemo { void say(String name); }同时,Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法。还可以存在静态的方法。
@FunctionalInterface public interface FunctionInterfaceDemo { void say(String name); default void print(String text) { System.out.println(text); }; static void write(String message) { System.out.println(message); } }
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
(parameters) -> expression 或 (parameters) ->{ statements; }以下是lambda表达式的重要特征:
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。可选的大括号:如果主体包含了一个语句,就不需要使用大括号。可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
在Lambda表达式使用中,Lambda表达式外面的局部变量会被JVM隐式的编译成final类型,Lambda表达式内部只能访问,不能修改;Lambda表达式内部对静态变量和成员变量是可读可写的; public class VariableScopeDemo { static int a = 1; public static void main(String[] args) { VariableScope vs = (n) -> { a = 2; return a * n; }; System.out.println(vs.add(2)); } } interface VariableScope { int add(int n); }
在lambda表达式中,方法引用是一种简化写法,引用的方法就是Lambda表达式的方法体的实现 。
语法:类名::方法名
方法引用一般分为三类:
Lambda为java8带来了闭包,支持对集合对象的stream进行函数式操作, stream api被集成进了collection api ,允许对集合对象进行批量操作。
Stream表示数据流,它没有数据结构,本身也不存储元素,其操作也不会改变源Stream,而是生成新Stream。作为一种操作数据的接口,它提供了过滤、排序、映射、规约等多种操作方法,这些方法按照返回类型被分为两类:凡是返回Stream类型的方法,称之为中间方法(中间操作),其余的都是完结方法(完结操作)。完结方法返回一个某种类型的值,而中间方法则返回新的Stream。
Stream的使用过程有着固定的模式:
1.创建Stream
2.通过中间操作,对原始Stream进行“变化”并生成新的Stream
3.使用完结操作,生成最终结果
结合Predicate接口,Filter对流对象中的所有元素进行过滤,该操作是一个中间操作,这意味着你可以在操作返回结果的基础上进行其他操作
public static void main(String[] args) { List<String> languages = Arrays.asList("Java", "html5", "JavaScript", "C++", "hibernate", "PHP"); // 开头是J的语言 filter(languages, (name) -> name.startsWith("J")); // 5结尾的 filter(languages, (name) -> name.endsWith("5")); // 所有的语言 filter(languages, (name) -> true); // 一个都不显示 filter(languages, (name) -> false); // 显示名字长度大于4 filter(languages, (name) -> name.length() > 4); System.out.println("-----------------------"); // 名字以J开头并且长度大于4的 Predicate<String> c1 = (name) -> name.startsWith("J"); Predicate<String> c2 = (name) -> name.length() > 4; filter(languages, c1.and(c2)); // 名字不是以J开头 Predicate<String> c3 = (name) -> name.startsWith("J"); filter(languages, c3.negate()); // 名字以J开头或者长度小于4的 Predicate<String> c4 = (name) -> name.startsWith("J"); Predicate<String> c5 = (name) -> name.length() < 4; filter(languages, c4.or(c5)); // 名字为Java的 filter(languages, Predicate.isEqual("Java")); // 判断俩个字符串是否相等 boolean test = Predicate.isEqual("hello").test("world"); System.out.println(test); } public static void filter(List<String> languages, Predicate<String> condition) { for (String name : languages) { if (condition.test(name)) { System.out.println("=========================="); System.out.println(name + " "); } } }结合Comparator,该操作返回一个排序过后的流的视图,原始流的顺序不会改变。通过Comparator来指定排序规则,默认是自然排序
List<String> list = Arrays.asList("a1", "a2", "a3", "b1", "b2", "b3"); // 倒序 list.stream().sorted((s1,s2)->s2.compareTo(s1)).forEach(System.out::println); // 也可以这样写 Collections.sort(list, (String s1, String s2) -> { return s1.compareTo(s2); }); // 简写: Collections.sort(list, (s1, s2) -> s1.compareTo(s2));List<Map<String,Integer>> 根据Map.key进行排序:
// List<Map<String,Integer>> 根据Map.key进行排序 public static void main(String[] args) { List<Map<String,Integer>> list = new ArrayList<>(); list.add(Collections.singletonMap("bily", 3)); list.add(Collections.singletonMap("alice", 2)); list.add(Collections.singletonMap("allen", 1)); list.add(Collections.singletonMap("tony", 6)); list.add(Collections.singletonMap("nice", 5)); list.add(Collections.singletonMap("miky", 4)); list.stream().sorted((m1, m2) -> { return m1.keySet().iterator().next().compareTo(m2.keySet().iterator().next()); }).collect(Collectors.toList()) .forEach(System.out::println);; }结果展示:
Map<String,Integer> 根据key进行排序:
// Map<String,Integer> 根据key进行排序 public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("bily", 3); map.put("alice", 2); map.put("tony", 6); map.put("miky", 4); map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(System.out::println); }结果展示:
结合Function接口,该操作能将流对象中的每一个元素映射为另一个元素,实现元素类型的转换。
public class MapedDemo { public static void main(String[] args) { List<Employee> list = new ArrayList<>(); list.add(new Employee().builder().id(1L).empName("jack").createTime(new Date()).build()); list.add(new Employee().builder().id(2L).empName("tom").createTime(new Date()).build()); list.add(new Employee().builder().id(3L).empName("allen").createTime(new Date()).build()); list.add(new Employee().builder().id(4L).empName("rock").createTime(new Date()).build()); // 将Employee转化成SysUser List<SysUser> userList = list.stream().map(TranUtils::trans).collect(Collectors.toList()); // 将list转map Map<Long, Employee> objMap = list.stream().collect(Collectors.toMap(Employee::getId, emp -> emp)); // 将list转map Map<Long, String> strMap = list.stream().collect(Collectors.toMap(Employee::getId, Employee::getEmpName)); // Collector.toMap另一个问题,Map中的key不能重复,如果重复的话,会抛出异常: // java.lang.IllegalStateException: Duplicate key The Fellowship of the Ring Map<Long, Employee> objMap2 = list.stream().collect(Collectors.toMap(Employee::getId, emp -> emp,(existing, replacement) -> existing)); // 将List 转换 ConcurrentHashMap Map<Long, Employee> conMap = list.stream().collect(Collectors.toMap(Employee::getId, emp -> emp,(s1, s2) -> s1,ConcurrentHashMap::new)); } } class TranUtils { public static SysUser trans(Employee emp) { return new SysUser().builder().id(emp.getId()).username(emp.getEmpName()).build(); } }在对经过变换后,将变换的stream元素收集,比如将这些元素存在集合中,可以使用stream提供的collect方法.
groupBy多个属性:
// groupBy多个属性 private static String groupByMutilKeys(BizOrder order) { return order.getCustomerId() + "#" + order.getStatus(); } public static void main(String[] args) throws ParseException, InterruptedException { List<BizOrder> orderList = new ArrayList<>(); BizOrder bizOrder1 = BizOrder.builder().customerId(1L).status("SUCCESS").isValid(true).build(); BizOrder bizOrder2 = BizOrder.builder().customerId(1L).status("SUCCESS").isValid(false).build(); BizOrder bizOrder3 = BizOrder.builder().customerId(2L).status("FAIL").isValid(false).build(); BizOrder bizOrder4 = BizOrder.builder().customerId(2L).status("SUCCESS").isValid(true).build(); BizOrder bizOrder5 = BizOrder.builder().customerId(3L).status("FAIL").isValid(true).build(); BizOrder bizOrder6 = BizOrder.builder().customerId(3L).status("FAIL").isValid(false).build(); orderList.add(bizOrder1); orderList.add(bizOrder2); orderList.add(bizOrder3); orderList.add(bizOrder4); orderList.add(bizOrder5); orderList.add(bizOrder6); Map<String, List<BizOrder>> map = orderList.stream().collect(Collectors.groupingBy(o->groupByMutilKeys(o))); for(String key : map.keySet()) { System.out.println("key = " + key); List<BizOrder> subOrderList = map.get(key); System.out.println(subOrderList); }