java8

在前东家测试过java8以及java6的性能对比,发现增长不大,另外自己也快离职了所以一直没有升级主服务到java8,自己平时写代码也都基本没有使用新的语言特性,主要还是和别的同事保持一致就好。现在新同事能用新特性的会使用新的特性,产品要求必须是jdk8的环境,所以看一下书记一下看的过程。

lambda表达示

lambda表达式名称源于字母λ,是参数的意思。在java8中可以使用参数,箭头,表达式来组成一个lambda表达式

  • 如果表达式比较复杂不能用一行写清楚,可以放在{}里面

  • 参数一般形式是(类型 参数1,类型 参数2, ...),对于可以推断出来的类型,可以省略;如果只有一个参数,可以不用小括号;如果没有参数,就是一个空的小括号。

Comparator<String> comparator = (a, b) ->  a.compareTo(b);  
  • 不需要为一个lambda表达式加上一个返回结果,这个是可以被推导出来的。但如果你的代码只考虑了某些分支而忘记了别的分支的处理,这样是会有问题的。
  • 对于只包含一个抽像方法的接口,我们可以通过lambda表达式来创建这个接口的对象,这种接口叫做函数式接口。其实,函数式接口转换是java中使用lambda表达式目前唯一能做的事。不过,java.util.function中定义了许多的通过的函数式接口,你也可以自己写函数式接口。建议在任何的函数式接口上标@FunctionalInterface注解,好处是可以得到编译器的检查 ,也可以在javadoc页面中得到说明。这个注解不是强制使用的,只是让代码更清晰。
常用的: Runnable, Comparetor
  • 需要注意处理检查期异常,可以在表达式中捕获,也可以将lambda表达式给一个抽象方法可以抛出异常的接口。
  • 方法引用与构造器引用
(a, b)-> Math.pow(a, b)可以写成Math::pow
(x)->this.equals(x)可以写成this::equals
另外还可以super::method
构造器引用:String::new
  • 变量的作用域 lambda表达式可以捕获闭包中的变量,但是不能在lambda表达式里面进行修改。另外由于与同级的代码有相同的作用域,所以不能声明一个与局部变量同名的变量。并且在lambda表达式中使用this,得到的是对象而不是lambda表达式的对象
public class LambdaDemo {  
    private void testThis() {
        Runnable testThis = () -> {System.out.println(this.getClass().getName());};
        new Thread(testThis).start();
    }
    public static void main(String[] args) {
        new LambdaDemo().testThis();
 }
  • 默认方法 背景:例如集合库,我们要加一个foreach方法,意味着所有实现这个接口的类,都需要加上这个方法,这个是不能搞的。所以引入了一个默认类的概念,就是允许接口实现一个默认方法,实现类可以直接使用而不用实现。
    1. 如果父类中有同样的方法,以父类实现优先;如果多个父接口中有方法冲突,必须覆盖。
  • 静态方法 在java8里面,接口可以加静态方法。

Stream

用于处理集合,但不会改变源对象,另外是延迟执行的,也就是需要结果时,才会执行。优点是比循环有更好的可读性以及更容易用parallelStream来转为并行执行。

  • 创建stream 可以用集合创建,也可用Stream.of来创建,java8中也会有别的一些类加了stream的方法,例如Pattern.splitAsStream,另外对于文件也会有
try {Stream<String> lines = Files.lines(path){//operators}  
  • 一些方法 filter/map/flatMap/limit/skip/distinct/reversed/reduce/

时间日期

都在java.time里面了,常用的有LocalDateTime, DateTimeFormatter, Instant,Duration

  public static void main(String[] args) throws InterruptedException {
        Instant instantStart = Instant.now();
        System.out.println(instantStart);

        Thread.currentThread().sleep(1000);
        Instant instantEnd = Instant.now();
        System.out.println(instantEnd);

        System.out.println("duration second:" + Duration.between(instantStart, instantEnd).getSeconds());
        System.out.println("duration millSecond:" + Duration.between(instantStart, instantEnd).toMillis());

        /////////

        LocalDate localDate = LocalDate.now();
        System.out.println(localDate);
        LocalDate a = localDate.of(1988, 01, 01);
        System.out.println(a);//month start from 1, but in java.util.Date is 0

        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(dtf.format(LocalDateTime.now()));
    }

concurrent

  • compareAndSet之前是写死循环的,现在只需要传入lambda表示式把观测值与修改值一并传入就可以了。

  • 有了新的ConcurrentHashMap

    1. merge可以进行无初值的设定,就不用再先判空了。
    2. 对于并发Set,可以继续用keySet这样的操作来获取
    3. 并发例子
   public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(1);
        int newNum = 0;
        atomicInteger.updateAndGet(x->Math.max(x, newNum));

        ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
        concurrentHashMap.merge("a", -1, (exstingValue, newValue) -> exstingValue + newValue);
        concurrentHashMap.merge("a", 1, (exstingValue, newValue) -> exstingValue + newValue);
        concurrentHashMap.merge("a", 1, (exstingValue, newValue) -> exstingValue + newValue);
        System.out.println(concurrentHashMap.get("a"));
        concurrentHashMap.merge("a", 1, Integer::sum);
        System.out.println(concurrentHashMap.get("a"));

        concurrentHashMap.merge("b", 3, Integer::sum);
        concurrentHashMap.merge("c", 1, Integer::sum);
        concurrentHashMap.merge("ab", 1, Integer::sum);

        String key = concurrentHashMap.search(1, (x, y) -> y > 1 ? x: null);
        System.out.println(key);

        key = concurrentHashMap.searchKeys(1, (x) -> x.length() > 1 ? x: null);
        System.out.println(key);

        concurrentHashMap.forEach(1, (x, y) -> x + ":" + y + "\n", System.out::print);
    }
  • 可完成的future 我们需要调futurn中的内容进行后面的操作时,会被future的get()阻塞。不好回调函数。现在可以使用CompletableFuture来操作
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        Future<Integer> f = executorService.submit(() -> {
            try {
                Thread.currentThread().sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        });
        System.out.println(f.get());
        executorService.shutdown();

        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(()->{
            try {
                Thread.currentThread().sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2;
        }).whenComplete((v, e) -> {
            System.out.println("complete now");
            System.out.println("a is:" + v);
            System.out.println("b is:" + e);
        });
        System.out.println(f1.get());

        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {return 10;});
        f2.thenApply((v)-> {v= v + 1;System.out.println("v in 1 is:" + v);return v;}).thenApply((v) -> {v = v + 1; System.out.println("v in 1 is:" + v);return v;});
        System.out.println("f2 is:" + f2.get());
    }

别的改动

  • 使用String.join来代替String的+号,也可以插入分隔符了
  • Integer支持无符号运算
  • Files.lines以及Files.list、Files.walk来进行遍历操作
  • Base64的官方支持
  • 原始数据类型加了一个SIZE字段以bit表示类型的长度
  • Comparator加入了thenComparing来进行多级比较
  • 注解可以重复
  • 使用lambda表达式来延迟带Log从而避免不需要打的log也进行了拼接的问题
comments powered by Disqus