zoukankan      html  css  js  c++  java
  • java8新特性

    java8新特性:函数式编程,stream流,Optional 类!

    参考文献:

    理解、学习与使用 Java 中的 Optional

    Java8之Stream流(一)基础体验

    java8 stream流操作的flatMap(流的扁平化)

    java中使用Lambda表达式的5种语法

    Lambda语法

    • 标准写法

      Arrays.sort(arr, (String m, String n) -> Integer.compare(m.length(), n.length()));
      

      lambda表达式的标准写法由下面几点构成:

      • 以逗号分隔,以()关闭的形参:(Dog m, Dog n)
      • 箭头标记:->
      • 主体部分则是一个单表达式或者声明代码块。如下是单表达式形式:Integer.compare(m.getWeight(), n.getWeight())
    • 参数类型可以推断

      如果参数的类型可以根据上下文推断出来,则可以省略掉类型

    • 存在多行代码

      需要{} 括起来,且代码应该有明确的返回语句

      Arrays.sort(arr, (String m, String n) -> {
          if (m.length() > n.length())
              return -1;
          else
              return 0;
      });
      
    • 单个参数并可推断类型

      可以省略参数 “x” 的括号

    • 方法引用

      写成::形式,并省略参数。

      stream.forEach(System.out::println);
      
    • 没有参数

      () -> {for(int i=0; i<10; i++) doSomthing();}

    Optional 类

    包含有可选值的包装类,既可以含有对象也可以为空。

    常用方法

    • ofNullable()

      创建Optional对象:传入的对象即可能是 null 也可能是非 null,不会抛出异常NullPointerException

    • ifPresent()

      选择性执行语句:该方法除了执行检查,还接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式:

      opt.ifPresent( u -> assertEquals(user.getEmail(), u.getEmail()));
      

      这个例子中,只有 user 用户不为 null 的时候才会执行断言。

    • orElseGet()

      返回默认值:这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果:

      User result = Optional.ofNullable(user).orElseGet( () -> user2);
      

      orElse() 和 orElseGet() 的不同之处: Optional 对象返回非空值后,orElse() 方法仍然创建了 默认值 对象,而orElseGet() 方法不创建 默认值 对象。

    • orElseThrow()

      在对象为空的时候抛出异常,而不是返回备选的值:

      @Test(expected = IllegalArgumentException.class)
      public void whenThrowException_thenOk() {
          User result = Optional.ofNullable(user)
            .orElseThrow( () -> new IllegalArgumentException());
      }
      

      这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException

    • map()

    • filter()

    • Optional 类的链式方法

      String result = Optional.ofNullable(user)
        .flatMap(User::getAddress)
        .flatMap(Address::getCountry)
        .map(Country::getIsocode)
        .orElse("default");
      

    Stream流

    • 概念

      Java 8 中的 Stream 是对集合(Collection)对象功能的增强

      • 专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation)
      • 大批量数据操作 (bulk data operation)
      • 支持 Lambda 表达式
      • 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的
      • 作用更像一个高级版本的 Iterator,与迭代器不同点,Stream 可以并行化操作,迭代器只能命令式地、串行化操作
      • Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程
    • "终端操作"&"中间操作"

      • 终端操作: 会消费流,这种操作会产生一个结果的

        iterator()、 spliterator()、min()、max()、forEach()

      • 中间操作:会产生另一个流,类似管道

    • 缩减操作

      缩减操作的三个约束条件

      • 无状态
      • 不干预
      • 关联性

      reduce()-通用的方法,而min()和max(),count()这些操作称为特例缩减。

      T reduce(T identity, BinaryOperator<T> accumulator);//1
      Optional<T> reduce(BinaryOperator<T> accumulator);//2
      

      第一个版本的identity为初始化值(兼容单个值的情况),求和的时候为0,求积的时候它的值为1。

      其中的accumulator是一个BinaryOperator的类型,他是java.util.function包中声明的函数式接口,它扩展了BiFunction函数式接口.

      @FunctionalInterface
      public interface BinaryOperator<T> extends BiFunction<T,T,T> {
      }
      
      @FunctionalInterface
      public interface BiFunction<T, U, R> {
         R apply(T t, U u);//notice
      }
      

      apply()对他的两个操作数(t,u)应用到同一个函数上,并返回结果

      # 直接函数式编程
      reduce((a, b) -> a + b)
      
    • 并行流

      对流调用一下parallel(),或者Collection.parallelStream()

      在reduce()的第三版本比较适合并行流,accumulator被称为累加器, combiner被称为合成器, combiner定义的函数将accumulator提到的两个值合并起来

      public interface Stream<T> extends BaseStream<T, Stream<T>> {
      //、、、忽略其他无关紧要的元素
      <U> U reduce(U identity,
                BiFunction<U, ? super T, U> accumulator,
                BinaryOperator<U> combiner);
      }
      
    • 顺序流&并行流&无序流之间的切换操作

      在使用并行流时,有时候流是无序的就能获得性能上的提升,可以通过BaseStream接口提供的unordered()方法把流转换成一个无序流之后,再进行各种操作

      forEach()方法不一定会保留并行流的顺序,如果在对并行流的每个元素执行操作时,也希望保留顺序,那么可以使用forEachOrdered()方法,它的用法和forEach()是一样的。

      forEach底层采用的是迭代器的方式。如果数据结构是ArrayList这种数据结构,那你可以采用for,但是你的数据结构如果是LinkList那你千万别再用for,应该果断采用forEach,因为数据一多起来的,for此时的效率低得可怜

    • 映射

      • filter方法

        filter方法的参数是一个Predicate对象,即一个从T到boolean的函数,返回为true的

      • map方法

        对一个流中的值进行某种形式的转换,返回的是对应类型的Stream对象。

      • flatMap方法

        flat -- 摊平,流的扁平化

        flatMap()操作能把原始流中的元素进行一对多的转换,并且将新生成的元素全都合并到它返回的流里面,即重新整合为一个流。

        将多个Stream连接成一个Stream,这时候不是用新值取代Stream的值,与map有所区别,这是重新生成一个Stream对象取而代之。

        String[] words = new String[]{"Hello","World"};
        List<String> a = Arrays.stream(words)
            .map(word -> word.split(""))
            .flatMap(Arrays::stream)
            .distinct()
            .collect(toList());
        a.forEach(System.out::print);
        // 输出 ["H","e","l","o","W","r","d"]
        
    • 收集功能

      • Collectors

        public static <T>  Collector<T, ?, List<T>> toList()
        public static <T> Collector<T, ?, Set<T>> toSet()
        

        用法:steam.collect(Collectors.toList)

      • collect方法

         <R> R collect(Supplier<R> supplier,
                          BiConsumer<R, ? super T> accumulator,
                          BiConsumer<R, R> combiner);
        

        类似上面的缩减操作。其中supplier指定如何创建用于保存结果的对象,比如,要使用ArrayList作为结果的集合,需要指定它的构造函数,accumulator函数是将一个元素添加到结果中,而combiner函数合并两个部分的结果

        private static void learnCollect() {
                List<HeroPlayerGold> lists = new ArrayList<>();
                lists.add(new HeroPlayerGold("盖伦", "RNG-Letme", 100));
                lists.add(new HeroPlayerGold("诸葛亮", "RNG-Xiaohu", 300));
                lists.add(new HeroPlayerGold("露娜", "RNG-MLXG", 300));
                lists.add(new HeroPlayerGold("狄仁杰", "RNG-UZI", 500));
                lists.add(new HeroPlayerGold("牛头", "RNG-Ming", 500));
        
        
                lists.stream().collect(HashSet::new,
                                       HashSet::add,
                                       HashSet::addAll
                ).forEach(System.out::println);
        }
        
    • Spliterator

      Spliterator是Java8新增的一种迭代器,Spliterator支持并行迭代。

    Stream 常用方法

    参考:JDK 8 通过Stream 对List,Map操作和互转

    • list 转 map

      List<Student> list = Arrays.asList(new Student(1, 18, "阿龙", GenderColumn.BOY.getCode()),
                                             new Student(2, 17, "小花", GenderColumn.GIRL.getCode()),
                                             new Student(3, 17, "阿浪", GenderColumn.LADYBOY.getCode()));
      // value 为对象 student -> student jdk1.8返回当前对象
      Map<Integer, Student> map = list.stream().collect(Collectors.toMap(Student::getId, student -> student));
      
    • map 转 map

      Map<String, Map<String, Object>> map1 = aggregationMap.entrySet().stream().collect(Collectors.toMap(
                      e -> e.getKey(),
                      e -> {
                          List<String> options = ((StringTerms) e.getValue()).getBuckets().stream().map(StringTerms.Bucket::getKeyAsString).collect(Collectors.toList());
                          Map<String, Object> map = new HashMap<>();
                          map.put("options", options);
                          return map;
                      }
              ));
      
      
    • map 转 list

      // stream map 转 list
      List<Map<String, Object>> paramMapList = aggregationMap.entrySet().stream().map((e) -> {
                  List<String> options = ((StringTerms) e.getValue()).getBuckets().stream().map(StringTerms.Bucket::getKeyAsString).collect(Collectors.toList());
                  Map<String, Object> map = new HashMap<>();
                  map.put("k", e.getKey());
                  map.put("options", options);
                  return map;
      }).collect(Collectors.toList());
      
      
  • 相关阅读:
    记录一波三折的ViewPager与PagerAdapter
    关于加载网络图片时候 ,URL.openstream抛出异常的问题的解决
    android studio 导入第三方库的方法
    sysctl.conf优化
    SSH无需密码密钥登录
    vps添加swap
    Android之基本常见知识(持续更新)
    SSH无需密码密钥登录
    python __name__
    python code
  • 原文地址:https://www.cnblogs.com/jarvankuo/p/11955011.html
Copyright © 2011-2022 走看看