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

    Java8发布了挺久了,而且有很大的变动。这里是一篇迟来的部分Java8新特性的总结。

    接口

    接口提供默认方法的实现,非static方法前必须有default关键字。

    default void print(Object a){
    ...
    }
    

    从这个角度来说,Java的接口更加接近Scala语法中的trait了。

    lambda

    lambda表达式也不是非常新的东西,在Python中早就引入过。现在Java引入lamda之后,很多代码都能够简化了。

    之前在算法题中经常需要写比较Comparator的实现,现在可以直接写一个lambda就行了:

    Arrays.sort(students,new Comparator<Student>(){
             @Override
                public int compare(Student s1, Student s2) {
                    return s1.getName().compareTo(s2.getName());
                }
    });
    //用lambda可以写为:
    Arrays.sort(students,(a,b)->(a.getName().compareTo(b.getName());
    

    lambda的作用域和匿名方法相同,可以访问:

    1. 外面的final本地变量(未显式声明为final的,会被隐式当做final来处理,在IDEA编辑器中会红色显式)。
    2. 所有的对象实例变量和类变量,并且可以修改它们
    3. 不可以访问接口的默认方法

    函数式接口

    函数式接口是只包含了一个抽象方法的接口(默认方法个数无限制)。

    函数式接口的声明和使用

    声明函数式接口可以用@FunctionalInterface注解,也可以不用:

    @FunctionalInterface
    public interface Comparator<T> {
    }
    

    使用函数式接口,通过把函数赋值给接口对象,实现把函数当做对象用:

    Comparator comp=(a,b)->a.val.compareTo(b.val);
    res=comp.compare(student1,student2);
    

    对已有方法、构造函数的引用:

    conv=Integer::valueOf;//static函数
    conv=std::startWith;//对象函数
    
    //构造函数P::new与工厂
    interface PFactory<P>{
    P create(String s1,String s2);
    }
    PFactory pf=P::new;
    P p1=pf.create("a","b");//调用P的构造函数中有两个String的那个
    
    //P p2=pf.create();假如工厂中的create是无参函数,那么调用这个能自动去调用P中所有构造函数中无参的那个
    

    Java8中常用的函数式接口

    Predicate

    Predicate<参数>:判断指定类型的参数是否满足某种条件,返回bool。支持实例方法的与或非操作和静态方法的相等、取非操作。

    p1=String::isEmpty
    p2=p1.negative();
    p3=p1.and(p5);
    p4=p2.or(p5);
    
    p7=Predicate.isEqual(p3,p4);
    p8=Predicate.not(p4);
    

    抽象方法为test,还有一些其他默认方法,其实现如下:

    
    @FunctionalInterface
    public interface Predicate<T> {
        boolean test(T var1);
    
        default Predicate<T> and(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> {
                return this.test(t) && other.test(t);
            };
        }
    
        default Predicate<T> negate() {
            return (t) -> {
                return !this.test(t);
            };
        }
    
        default Predicate<T> or(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> {
                return this.test(t) || other.test(t);
            };
        }
    
        static <T> Predicate<T> isEqual(Object targetRef) {
            return null == targetRef ? Objects::isNull : (object) -> {
                return targetRef.equals(object);
            };
        }
    
        static <T> Predicate<T> not(Predicate<? super T> target) {
            Objects.requireNonNull(target);
            return target.negate();
        }
    

    Function、BiFunction

    Function<参数,返回>:通过指定类型的参数对象返回另一个指定类型的对象

    Function的抽象方法为apply,把T类型转化为R类型返回。另外的composeandThen是提供把两个Function组合起来。compose是从后往前,andThen是从前往后。例子如下:

    Function<Integer, Integer> times2 = i -> i*2;
    Function<Integer, Integer> squared = i -> i*i;        
    System.out.println(times2.apply(4)); //2*4=8       
    System.out.println(squared.apply(4));//4*4=16
    
    System.out.println(times2.compose(squared).apply(4));  //4*4=16,16*2=32
    System.out.println(times2.andThen(squared).apply(4)); //4*2=8,8*8=64
    

    Function的实现如下:

    
    @FunctionalInterface
    public interface Function<T, R> {
        R apply(T var1);
    
        default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {//先执行里面的apply,再执行自己的apply
            Objects.requireNonNull(before);
            return (v) -> {
                return this.apply(before.apply(v));
            };
        }
    
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {//先执行自己的apply,再执行里面的apply
            Objects.requireNonNull(after);
            return (t) -> {
                return after.apply(this.apply(t));
            };
        }
    
        static <T> Function<T, T> identity() {
            return (t) -> {
                return t;
            };
        }
    

    BiFunction<参数,参数,返回>:通过指定类型的两个参数对象返回另一个指定类型的对象。和Function的差别在于输入参数的个数多了一个。
    它只有一个默认方法andThen。它的参数是一个Function,先执行BiFunction,然后执行这个参数Function。

    BiFunction<Integer,Integer,Integer> add=(a,b)->a+b;
    Function<Integer, Integer> times2 = i -> i*2;
    
            System.out.println(add.andThen(times2).apply(2,4)); //2+4=6,2*6=12
    
    

    实现如下:

    @FunctionalInterface
    public interface BiFunction<T, U, R> {
        R apply(T var1, U var2);
    
        default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (t, u) -> {
                return after.apply(this.apply(t, u));
            };
        }
    }
    

    Supplier、Consumer

    Supplier<返回>:生产者:生成实例,用get获取
    Consumer<参数>:消费者:消费实例,用accept消费

    使用:

    Supplier<Student> ss=Student::new;
    s1=ss.get();
    
    Consumer<Student> cs=(a1)->System.out.println(a1.name));
    s1.accept();
    
    //Consumer有一个andThen(Consumer),从前往后消费指定对象
    cs1.andThen((a2)->System.out.println(a1.age)).apply(s1);
    

    实现如下:

    @FunctionalInterface
    public interface Supplier<T> {
        T get();
    }
    
    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T var1);
    
        default Consumer<T> andThen(Consumer<? super T> after) {
            Objects.requireNonNull(after);
            return (t) -> {
                this.accept(t);
                after.accept(t);
            };
        }
    }
    

    Comparator

    Comparator<参数>:比较两个指定类型的对象,返回int

    Comparator的抽象方法是compare,还支持reversed获取逆序对应的Comparator。

    Comparator<Integer> intCmp=(a,b)->a-b;
    Comparator<Integer> intCmpRev=intCmp.reversed();
    

    Optional

    Optional<参数>:可以看做容器,装null或者指定类型的对象。

    流和函数式接口一起使用。用来对集合进行操作。

    容器类和流的转化

    把Collection容器类(List、Set,注意Map不是Collection)转为stream有两种方式,其中并发是用多线程实现:

    list.stream();
    list.parallelStream()
    

    它们的实现是在Collection类中:

    default Stream<E> stream() {
        return StreamSupport.stream(this.spliterator(), false);
    }
    
    default Stream<E> parallelStream() {
        return StreamSupport.stream(this.spliterator(), true);
        
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);//产生Spliterator的实现类IteratorSpliterator(Spliterators工具类的内部类)
    }
    
    }
    

    关于Stream、Spliterator的实现稍微有点多,需要单独开一篇博客讲吧。

    把流转化会普通集合是用collect:

    .collect(Collectors.toList());
    .collect(Collectors.toSet());
    //如果Collectors里面没有提供实现,则用三个参数的方法
    .collect(() -> new HashSet<>(),
        (set,elem)->set.add(elem),
        (setA,setB)->setA.addAll(setB)
        
    .collect(HashSet::new,
       HashSet::add,
       HashSet::addAll
    )
    

    流对基本类型的数组和Iterable类的支持:

    int[] arr={1,3,2,1};
    Arrays.stream(arr)//int数组也可以产生流
    
    //并不是支持所有Iterable类
    SerialException serialException=new SerialException();
    serialException.stream();//错误,没有stream方法
    

    流的转化

    流的特性和Spark的rdd转化过程很像。

    1. 在流的转化过程中,是不会修改原来的流,而是产生新的流。
    2. 惰性执行,map等中间操作不会触发执行,只有最终操作才会触发执行。使用了最终操作后,流就被消费掉了,就不能再接着串联流的操作。(类似Scala中的action算子)

    Stream类支持这些函数,并且很多函数返回新的Stream,使得这些函数能够串联执行。

    中间操作:
    filter(Predicate):产生的新的流只包含满足指定条件的元素
    sorted()/sorted(Comparator)
    match(Predicate)
    map/flatMap(Function):另外还有mapToInt,mapToLong,mapToDouble这三种操作及对应的flatMap操作(flatMapToInt等),把流转化成指定类型的流。flatMap是针对元素映射成集合或者流的时候,结果会所有集合的集合压平成一个流。

    最终操作:
    count()
    limit(k)
    forEach(Consumer)
    max/min(Comparator):产生最大值和最小值,返回Optional类型。
    reduce(BiFunction)/reduce(初始值,BiFunction累加器)/reduce(初始值,BiFunction,BiOperator combiner):指把集合中所有元素规约生成一个元素。max和min是一种特殊的reduce操作。带combiner的reduce操作和parallelStream结合,每个线程内部调用累加器Accumulator,得到结果后线程之间汇总用combiner得到最终结果。

    reduce的三种形式:

    1. 未定义初始值,则第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素
    2. 定义了初始值,则第一次执行的时候第一个参数的值是初始值,第二个参数是Stream的第一个元素
    3. 定义了初始值和combiner,则第三个参数只会作用于parallelStream。

    使用流的例子:

    Stream<Integer> stream = lists.stream();
    Optional<Integer> min = stream.min(Integer::compareTo);//最小值,可以指定比较器Comparator
    if (min.isPresent()) {
        System.out.println(min.get());
    }
    
    lists.stream().max(Integer::compareTo).ifPresent(System.out::println);
    
    Optional<Integer> sum = lists.stream().reduce((a, b) -> a + b);//reduce求和
    Integer sum2 = lists.stream().reduce(0, (a, b) -> a + b);//指定初始值的reduce
    Integer product = lists.parallelStream().reduce(1, (a, b) -> a *  (b * 2),(a, b) -> a * b);//
    
    lists.stream().sorted().forEach(elem -> System.out.print(elem + " "));
    
    lists.stream()
    .filter(elem -> elem > 3)
    .forEach(elem -> System.out.print(elem + " "));
    
    citys.stream().flatMap(mCities->Arrays.stream(mCities.split(" "))).forEach(System.out::println);```
    
  • 相关阅读:
    一个好的时间函数
    Codeforces 785E. Anton and Permutation
    Codeforces 785 D. Anton and School
    Codeforces 510 E. Fox And Dinner
    Codeforces 242 E. XOR on Segment
    Codeforces 629 E. Famil Door and Roads
    Codeforces 600E. Lomsat gelral(Dsu on tree学习)
    Codeforces 438D The Child and Sequence
    Codeforces 729E Subordinates
    【ATcoder】D
  • 原文地址:https://www.cnblogs.com/FannyChung/p/java8te-xing.html
Copyright © 2011-2022 走看看