还在使用 Java6 Java7 吗,还不了解的 Java8 的可以看看
本文已参加 GitChat「我的技术实践」有奖征文活动,活动链接: GitChat「我的技术实践」有奖征文活动
Java8 Optional- 例一
以前写法
public String getCity(User user) throws Exception{ if(user!=null){ if(user.getAddress()!=null){ Address address = user.getAddress(); if(address.getCity()!=null){ return address.getCity(); } } } throw new Excpetion("取值错误"); }
Java8 写法
public String getCity(User user) throws Exception{ return Optional.ofNullable(user) .map(u-> u.getAddress()) .map(a->a.getCity()) .orElseThrow(()->new Exception("取指错误"));}
- 例二以前写法
if(user!=null){ dosomething(user);}
Java8 写法
Optional.ofNullable(user) .ifPresent(u->{ dosomething(u); });
- 例三以前写法
public User getUser(User user) throws Exception{ if(user!=null){ String name = user.getName(); if("zhangsan".equals(name)){ return user; } }else{ user = new User(); user.setName("zhangsan"); return user; }}
Java8 写法
public User getUser(User user) { return Optional.ofNullable(user) .filter(u->"zhangsan".equals(u.getName())) .orElseGet(()-> { User user1 = new User(); user1.setName("zhangsan"); return user1; });}
Java8 妙用 Optional
Java8 Lambda 表达式java 自己带的函数式接口都在 java.util.function 包里面,这里面有一些事正常的函数式接口,java 还为我们提供了一些不用自动装箱和拆箱的方法,因为正常的情况下泛型不支持基础类型,比如:int、double 之类的,只支持它们的包装类,所以如果我们传进去的是基础类型就会自动装箱,浪费时间和空间,所以 java 提供了一些基础类型的函数式接口
java 自带的函数式接口的那个函数不带抛出异常的,要想带,只能自己声明函数式接口
通用套路:
// 先定义一个函数式接口,自己定义要加上@FunctionalInterface@FunctionalInterfacepublic interface BufferedReaderProcessor {String process(BufferedReader b) throws IOException;}// 使用函数式接口定义一个通用处理函数public static String processFile(BufferedReaderProcessor p) throwsIOException { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) { return p.process(br); }}// 使用通用处理函数,传递 lambda 表达式String result = processFile((BufferedReader br) -> br.readLine() + br.readLine());
Lambda 表达式可以类型推倒,但是吧,有时候感觉还是带着类型,清晰些
Lambda 表达式可以使用局部变量,就像匿名类一样,==但是有一点需要注意,就是 Lambda 表达式里面使用的局部变量必须是 final 的==,上例子:
// 这种是报错的,因为 Lambda 引用的 portNumber 被赋值两次,不是 final 的int portNumber = 1337;Runnable r = () -> System.out.println(portNumber);portNumber = 31337;
之所以有这个 final 的限制,是因为局部变量是保存在栈上的,而实例变量是保存在堆上,保存在栈上的,就是每个线程独自的。如果我们的 Lambda 表达式是在另一个线程中运行的,比如 Runnable,那么就可能会有线程不安全的问题,因为这个时候相当于是两个线程访问同一个局部变量。但是堆上的东西就没事,本来也是所有线程共享的。==出于这个目的,Lambda 可以随意访问实例变量和静态变量,但是局部变量只能为 final。==Lambda 表达式能实现一部分闭包了,就是能让一个函数作为参数传递给另一个函数。
- 方法引用
主要是分成三种情况:
- 类的静态方法,直接使用 类名::方法名
- 实例方法,使用 类名::方法名
String::length (String str) -> str.length()
- 针对现有对象的实力方法,使用 对象名::方法名
expensiveTransaction::getValue ()->expensiveTransaction.getValue()
4.构造函数的方法引用
// 如果是无参的构造函数,正好和 Supplier 接口符合Supplier c1 = Apple::new; Supplier c1 = () -> new Apple();Apple apple = c1.get();// 如果带一个参数,就符合 Function 接口 Apple(Integer weight)Function c2 = Apple::new; Function c2 = (weight) -> new Apple(weight);// 如果带两个参数,就符合 BiFunction 接口 Apple(String color, Integer weight)BiFunction c3 = Apple::new;Apple c3 = c3.apply("green", 110);// 如果带三个参数的话,就需要自己定义函数式接口了public interface TriFunction{ R apply(T t, U u, V v);}TriFunction colorFactory = Color::new;
java8 in action 中介绍的终极简化版本
inventory.sort(comparing(Apple::getWeight));
- Lambda 复合
- 比较器复合
// Comparator 的静态方法 comparing 是为了将一个 Function 接口转换成一个 ComparatorComparator c = Comparator.comparing(Apple::getWeight);// Comparator 中实现了很多默认接口,这都是 java8 的东西嘛,如下:reversed() // 逆序Comparator thenComparing(Comparator
关注
打赏