jdk1.8特性
一、lambda表达式
lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码。
先来体验一下lambda最直观的优点:简洁代码
//匿名内部类 Comparator<Integer> cpt = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1,o2); } }; TreeSet<Integer> set = new TreeSet<>(cpt); System.out.println("========================="); //使用lambda表达式 Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y); TreeSet<Integer> set2 = new TreeSet<>(cpt2);
只需要一行代码,极大减少代码量!!
这样一个场景,在商城浏览商品信息时,经常会有条件的进行筛选浏览,例如要选颜色为红色的、价格小于8000千的….
// 筛选颜色为红色 public List<Product> filterProductByColor(List<Product> list){ List<Product> prods = new ArrayList<>(); for (Product product : list){ if ("红色".equals(product.getColor())){ prods.add(product); } } return prods; } // 筛选价格小于8千的 public List<Product> filterProductByPrice(List<Product> list){ List<Product> prods = new ArrayList<>(); for (Product product : list){ if (product.getPrice() < 8000){ prods.add(product); } } return prods; }
我们发现实际上这些过滤方法的核心就只有if语句中的条件判断,其他均为模版代码,每次变更一下需求,都需要新增一个方法,然后复制黏贴,假设这个过滤方法有几百行,那么这样的做法难免笨拙了一点。如何进行优化呢?
优化一:使用lambda表达式
定义一个MyPredicate接口
public interface MyPredicate <T> { boolean test(T t); }
定义过滤方法:
public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){ List<Product> prods = new ArrayList<>(); for (Product prod : list){ if (mp.test(prod)){ prods.add(prod); } } return prods; }
使用lambda表达式进行过滤:
@Test public void test4(){ List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000); for (Product pro : products){ System.out.println(pro); } }
在jdk1.8中还有更加简便的操作 Stream API
优化二:使用Stream API
甚至不用定义过滤方法,直接在集合上进行操作
// 使用jdk1.8中的Stream API进行集合的操作 @Test public void test(){ // 根据价格过滤 proList.stream() .fliter((p) -> p.getPrice() <8000) .limit(2) .forEach(System.out::println); // 根据颜色过滤 proList.stream() .fliter((p) -> "红色".equals(p.getColor())) .forEach(System.out::println); // 遍历输出商品名称 proList.stream() .map(Product::getName) .forEach(System.out::println); }
Lmabda表达式的语法总结: () -> ();
前置 | 语法 |
---|---|
无参数无返回值 | () -> System.out.println(“Hello WOrld”) |
有一个参数无返回值 | (x) -> System.out.println(x) |
有且只有一个参数无返回值 | x -> System.out.println(x) |
有多个参数,有返回值,有多条lambda体语句 | (x,y) -> {System.out.println(“xxx”);return xxxx;}; |
有多个参数,有返回值,只有一条lambda体语句 | (x,y) -> xxxx |
口诀:左右遇一省括号,左侧推断类型省
注:当一个接口中存在多个抽象方法时,如果使用lambda表达式,并不能智能匹配对应的抽象方法,因此引入了函数式接口的概念。
二、函数式接口
函数式接口的提出是为了给Lambda表达式的使用提供更好的支持。
函数式接口: 简单来说就是只定义了一个抽象方法的接口,并且还提供了注解:@FunctionalInterface。
常见的四大函数式接口
Consumer 《T》:消费型接口,有参无返回值
@Test public void test(){ changeStr("hello",(str) -> System.out.println(str)); } /** * Consumer<T> 消费型接口 * @param str * @param con */ public void changeStr(String str, Consumer<String> con){ con.accept(str); }
Supplier 《T》:供给型接口,无参有返回值
@Test public void test2(){ String value = getValue(() -> "hello"); System.out.println(value); } /** * Supplier<T> 供给型接口 * @param sup * @return */ public String getValue(Supplier<String> sup){ return sup.get(); }
Function 《T,R》::函数式接口,有参有返回值
@Test public void test3(){ Long result = changeNum(100L, (x) -> x + 200L); System.out.println(result); } /** * Function<T,R> 函数式接口 * @param num * @param fun * @return */ public Long changeNum(Long num, Function<Long, Long> fun){ return fun.apply(num); }
Predicate《T》: 断言型接口,有参有返回值,返回值是boolean类型
public void test4(){ boolean result = changeBoolean("hello", (str) -> str.length() > 5); System.out.println(result); } /** * Predicate<T> 断言型接口 * @param str * @param pre * @return */ public boolean changeBoolean(String str, Predicate<String> pre){ return pre.test(str); }
总结:函数式接口的提出是为了让我们更加方便的使用lambda表达式,不需要自己再手动创建一个函数式接口,直接拿来用就好了。
三、方法引用和构造器引用
四、Stream API
五、接口中默认的方法与静态方法
六、新时间日期API
七、其他特性