• Java学习之==>Java8 新特性详解


    一、简介

      Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级。Java 8是 Java 自 Java 5(发布于2004年)之后的最重要的版本。这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。在本文中我们将学习这些新特性,并用实际的例子说明在什么场景下适合使用。

    • 语言
    • 编译器
    • 工具
    • JVM

    二、Java语言的新特性

    1、Lambda表达式

      Lambda 表达式(也称为闭包)是Java 8中最大和最令人期待的语言改变。它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理,函数式开发者非常熟悉这些概念。

    Lambda 表达式的组成:

    • 参数列表部分, 位于表达式左侧的括号内
      • (o1,o2)->{}
      • ()->{}
      • x ->{}
    • 语法标识符,或参数与代码体分隔符
      • ->
    • 代码块,代码体
      • 一般多行代码使用括号包起来;
      • 如果只有一行代码,可以省略括号不写;
      • 有return则需写return带有返回值,如果没有则不写;
      • (params) -> code-body

    举例:

    public void test1(){
      // 原始代码
      new Thread(new Runnable() {
    
        @Override
        public void run() {
          System.out.println("I love lambda");
        }
      }).start();
    
      // 使用lambda之后的效果
      new Thread(() -> System.out.println("I love lambda")).start();
    }

    Lambda表达式-函数式接口:

      函数接口指的是只有一个函数的接口,这样的接口可以隐式转换为Lambda表达式。在实践中,函数式接口非常脆弱:只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface(Java 库中的所有相关接口都已经带有这个注解了),上面代码中的 Runnable 就是函数式接口,源码如下:

    自定义函数式接口

    /**
     * 自定义函数式接口
     */
    @FunctionalInterface
    public interface FooIface<R, T, S, U> {
    
      R foo(T t, S s, U u);
    
      static void test2() {
      }
    
      default void test1() {
      }
    }

    值得注意的是,默认方法和静态方法不会破坏函数式接口的定义,因此以上的代码是合法的。

    Lambda表达式-四大类函数式接口:

    消费型

    • java.util.function.Consumer
    public void testConsumer() {
      /**
       * 消费型
       * 有参,无返回值
       */
      Consumer<String> consumer1 = new Consumer<String>() {
         @Override
         public void accept(String s) {
           System.out.println(s);
         }
       };
    
      Consumer<String> consumer2 = s -> System.out.println(s);
      
    }

    供给型

    • java.util.function.Supplier
    public void testSupplier() {
      /**
       * 供给型
       * 无参,有返回值
       * () -> "hello";
       */
      Supplier<String> supplier1 = new Supplier<String>() {
        @Override
        public String get() {
          return "hello";
        }
      };
    
      Supplier<String> supplier2 = () -> "hello";
    }

    断言型

    • java.util.function.Predicate
    public void testPredicate() {
      /**
       * 断言型
       * 有参数,返回值是boolean类型
       */
      Predicate<String> predicate1 = new Predicate<String>() {
    
        @Override
        public boolean test(String s) {
          return s.startsWith("abc_");
        }
      };
    
      Predicate<String> predicate2 = s -> s.startsWith("abc_");
    
    }

    转化型

    • java.util.function.Function
    public void testFunction() {
      /**
       * 转化型
       * 有参数,有返回,但是参数和返回是不同的数据类型
       */
      Function<String, Integer> function1 = new Function<String, Integer>() {
    
        @Override
        public Integer apply(String s) {
          return s.length();
        }
      };
    
      Function<String, Integer> function2 = s -> s.length();
      Function<String, Integer> function3 = String::length;
    }

    2、方法引用

      方法引用使得开发者可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。先来看一下下面这段代码:

    public void test4() {
      /**
       * 方法引用
       interface Comparator<T>
       int compare(T o1, T o2);
    
       Integer#compare(int x, int y)
       public static int compare(int x, int y) {
       return (x < y) ? -1 : ((x == y) ? 0 : 1);
       }
       */
      // 原始写法,java8之前
      Comparator<Integer> comparator1 = new Comparator<Integer>() {
    
        @Override
        public int compare(Integer o1, Integer o2) {
          return Integer.compare(o1, o2);
        }
      };
    
      // 基于lambda改写后的,第一种写法,但是有冗余代码,比如return和代码块的大括号
      Comparator<Integer> comparator2 = (x, y) -> { return Integer.compare(x, y); };
    
      // 再一次改写,去掉了return,因为我明明知道就是要return,还需要你再写吗?
      Comparator<Integer> comparator3 = (x, y) -> Integer.compare(x, y);
    
      // 最终,这两个形参x,y其实只是一个占位而已,接受者Integer::compare就知道有这样两个参数传进来,大家心知肚明的事情, 就省略嘛
      Comparator<Integer> comparator4 = Integer::compare;
    
      int x = 10;
      int y = 20;
    
      System.out.println(comparator1.compare(x, y));
      System.out.println(comparator2.compare(x, y));
      System.out.println(comparator3.compare(x, y));
      System.out.println(comparator4.compare(x, y));
    }

    以上这段代码写了从最原始的写法到使用 Lambda 改写后的写法再到最终的方法引用。

    方法引用包括四类:

    构造方法引用

    • Supplier supplier = String::new;
    • Function<String, String> function = String::new;
    • Function<Integer, List> function = ArrayList::new;
    • BiFunction<Integer, Float, HashMap> biFunction = HashMap::new;
    • Function<Integer, String[]> function = String[]::new;

    静态方法引用

    • class::statisMethod
      • Comparator comparator = Integer::compare;

    成员方法引用

    • class::Method
      • BiPredicate<String, String> predicate = String::equals;

    示例对象的方法引用

    • class::instanceMethod
      • Supplier supplier = linkedList::pop;

    自定义类实现方法引用

    public class StringLengthCompare {
    
      public static int abc(String o1, String o2) {
        return o1.length() > o2.length() ? 1 : -1;
      }
    
      public int bcd(String o1, String o2) {
        return o1.length() > o2.length() ? 1 : -1;
      }
    }
    StringLengthCompare 类
    public void test5() {
      /**
       * 第一种,原始写法
       */
      Comparator<String> comparator = new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
          return o1.length() > o2.length() ? 1 : -1;
        }
      };
    
      int res = comparator.compare("abc", "ab");
      System.out.println(res);
      
      /**
       * 第二种,使用lambda改写
       */
      Comparator<String> comparator1 = (str1, str2) -> str1.length() > str2.length() ? 1 : -1;
    
      res = comparator1.compare("abc", "ab");
      System.out.println(res);
      
      /**
       * 第三种,自定义StringLengthCompare类实现方法引用
       */
      // abc为静态方法,直接用类名调用
      Comparator<String> comparator2 = StringLengthCompare::abc;
      System.out.println("comparator2 = " + comparator2);
    
      // bcd为非静态方法,需要用对象来调用
      StringLengthCompare stringLengthCompare = new StringLengthCompare();
      Comparator<String> comparator3 = stringLengthCompare::bcd;
      System.out.println("comparator3 = " + comparator3);
    }

    3、接口的静态方法和默认方法

      Java 8 使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法使得开发者可以在不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。默认方法和抽象方法之间的区别在于抽象方法需要实现,而默认方法不需要。接口提供的默认方法会被接口的实现类继承或者覆写,例子代码如下:

    private interface Defaulable {
        // Interfaces now allow default methods, the implementer may or 
        // may not implement (override) them.
        default String notRequired() { 
            return "Default implementation"; 
        }        
    }
    Defaulable
    private static class DefaultableImpl implements Defaulable {
    }
    DefaultableImpl
    private static class OverridableImpl implements Defaulable {
        @Override
        public String notRequired() {
            return "Overridden implementation";
        }
    }
    OverridableImpl

    Defaulable 接口使用关键字 default 定义了一个默认方法 notRequired()。DefaultableImpl 类实现了这个接口,同时默认继承了这个接口中的默认方法;OverridableImpl 类也实现了这个接口,但覆写了该接口的默认方法,并提供了一个不同的实现。

    Java 8带来的另一个有趣的特性是在接口中可以定义静态方法,例子代码如下:

    private interface DefaulableFactory {
        // Interfaces now allow static methods
        static Defaulable create( Supplier< Defaulable > supplier ) {
            return supplier.get();
        }
    }
    DefaulableFactory

    下面的代码片段整合了默认方法和静态方法的使用场景:

    public static void main( String[] args ) {
        Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
        System.out.println( defaulable.notRequired() );
    
        defaulable = DefaulableFactory.create( OverridableImpl::new );
        System.out.println( defaulable.notRequired() );
    }

    这段代码输入结果如下:

    Default implementation
    Overridden implementation

    由于JVM上的默认方法的实现在字节码层面提供了支持,因此效率非常高。默认方法允许在不打破现有继承体系的基础上改进接口。该特性在官方库中的应用是:给java.util.Collection接口添加新方法,如stream()、parallelStream()、forEach() 和removeIf() 等等。尽管默认方法有这么多好处,但在实际开发中应该谨慎使用:在复杂的继承体系中,默认方法可能引起歧义和编译错误。

    注意:实现接口的类或者子接口不会继承接口中的静态方法

    4、重复注解

    在 Java学习之==>注解 这篇文章中有关于重复注解的介绍和使用。重复注解也是在 Java 8 中才开始支持的。

    三、Java 官方库的新特性

    1、Streams

    新增的 Stream API(java.util.stream)将函数式编程引入了 Java 库中。这是目前为止最大的一次对 Java 库的完善,以便开发者能够写出更加有效、更加简洁和紧凑的代码。Steam API 极大的简化了集合操作(后面我们会看到不止是集合)。

    Stream概述

    • 非主流式定义: 像写SQL一样来处理集合;
    • 理解类定义: 流式处理;
    • 流式处理学习路线: 创建,操作(中间操作,终止操作);

    Stream创建

    • Collection等集合接口实现的stream()方法和parallelStream()方法;
    • Arrays提供的数组流;
    • Stream类提供的静态创建方法of();
    public class Demo {
    
      public static void main(String[] args) {
        /**
         * 创建Stream流,有三种方式
         */
        // 第一种,集合类自带的方法
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
    
        Set<String> set = null;
        Stream<String> stream1 = set.stream();
    
        // 第二种,数组类流的创建
        int[] arr = new int[]{1, 2, 3};
        IntStream stream2 = Arrays.stream(arr);
    
        /**
         * public static<T> Stream<T> of(T... values) {
         *   return Arrays.stream(values);
         *  }
         */
        // 第三种,Stream接口自己提供的of方法,从实现来看是和第二种是一样的
        Stream<String> stream3 = Stream.of("", "", "");
      }
    }
    创建Stream流的三种方式

    Stream中间操作

    • 过滤::filter;
    • 切片 & 分页:sklip , limit;
    • 去重:distinct(去重的对象需要实现hashCode和equals);
    • 映射:map, flatMap;
    • 排序:sort;

    Stream终止操作

    • 匹配
      • allMatch:检查是否匹配所有元素;
      • anyMatch:检查是否匹配至少一个元素;
      • noneMatch:检查是否没有匹配所有元素
    • 查找
      • findFirst:查找找到的第一个元素;
      • findAny:查找找到的任意一个元素
    • 计算流中元素个数:count();
    • 计算流中元素的最大/最小值:max() , min();
    • 内部迭代:forEach;
    • 收集:collect;

    下面我们来举例操作一下:

    首先定义两个实体类 Account 和 User 

    @Setter
    @Getter
    @ToString
    public class Account {
    
      private int id;
    
      private String accountName;
    
      private boolean isInner;
      private boolean isA;
      private boolean isB;
      private boolean isC;
    
      private String type;
    
      private List<User> users;
    
      private Account() {
      }
    
      private Account(int id, String accountName, boolean isInner, String type, List<User> users) {
        this.id = id;
        this.accountName = accountName;
        this.isInner = isInner;
        this.type = type;
        this.users = users;
      }
    
      public Account(int id, String accountName, boolean isInner, boolean isA, boolean isB, boolean isC,
          String type) {
        this.id = id;
        this.accountName = accountName;
        this.isInner = isInner;
        this.isA = isA;
        this.isB = isB;
        this.isC = isC;
        this.type = type;
      }
    
      public static Account of(int id, String accountName, boolean isInner, String type,
          List<User> users) {
        return new Account(id, accountName, isInner, type, users);
      }
    
      public static Account of(int id, String accountName, boolean isInner, boolean isA, boolean isB,
          boolean isC,
          String type) {
        return new Account(id, accountName, isInner, isA, isB, isC, type);
      }
    
      @Override
      public boolean equals(Object o) {
        if (this == o) {
          return true;
        }
        if (o == null || getClass() != o.getClass()) {
          return false;
        }
    
        Account account = (Account) o;
    
        if (id != account.id) {
          return false;
        }
        return accountName != null ? accountName.equals(account.accountName)
            : account.accountName == null;
      }
    
      @Override
      public int hashCode() {
        int result = id;
        result = 31 * result + (accountName != null ? accountName.hashCode() : 0);
        return result;
      }
    }
    Account
    @Setter
    @Getter
    @ToString
    public class User {
    
      private int id;
    
      private String name;
    
      private User() {
      }
    
      private User(int id, String name) {
        this.id = id;
        this.name = name;
      }
    
      public static User of(int id, String name) {
        return new User(id, name);
      }
    
      // @Override
      // public boolean equals(Object o) {
      //   if (this == o) {
      //     return true;
      //   }
      //   if (o == null || getClass() != o.getClass()) {
      //     return false;
      //   }
      //   User user = (User) o;
      //   return id == user.id &&
      //       Objects.equal(name, user.name);
      // }
      //
      // @Override
      // public int hashCode() {
      //   return Objects.hashCode(id, name);
      // }
    
    
      @Override
      public boolean equals(Object o) {
        if (this == o) {
          return true;
        }
        if (o == null || getClass() != o.getClass()) {
          return false;
        }
        User user = (User) o;
        return id == user.id;
      }
    
      @Override
      public int hashCode() {
        return Objects.hashCode(id);
      }
    }
    User

    生成 Account 对象集合的类 AccountFactory

    public class AccountFactory {
    
      public static List<Account> getSimpleAccounts() {
    
        List<Account> accounts = new ArrayList<>();
    
        accounts.add(Account.of(1, "微信支付1账户", false, "出款", UserFactory.getSimpleUsers(true)));
        accounts.add(Account.of(2, "微信支付2账户", false, "入款", UserFactory.getSimpleUsers(true)));
        accounts.add(Account.of(3, "微信支付3账户", true, "出款", UserFactory.getSimpleUsers(false)));
        accounts.add(Account.of(4, "微信支付4账户", true, "入款", UserFactory.getSimpleUsers(true)));
        accounts.add(Account.of(5, "微信支付5账户", false, "出款", UserFactory.getSimpleUsers(false)));
        accounts.add(Account.of(6, "微信支付6账户", false, "入款", UserFactory.getSimpleUsers(true)));
        accounts.add(Account.of(7, "微信支付7账户", false, "出款", UserFactory.getSimpleUsers(false)));
        accounts.add(Account.of(8, "微信支付8账户", true, "出款", UserFactory.getSimpleUsers(true)));
        accounts.add(Account.of(9, "微信支付9账户", true, "入款", UserFactory.getSimpleUsers(false)));
        accounts.add(Account.of(10, "微信支付10账户", true, "出款", UserFactory.getSimpleUsers(true)));
        accounts.add(Account.of(11, "微信支付11账户", true, "入款", UserFactory.getSimpleUsers(true)));
        accounts.add(Account.of(12, "微信支付12账户", false, "出款", UserFactory.getSimpleUsers(true)));
    
        return accounts;
      }
    
      public static List<Account> getSimpleABCAccounts() {
    
        List<Account> accounts = new ArrayList<>();
    
        accounts.add(Account.of(1, "微信支付1账户", false, false, true, true, "出款"));
        accounts.add(Account.of(2, "微信支付2账户", false, false, false, true, "入款"));
        accounts.add(Account.of(3, "微信支付3账户", true, false, true, false, "出款"));
        accounts.add(Account.of(4, "微信支付4账户", true, false, true, true, "入款"));
        accounts.add(Account.of(5, "微信支付5账户", false, false, false, false, "出款"));
        accounts.add(Account.of(6, "微信支付6账户", false, false, true, true, "入款"));
        accounts.add(Account.of(7, "微信支付7账户", false, false, false, false, "出款"));
        accounts.add(Account.of(8, "微信支付8账户", true, false, false, true, "出款"));
        accounts.add(Account.of(9, "微信支付9账户", true, false, true, true, "入款"));
        accounts.add(Account.of(10, "微信支付10账户", true, false, false, false, "出款"));
        accounts.add(Account.of(11, "微信支付11账户", true, false, false, true, "入款"));
        accounts.add(Account.of(12, "微信支付12账户", false, false, true, true, "出款"));
    
        return accounts;
      }
    
      public static void printAccount(List<Account> accounts) {
        for (Account account : accounts) {
          System.out.println("account = " + account);
        }
      }
    
      public static void printAccount(Map<String, List<Account>> accounts) {
        accounts.forEach((key, val) -> {
          System.out.println("groupName:" + key);
          for (Account account : val) {
            System.out.println("		 account:" + account);
          }
        });
      }
    }
    AccountFactory

    生成 User 对象集合的类 UserFactory

    public class UserFactory {
    
      public static List<User> getSimpleUsers(boolean type) {
    
        List<User> users = Lists.newArrayList();
    
        if (type) {
          users.add(User.of(1, "张三"));
          users.add(User.of(1, "李四"));
          users.add(User.of(1, "王五"));
        } else {
          users.add(User.of(1, "张三"));
          users.add(User.of(1, "李四"));
          users.add(User.of(1, "王五"));
          users.add(User.of(1, "王二麻子"));
          users.add(User.of(1, "小淘气"));
        }
    
        return users;
      }
    
      public static List<User> getSimpleUsers() {
    
        List<User> users = Lists.newArrayList();
    
        users.add(User.of(1, "张三"));
        users.add(User.of(1, "李四"));
        users.add(User.of(1, "王五"));
        users.add(User.of(1, "王五"));
        users.add(User.of(1, "王五"));
        users.add(User.of(1, "王五"));
        users.add(User.of(1, "王五"));
        users.add(User.of(1, "王二麻子"));
        users.add(User.of(1, "小淘气"));
    
        return users;
      }
    }
    UserFactory

    以下为测试代码:

    public class StreamDemo1 {
    
      /**
       * 过滤:原始写法
       */
      @Test
      public void test1() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
        List<Account> accs = new ArrayList<>();
        for (Account account : accounts) {
          if (account.isInner()) {
            accs.add(account);
          }
        }
        AccountFactory.printAccount(accs);
      }
    
      /**
       * 过滤:java8写法
       */
      @Test
      public void test2() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
        List<Account> accs = accounts
            .stream() // 创建流
            .filter(Account::isInner) // 中间操作
            .collect(Collectors.toList()); // 终止操作
        AccountFactory.printAccount(accs);
      }
    
      /**
       * 分组:原始写法
       */
      @Test
      public void test3() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        Map<String, List<Account>> group = new HashMap<>();
        for (Account account : accounts) {
          if (group.containsKey(account.getType())) {
            group.get(account.getType()).add(account);
          } else {
            List<Account> acc = new ArrayList<>();
            acc.add(account);
            group.put(account.getType(), acc);
          }
        }
        AccountFactory.printAccount(group);
      }
    
      /**
       * 分组:java8的写法
       */
      @Test
      public void test4() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        Map<String, List<Account>> group = accounts
            .stream()
            .collect(Collectors.groupingBy(Account::getType));
        AccountFactory.printAccount(group);
      }
    
      /**
       * 分组, 对内部账户进行分组
       */
      @Test
      public void test5() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        Map<String, List<Account>> group = new HashMap<>();
        for (Account account : accounts) {
    
          if (!account.isInner()) {
            continue;
          }
    
          if (account.isA()) {
            continue;
          }
    
          if (!account.isB()) {
            continue;
          }
    
          if (group.containsKey(account.getType())) {
            group.get(account.getType()).add(account);
          } else {
            List<Account> acc = new ArrayList<>();
            acc.add(account);
            group.put(account.getType(), acc);
          }
        }
        AccountFactory.printAccount(group);
      }
    
      /**
       * 基于java8的分组,对内部账户进行分组
       */
      @Test
      public void test6() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        Map<String, List<Account>> group = accounts
            .stream()
            .filter(Account::isInner)
            .filter(account -> !account.isB())
            .filter(Account::isC)
            .collect(Collectors.groupingBy(Account::getType));
    
        AccountFactory.printAccount(group);
      }
    
      @Test
      public void test7() {
    
        /**
         * filter是中间操作
         * filter操作完以后Stream对象类型不变
         */
        Stream<String> stream = Stream.of("abc_d", "ef", "abc_123")
            .filter(str -> str.startsWith("abc_"));
    
        /**
         * collect是终止操作
         * collect操作完以后Stream对象类型变成其他类型了
         */
        List<String> collect = Stream.of("abc_d", "ef", "abc_123")
            .filter(str -> str.startsWith("abc_"))
            .collect(Collectors.toList());
    
        for (String s : collect) {
          System.out.println(s);
        }
      }
    }
    StreamDemo1
    public class StreamDemo2 {
    
      /**
       * map:映射,获取对象的某个属性
       * 返回所有内部账户的账户名
       */
      @Test
      public void testMap() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        List<String> list = accounts.stream()
            .filter(Account::isInner)
            .map(Account::getAccountName)
            .collect(Collectors.toList());
    
        for (String s : list) {
          System.out.println(s);
        }
      }
    
      /**
       * skip:切片,去除前面几条
       */
      @Test
      public void testSkip() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        List<Account> list = accounts
                .stream()
                .skip(5)
                .collect(Collectors.toList());
        for (Account account : list) {
          System.out.println(account);
        }
      }
    
      /**
       * skip:切片,去除调前面几条
       * limit:分页,控制结果的数量
       */
      @Test
      public void testLimit() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        List<Account> list = accounts
                .stream()
                .skip(3)
                .limit(5)
                .collect(Collectors.toList());
        for (Account account : list) {
          System.out.println(account);
        }
      }
    
    
      /**
       * 拿出account中user列表的名字
       *
       * 去重
       */
      @Test
      public void testflatMap() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        // 这个搞不定
        List<List<String>> res = accounts.stream()
            .map(account -> {
              List<User> users = account.getUsers();
              return users.stream().map(User::getName).collect(Collectors.toList());
            })
            .distinct()
            .collect(Collectors.toList());
    
        System.out.println("res:" + res);
    
        List<String> res2 = accounts.stream()
            // [[1,2],[1,2,3],[1,2,3,4]]
            .flatMap(account -> account.getUsers().stream())
            //[1,2,1,2,3,1,2,3,4]
            .map(User::getName)
            .distinct()
            .collect(Collectors.toList());
        System.out.println("res2:" + res2);
      }
    }
    StreamDemo2
    public class StreamDemo3 {
    
      @Test
      public void testMaxOrMin() {
    
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        Optional<Integer> optional = accounts.stream()
            .filter(Account::isInner)
            .map(Account::getId)
                /**
                 * peek,调试时输出值
                 */
            .peek(System.out::println)
            .max(Integer::compare);
    
        Integer maxId = optional.get();
    
        System.out.println("maxId = " + maxId);
      }
    
      @Test
      public void testForeach() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        accounts.stream()
            .filter(Account::isInner)
            .map(Account::getId)
            .forEach(System.out::println);
      }
    
      @Test
      public void testFind() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        Optional<Integer> optional = accounts.stream()
            .filter(Account::isInner)
            .map(Account::getId)
            .findAny();
    
        System.out.println("optional.get() = " + optional.get());
      }
    
      @Test
      public void testMatch() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
    
        boolean match = accounts.stream()
            .anyMatch(Account::isInner);
        System.out.println("match = " + match);
      }
    
      @Test
      public void testMapForeach() {
        Map<String, String> mapData = Maps.newHashMap();
    
        mapData.put("hello", "hi");
        mapData.put("yes", "no");
    
        mapData.forEach((key, val) -> {
          System.out.println(key + "," + val);
        });
      }
    }
    StreamDemo3
    public class StreamDemo4 {
    
      /**
       * 我以accountName作为key,来划分Account
       *
       * list<account> = [account,account]
       *
       * map<string,account> = {(accountName,account),(accountName,account)} map<string,account.id> =
       * {(accountName,account),(accountName,account)}
       */
      @Test
      public void test1() {
        List<Account> accounts = AccountFactory.getSimpleAccounts();
         Map<String, Account> map = accounts
             .stream()
             .collect(Collectors.toMap(Account::getAccountName, account -> account));
    
         map.forEach((key, val) -> {
           System.out.println(key + "," + val);
         });
      }
    
      @Test
      public void test2(){
        List<Account> accounts = AccountFactory.getSimpleAccounts();
        Map<String, Integer> map = accounts
                .stream()
                .collect(Collectors.toMap(Account::getAccountName, Account::getId));
    
        map.forEach((key, val) -> {
          System.out.println(key + "," + val);
        });
      }
    }
    StreamDemo4

    2、Date/Time API(JSR 310)

    3、Optional

    简介

    • Optional 类是一个可以为 null 的容器对象。如果值存在则 isPresent() 方法会返回true,调用get()方法会返回该对象。
    • Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
    • Optional 类的引入很好的解决空指针异常。

    类的属性和方法

    从图中我们可以看出,它的构造方法都是private修饰的,其实是一个单例模式的应用。

    下面我们主要来讲一下 filter() 和 map() 方法:

    filter 方法

    该方法是过滤方法,过滤符合条件的 Optional 对象,这里的条件用 Lambda 表达式来定义,源码如下:

        public Optional<T> filter(Predicate<? super T> predicate) {
            //如果入参predicate对象为null将抛NullPointerException异常
            Objects.requireNonNull(predicate);
            //如果Optional对象的值为null,将直接返回该Optional对象
            if (!isPresent())
                return this;
            //如果Optional对象的值符合限定条件(Lambda表达式来定义),返回该值,否则返回空的Optional对象
            else
                return predicate.test(value) ? this : empty();
        }

    map 方法

    map方法用于修改该值,并返回修改后的Optional对象,一般会在多级取值的时候用到,源码如下:

        public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
            //如果入参mapper对象为null将抛NullPointerException异常
            Objects.requireNonNull(mapper);
            //如果Optional对象的值为null,将直接返回该Optional对象
            if (!isPresent())
                return empty();
            //执行传入的lambda表达式,并返回经lambda表达式操作后的Optional对象
            else {
                return Optional.ofNullable(mapper.apply(value));
            }
        }

    举例:

    判断不为null然后进行操作

    public class Demo {
      /**
       * 不为null时进行操作
       * 原始写法
       */
      public static void doThing(String name) {
        if (name != null) {
          System.out.println(name);
        }
      }
    
      // 使用Optional的写法
      public static void doThingOptional(String name) {
        Optional.ofNullable(name).ifPresent(System.out::println);
      }
    }

    多层级取值

    public class Demo {
      
      // 原始写法
      public static String getAddress(User user) {
        if (user != null) {
          AddressEntity addressEntity = user.getAddressEntity();
          if (addressEntity != null) {
            String address = addressEntity.getAddress();
            if (address != null && address.length() > 3) {
              return address;
            }
          }
        }
        return null;
      }
    
      // 使用Optional的写法
      public static String getAddressOptional(User user) {
        return Optional.ofNullable(user)
                .map(u -> u.getAddressEntity())
                .map(a -> a.getAddress())
                .filter(s -> s.length() > 3)
                .orElse(null);
      }
    }

    四、JVM 的新特性

      使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。

  • 相关阅读:
    memcached事故
    总算会用sphinx生成文档了
    python tip
    抓包工具wireshark
    狗日的用户体验
    python tip
    pymmseg
    memcached事故
    windwos序列号
    7z fromat on ubuntu&replace my fujishu electric fan
  • 原文地址:https://www.cnblogs.com/L-Test/p/11577515.html
Copyright © 2020-2023  润新知