zoukankan      html  css  js  c++  java
  • java8新特性学习:stream与lambda

    Streams api

    image

    对 Stream 的使用就是实现一个 filter-map-reduce 过程,产生一个最终结果,或者导致一个副作用(side effect)。

    流的操作类型分为两种:

    • Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
    • Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
    • short-circuiting。用以指:
      对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。
      对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。
      当操作一个无限大的 Stream,而又希望在有限时间内完成操作,则在管道内拥有一个 short-circuiting 操作是必要非充分条件。

    map/flatMap

    map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。还有一些场景,是一对多映射关系的,这时需要 flatMap。

    reduce

    主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。

    Optional

    Optional 中我们真正可依赖的应该是除了 isPresent() 和 get() 的其他方法:

    public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
    public T orElse(T other)
    public T orElseGet(Supplier<? extends T> other)
    public void ifPresent(Consumer<? super T> consumer)
    public Optional<T> filter(Predicate<? super T> predicate)
    public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
    

    构造方法

    Optional 的三种构造方式:

    1. Optional.of(obj),
    2. Optional.ofNullable(obj) 和
    3. 明确的 Optional.empty()
    • 存在即返回, 无则提供默认值
    return user.orElse(null);  //而不是 return user.isPresent() ? user.get() : null;
    return user.orElse(UNKNOWN_USER);
    
    • 存在即返回, 无则由函数来产生
    return user.orElseGet(() -> fetchAUserFromDatabase()); //而不要 return user.isPresent() ? user: fetchAUserFromDatabase();
    
    • 存在才对它做点什么
    user.isPresent(System.out::println);
    
    • map 函数隆重登场

    当 user.isPresent() 为真, 获得它关联的 orders, 为假则返回一个空集合时, 我们用上面的 orElse, orElseGet 方法都乏力时, 那原本就是 map 函数的责任

    return user.map(u -> u.getOrders()).orElse(Collections.emptyList())
    
    return user.map(u -> u.getUsername())
               .map(name -> name.toUpperCase())
               .orElse(null);
    
    • flatMap

    flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。

    upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
    System.out.println(upperName.orElse("No value found"));//输出SANAULLA
    
    • filter

    如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。

    Optional<String> longName = name.filter((value) -> value.length() > 6);
    System.out.println(longName.orElse("The name is less than 6 characters"));//输出Sanaulla
     
    //另一个例子是Optional值不满足filter指定的条件。
    Optional<String> anotherName = Optional.of("Sana");
    Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
    //输出:name长度不足6字符
    System.out.println(shortName.orElse("The name is less than 6 characters"));
    

    lambda

    Java中Lambda表达式的使用

    虽然看着很先进,其实Lambda表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。

    建议不要乱用,因为这就和某些很高级的黑客写的代码一样,简洁,难懂,难以调试,维护人员想骂娘.

    当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。

    lambda表达式有个限制,那就是只能引用 final 或 final 局部变量,这就是说不能在lambda内部修改定义在域外的变量。

    Lambda表达式的语法
    基本语法:
    (params) -> expression
    (params) -> statement
    (params) -> { statements }
    
    // 1. 不需要参数,返回值为 5  
    () -> 5  
      
    // 2. 接收一个参数(数字类型),返回其2倍的值  
    x -> 2 * x  
      
    // 3. 接受2个参数(数字),并返回他们的差值  
    (x, y) -> x – y  
      
    // 4. 接收2个int型整数,返回他们的和  
    (int x, int y) -> x + y  
      
    // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
    (String s) -> System.out.print(s)
    
    players.forEach((player) -> System.out.print(player + "; "));  
       
    // 在 Java 8 中使用双冒号操作符(double colon operator)  
    players.forEach(System.out::println);  
    
    // 使用匿名内部类  
    btn.setOnAction(event -> System.out.println("Hello World!"));  
    
    show.addActionListener((e) -> {
        System.out.println("Light, Camera, Action !! Lambda expressions Rocks");
    });
    
    new Thread(() -> System.out.println("Hello world !")).start(); 
    Runnable race2 = () -> System.out.println("Hello world !"); 
    
    //排序
    Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));   
    
    • 如何在lambda表达式中加入Predicate
    Predicate<String> startsWithJ = (n) -> n.startsWith("J");
    Predicate<String> fourLetterLong = (n) -> n.length() == 4;
    names.stream()
        .filter(startsWithJ.and(fourLetterLong))
        .forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));
    
    • Java 8中使用lambda表达式的Map和Reduce示例
    List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
    double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get();
    
    • 通过过滤创建一个String列表
    // 创建一个字符串列表,每个字符串长度大于2
    List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList());
    System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);
    
    • 对列表的每个元素应用函数
    // 将字符串换成大写并用逗号链接起来
    List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada");
    String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
    System.out.println(G7Countries);
    
    • 计算集合元素的最大值、最小值、总和以及平均值
    //获取数字的个数、最小值、最大值、总和以及平均值
    List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
    IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
    System.out.println("Highest prime number in List : " + stats.getMax());
    System.out.println("Lowest prime number in List : " + stats.getMin());
    System.out.println("Sum of all prime numbers : " + stats.getSum());
    System.out.println("Average of all prime numbers : " + stats.getAverage());
    

    方法引用

    • 第一种方法引用是构造器引用,它的语法是Class::new,或者更一般的Class< T >::new。
    • 第二种方法引用是静态方法引用,它的语法是Class::static_method。
    • 第三种方法引用是特定类的任意对象的方法引用,它的语法是Class::method。请注意,这个方法没有参数。
    String[] stringArray = { "Barbara", "James", "Mary", "John",
        "Patricia", "Robert", "Michael", "Linda" };
    Arrays.sort(stringArray, String::compareToIgnoreCase);
    The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).
    
    
    public void repair() {   
            System.out.println( "Repaired " + this.toString() );
        }
    cars.forEach( Car::repair );
    
    • 第四种方法引用是特定对象的方法引用,它的语法是instance::method。请注意,这个方法接受一个Car类型的参数
    class ComparisonProvider {
        public int compareByName(Person a, Person b) {
            return a.getName().compareTo(b.getName());
        }
            
        public int compareByAge(Person a, Person b) {
            return a.getBirthday().compareTo(b.getBirthday());
        }
    }
    ComparisonProvider myComparisonProvider = new ComparisonProvider();
    Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
    
    
    final Car police = Car.create( Car::new );
    cars.forEach( police::follow );
    public void follow( final Car another ) {
            System.out.println( "Following the " + another.toString() );
        }
    

    Java虚拟机(JVM)的新特性

    PermGen空间被移除了,取而代之的是Metaspace(JEP 122)。JVM选项-XX:PermSize与-XX:MaxPermSize分别被-XX:MetaSpaceSize与-XX:MaxMetaspaceSize所代替。

    参考


    tips:本文属于自己学习和实践过程的记录,很多图和文字都粘贴自网上文章,没有注明引用请包涵!如有任何问题请留言或邮件通知,我会及时回复。

  • 相关阅读:
    Hibernate unsaved-value 属性
    ResulsetHandler九个实现类
    Introspector内省和反射的区别.
    数据库表、字段命名规范
    Linux 时间同步 ntpdate
    http升级https改造方案
    org.apache.tomcat.util.net.NioEndpoint,打开的文件过多
    kafka常用命令
    elasticsearch.yml 配置说明
    getDate() 各种时间格式
  • 原文地址:https://www.cnblogs.com/small-k/p/8318739.html
Copyright © 2011-2022 走看看