您当前的位置: 首页 >  Java

Java8 特性小结

蔚1 发布时间:2019-09-11 23:31:03 ,浏览量:2

还在使用 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 表达式能实现一部分闭包了,就是能让一个函数作为参数传递给另一个函数。

  • 方法引用

主要是分成三种情况:

  1. 类的静态方法,直接使用 类名::方法名
  2. 实例方法,使用 类名::方法名
String::length     (String str) -> str.length()
  1. 针对现有对象的实力方法,使用 对象名::方法名
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 复合
  1. 比较器复合
// Comparator 的静态方法 comparing 是为了将一个 Function 接口转换成一个 ComparatorComparator c = Comparator.comparing(Apple::getWeight);// Comparator 中实现了很多默认接口,这都是 java8 的东西嘛,如下:reversed() // 逆序Comparator thenComparing(Comparator            
关注
打赏
1688896170
查看更多评论
0.0549s