• 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);```
    
  • 相关阅读:
    docker将jar打包镜像文件
    特性阻抗(转)
    关于三极管偏置电路的思考
    怎样理解阻抗匹配?(转)
    你要包火到几时呢
    Bluetooth Note
    今年过年没回家
    第二天(tomcat与web程序结构与Http协议与HttpUrlConnection)
    JavaIO操作(1)转换流
    canphp框架功能与特性介绍
  • 原文地址:https://www.cnblogs.com/FannyChung/p/java8te-xing.html
Copyright © 2020-2023  润新知