美文网首页
java8特性总结

java8特性总结

作者: 知止9528 | 来源:发表于2019-01-25 23:30 被阅读4次
    1. Lambda 表达式
      格式
    (parameters) -> expression
    (parameters) -> { statements; }
    

    伪代码如下

    public static void main(String[] args) {
            JFrame jFrame = new JFrame("My JFrame");
            JButton jButton = new JButton("My button");
            jButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    
                }
            });
        }
    

    我们常常使用的匿名内部类如上

    使用Lambda 表达式改写后如下

    jButton.addActionListener(event -> System.out.println("button pressed"));
    

    原理

    @FunctionalInterface 函数式接口

    如果接口只有一个抽象方法,那么它就是一个函数式接口
    如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口

    @FunctionalInterface
    interface  MyInterface{
        void test();
    
        String toString();
    }
    
    public class Test {
    
        public  void myTest(MyInterface myInterface){
            System.out.println("进入myTest");
            myInterface.test();
            System.out.println("进入myTest执行完毕");
        }
        public static void main(String[] args) {
            Test test = new Test();
    
            test.myTest(()->{
                System.out.println("输出mytest");
            });
            System.out.println("------------");
           
            MyInterface myInterface =()->{
                System.out.println("hello");
            };
        }
    }
    

    小结

    即Java的函数式编程,其实只是把方法看作了一个对象,传入的还是一个接口,最终还是通过函数式接口去调用对应的方法,这也是java8为什么会有Default方法的原因之一,一个是为了兼容,子类不用去实现,就可以拥有方法的功能。

    jdk8里面的函数式接口
    JDK 1.8 新增加函数接口
    统一在java.util.function包下面

    接口 说明
    BiConsumer<T,U> 代表了一个接受两个输入参数的操作,并且不返回任何结果。
    BiFunction<T,U,R> 代表了一个接受两个输入参数的方法,并且返回一个结果。
    BinaryOperator<T> 代表了一个作用于两个同类型操作符的操作,并且返回了操作符同类型的结果。
    BiPredicate<T,U> 代表了一个两个参数的 boolean 值方法。
    BooleanSupplier 代表了 boolean 值结果的提供方。
    Consumer<T> 代表了接受一个输入参数并且无返回的操作。
    DoubleBinaryOperator 代表了作用于两个 double 值操作符的操作,并且返回一个 double 值的结果。
    DoubleConsumer 代表一个接受 double 值参数的操作,并且不返回结果。
    DoubleFunction<R> 代表接受一个 double 值参数的方法,并且返回结果。
    DoublePredicate<R> 代表一个拥有 double 值参数的 boolean 值方法。
    DoubleSupplier 代表一个 double 值结构的提供方。
    DoubleToIntFunction 接受一个 double 类型输入,返回一个 int 类型结果。
    DoubleToLongFunction 接受一个 double 类型输入,返回一个 long 类型结果。
    DoubleUnaryOperator 接受一个参数同为类型 double,返回值类型也为 double 。
    Function<T,R> 接受一个输入参数,返回一个结果。
    IntBinaryOperator 接受两个参数同为类型 int,返回值类型也为 int 。
    IntConsumer 接受一个 int 类型的输入参数,无返回值 。
    IntFunction<R> 接受一个 int 类型输入参数,返回一个结果 。
    IntPredicate 接受一个 int 输入参数,返回一个 boolean 的结果。
    IntSupplier 无参数,返回一个 int 类型结果。
    IntToDoubleFunction 接受一个 int 类型输入,返回一个 double 类型结果 。
    IntToLongFunction 接受一个 int 类型输入,返回一个 long 类型结果。
    IntUnaryOperator 接受一个参数同为类型 int,返回值类型也为 int 。
    LongBinaryOperator 接受两个参数同为类型 long,返回值类型也为 long。
    LongConsumer 接受一个 long 类型的输入参数,无返回值。
    LongFunction<R> 接受一个 long 类型输入参数,返回一个结果。
    LongPredicate 接受一个 long 输入参数,返回一个 boolean 类型结果。
    LongSupplier 无参数,返回一个结果 long 类型的值。
    LongToDoubleFunction 接受一个 long 类型输入,返回一个 double 类型结果。
    LongToIntFunction 接受一个 long 类型输入,返回一个int类型结果。
    LongUnaryOperator 接受一个参数同为类型 long,返回值类型也为 long。
    ObjDoubleConsumer<T> 接受一个 object 类型和一个 double 类型的输入参数,无返回值。
    ObjIntConsumer<T> 接受一个 object 类型和一个 int 类型的输入参数,无返回值。
    ObjLongConsumer<T> 接受一个 object 类型和一个 long 类型的输入参数,无返回值。
    Predicate<T> 接受一个输入参数,返回一个 boolean 结果。
    Supplier<T> 无参数,返回一个结果。
    ToDoubleBiFunction<T,U> 接受两个输入参数,返回一个 double 类型结果。
    ToDoubleFunction<T> 接受一个输入参数,返回一个 double 类型结果。
    ToIntBiFunction<T,U> 接受两个输入参数,返回一个 int 类型结果。
    ToIntFunction<T> 接受一个输入参数,返回一个 int 类型结果。
    ToLongBiFunction<T,U> 接受两个输入参数,返回一个 long 类型结果。
    ToLongFunction<T> 接受一个输入参数,返回一个 long 类型结果。
    UnaryOperator<T> 接受一个参数为类型 T,返回值类型也为 T。

    方法引用

    可以直接引用已有 Java 类或对象(实例)的方法或构造器。与 Lambda 联合使用,可以使语言的构造更紧凑简洁,减少冗余代码。
    通过方法的名字来指向一个方法。
    使用一对冒号 :: 。
    只是一个语法糖,并不是所有方法都可以使用方法引用

    有几种使用方式

    构造器引用

    语法为 Class::new,或者 Class< T >::new。

    静态方法引用

    语法为 Class::staticMethod。

    特定类的任意对象的方法引用

    语法为 Class::method。

    特定对象的方法引用

    语法为 instance::method。


    默认方法

    默认方法是接口可以有实现方法,而且不需要实现类去实现其方法。

    public interface IOperation {
       default void print(){
          System.out.println("");
       }
    }
    

    静态默认方法

    接口可以声明(并且可以提供实现)静态方法。

    public interface Operation {
       default void printA(){
          System.out.println("A");
       }
        // 静态方法
       static void printB(){
          System.out.println("B");
       }
    }
    

    Stream

    以一种声明的方式处理数据
    语法类似于SQL,即描述式的
    需要将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等
    元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

    List<Integer> transactionsIds = widgets.stream().filter(b -> b.getColor() == RED).sorted((x,y) -> x.getWeight() - y.getWeight()).mapToInt(Widget::getWeight).sum();
    
    

    像 filter 这样只描述 Stream,最终不产生新集合的方法叫作惰性求值方法。而像 sum 这样最终会从 Stream 产生值的方法叫作及早求值方法。
    在一个 Stream 操作中,可以有多次惰性求值,但有且仅有一次及早求值。

    小结
    Stream(流)是一个来自数据源的元素队列并支持聚合操作。

    元素是特定类型的对象,形成一个队列。 Java 中的 Stream 并不会存储元素,而是按需计算。
    数据源流的来源。 可以是集合,数组,I/O channel, 产生器 generator 等。
    聚合操作类似 SQL 语句一样的操作, 如 filter,map,reduce,find,match,sorted 等。
    中间操作(惰性求值)都会返回Stream,只有调用及早求值,才会返回最终结果

    流的分类

    有限长度,即有限流
    无限长度,即无限流,一般结合limit进行配合使用


    生成流的几种方式

    of

    其生成的 Stream 是有限长度的,Stream 的长度为其内的元素个数。

    返回

    Stream<Integer> integerStream = Stream.of(1, 2, 3);
    Stream<String> stringStream = Stream.of("A");
    

    generator

    返回一个 无限 长度的 Stream,其元素由 Supplier 接口的提供。

    1.在 Supplier 里是一个函数接口,只封装了一个 get() 方法,其用来返回任何泛型的值,该结果在不同的时间内,返回的可能相同也可能不相同,没有特殊的要求。
    2.通常用于随机数、常量的 Stream,或者需要前后元素间维持着某种状态信息的 Stream。
    3.把 Supplier 实例传递给 Stream.generate() 生成的 Stream,默认是串行(相对 parallel 而言)但无序的(相对 ordered 而言)。

    Stream.generate(java.lang.Math::random);
    

    iterate

    iterate方法,其返回的也是一个无限长度的 Stream,与 generate 方法不同的是,其是通过函数 f 迭代对给指定的元素种子而产生无限连续有序 Stream。

    Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);
    

    empty

    empty方法返回一个空的顺序 Stream,该 Stream 里面不包含元素项。

    Stream.empty();
    

    Collection 接口和数组的默认方法

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    // 获取对应的平方数
    List<Integer> squaresList = numbers.stream().map( i -> i*i).collect(Collectors.toList());
    

    在 Arrays 类,封装了一些列的 Stream 方法,不仅针对于任何类型的元素采用了泛型,更对于基本类型作了相应的封装,以便提升 Stream 的处理效率。

    int id[] = new int[]{1, 2, 3, 4};
    Arrays.stream(id).forEach(System.out::println);
    

    流的常见中间操作(Intermediate)

    concat

    1.concat 方法将两个 Stream 连接在一起,合成一个 Stream。
    2.若两个输入的 Stream 都是排序的,则新 Stream 也是排序的。
    3.若输入的 Stream 中任何一个是并行的,则新的 Stream 也是并行的。
    4.若关闭新的 Stream 时,原两个输入的 Stream 都将执行关闭处理

    Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5)).forEach(System.out::println);
    

    distinct

    distinct 方法以达到去除掉原 Stream 中重复的元素,生成的新 Stream 中没有没有重复的元素。

    Stream.of(1, 2, 3, 1, 2, 3).distinct().forEach(System.out::println);
    

    filter

    filter 方法用于通过设置的条件过滤出元素。

    // 获取空字符串的数量
    Stream.of("1", "2", "3", "4", "", "", "7", "", "").filter(string -> string.isEmpty()).count();
    

    map

    map 方法用于映射每个元素到对应的结果。

    // 获取对应的平方数
    Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).map(i -> i * i).collect(Collectors.toList());
    

    flatMap

    flatMap 方法与 map 方法类似,都是将原 Stream 中的每一个元素通过转换函数转换,不同的是,该换转函数的对象是一个 Stream,也不会再创建一个新的 Stream,而是将原 Stream的元素取代为转换的 Stream。
    原来是多个,会打平为一个,而map是原来是多和,返回的还是多个

    Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).flatMap(i -> i * i).collect(Collectors.toList());
    

    peek

    peek 方法生成一个包含原 Stream 的所有元素的新 Stream,同时会提供一个消费函数(Consumer实例),新 Stream 每个元素被消费的时候都会执行给定的消费函数,并且消费函数优先执行。

    Stream.of(1, 2, 3).peek(x -> System.out.print(x));
    

    skip

    skip 方法将过滤掉原 Stream 中的前 N 个元素,返回剩下的元素所组成的新 Stream。

    Stream.of(1, 2, 3,4,5) .skip(2) .forEach(System.out::println); 
    

    sorted

    sorted 方法将对原 Stream 进行排序,返回一个有序列的新 Stream。

    Stream.of(5, 4, 3, 2, 1).sorted().forEach(System.out::println);
    

    流的常见最终操作

    collect

    通过 collect 收集器,应用 Collector 工具。

    转换成其他集合
    toList

    List<Integer> collectList = Stream.of(1, 2, 3, 4).collect(Collectors.toList());
    

    toSet

    Set<Integer> collectSet = Stream.of(1, 2, 3, 4).collect(Collectors.toSet());
    

    toCollection
    其接受的函数参数必须继承于 Collection。

    TreeSet<Integer> collectSet = Stream.of(1, 2, 3, 4).collect(Collectors.toCollection(TreeSet::new));
    

    toMap
    备注:若 Stream 中重复值,导致 Map 中 key 重复,在运行时会报异常
    java.lang.IllegalStateException: Duplicate key

    public Map<Long, String> getIdNameMap(List<Account> accounts) {
        return accounts.stream().collect(Collectors.toMap(Account::getId, Account::getUsername));
    }
    

    其它

    方法 说明
    averagingDouble 求平均值,Stream 的元素类型为 double
    averagingInt 求平均值,Stream 的元素类型为 int
    averagingLong 求平均值,Stream 的元素类型为 long
    counting Stream 的元素个数
    maxBy 在指定条件下的,Stream 的最大元素。
    minBy 在指定条件下的,Stream 的最小元素。
    reducing reduce 操作,操作可以实现从 Stream 中生成一个值,其生成的值不是随意的,而是根据指定的计算模型。
    summarizingDouble 统计 Stream 的数据(double)状态,其中包括 count,min,max,sum 和平均。
    summarizingInt 统计 Stream 的数据(int)状态,其中包括 count,min,max,sum 和平均。、
    summarizingLong 统计 Stream 的数据(long)状态,其中包括 count,min,max,sum 和平均。、
    summingDouble 求和,Stream 的元素类型为 double
    summingInt 求和,Stream 的元素类型为 int
    summingLong 求和,Stream 的元素类型为 long
    max 最大值
    min 最小值

    对结果的分组与限制

    groupingBy

    Map<Boolean, List<Integer>> collectGroup= Stream.of(1, 2, 3, 4).collect(Collectors.groupingBy(it -> it > 3));
    

    limit

    Stream.of(1, 2, 3,4,5).limit(2).forEach(System.out::println);
    

    Optional

    Optional 类的引入很好的解决空指针异常。

    方法 说明
    static <T> Optional<T> empty() 返回空的 Optional 实例。
    boolean equals(Object obj) 判断其他对象是否等于 Optional。
    Optional<T> filter(Predicate<? super <T> predicate) 如果值存在,并且这个值匹配给定的 predicate,返回一个 Optional 用以描述这个值,否则返回一个空的 Optional。
    <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper) 如果值存在,返回基于 Optional 包含的映射方法的值,否则返回一个空的 Optional。
    T get() 如果在这个 Optional 中包含这个值,返回值,否则抛出异常:NoSuchElementException
    void ifPresent(Consumer<? super T> consumer) 如果值存在则使用该值调用 consumer , 否则不做任何事情。
    static <T> Optional<T> of(T value) 返回一个指定非 null 值的 Optional。
    static <T> Optional<T> ofNullable(T value) 如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。
    T orElse(T other) 如果存在该值,返回值, 否则返回 other
    T orElseGet(Supplier<? extends T> other) 如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。
    <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常

    相关文章

      网友评论

          本文标题:java8特性总结

          本文链接:https://www.haomeiwen.com/subject/ailbjqtx.html