Java8新特性总结

作者: 第四单元 | 来源:发表于2019-01-18 12:03 被阅读8次

    一.接口内允许添加默认实现的方法

    在原来的定义中接口中只能有方法声明,不能有方法体。在Java8中,接口也可以有自己带有实现的方法啦。具体来说是要用default来修饰的方法,其可以像类中的方法一样有执行语句。在实现接口时,可以不实现其default方法,并且实现类对象可以调用其接口的default方法。当然也可以在实现类中覆盖default方法。

    public class InterfaceDemo {
        public static void main(String[] args) {
            Formula formula = new Formula() {
                @Override
                public double calculate(int a) {
                    return a + 1;
                }
    
    //           @Override
    //            public double sqrt(int a) {
    //              return a;
    //            }
            };
    
            System.out.println(formula.calculate(100));
            System.out.println(formula.sqrt(100));
        }
    }
    
    interface Formula {
        //计算
        double calculate(int a);
    
        //求平方根
        default double sqrt(int a) {
            return Math.sqrt(a);
        }
    }
    

    二.Lambda表达式

    Lambda简化了匿名内部类的写法。Java8中可以通过类型推断来判断出用户的意图,不必将类型等信息写全。特别是方法实现体中只有一句语句的实现类,更能加大简化力度。

    Lambda解决了将一个方法作为参数传值的问题。解决了一个函数是否可以独立存在的问题。是Java向函数式编程的一种靠拢。

    一般在某个方法只使用一次的地方使用Lambda表达式;如果方法没有入参,则只写一个()->{语句};当只有一个参数,且类型可推断时,()可省略;如果方法体中只有一条语句花括号可以省略;

    
    public class LambdaDemo {
        public static void func1() {
            System.out.println("not use Lambda");
            List<String> strs = Arrays.asList("hello","word","apple","people","sea","book","school","computer");
    
            //old way 
            Collections.sort(strs,new Comparator<String>() {
                @Override
                public int compare(String a,String b) {
                    return b.compareTo(a);
                }
            });
    
            System.out.println(strs);
        }
    
        public static void func2() {
            System.out.println("use Lambda");
            List<String> strs = Arrays.asList("hello","word","apple","people","sea","book","school","computer");
    
            //way 1
            Collections.sort(strs,(String a,String b) -> {
                return a.compareTo(b);
            });
    
            //way 2 : only one statement 
            Collections.sort(strs,(String a,String b) -> a.compareTo(b));
    
            //way 3 : omit class
            Collections.sort(strs,(a,b) -> a.compareTo(b));
    
            System.out.println(strs);
        }
    }
    

    三.函数式接口Functional Interface

    学习了上述Lambda的内容肯定会有一些疑问:如果接口有多个需要实现的方法 呢,还能使用Lambda?如果可以的话Lambda是如何做推断的。

    答案是,使用Lambda时要求接口中只能有一个抽象方法(通过default修饰的带有方法体的接口中的方法不是抽象方法)。

    如果一个接口被注解@FunctionalInterface修饰,则该接口只能有一个抽象方法,否则会报错。

    四.引用类的构造器及方法

    在Lambda中若是直接调用了一个方法,且调用方法的形参和要实现的接口抽象方法形参一致,则可以进一步简写。举例如下:
    接口定义:

    @FunctionalInterface
    interface Converter<F,T> {
        T convert(F form);
    }
    

    Lambda表达式

    //旧的写法
    Converter<String,Integer> convert1 = (from) -> Integer.valueOf(from);
    //新的写法
    Converter<String,Integer> convert2 = Integer::valueOf;
    
    System.out.println(convert1.convert("1234"));
    

    引用其他类型的方法

    • 例子中的方法是Integer类的静态方法,如果是某个类的实例方法,则应该使用一个对象加::来引用。如,obj::func;
    • 如果要调用的一个构造方法(抽象方法返回的是一个对象),则应该这样使用:Integer::new。用new代替构造方法名字。

    五.Lambda访问外部变量及接口默认方法

    访问局部变量

    • 可以访问局部的final变量,但不能修改。
    • 与匿名内部类不同的是,外部变量不需要显示地声明为final,但却要有final的特点,不能被修改,在Lambda之后被修改也不行。

    访问成员变量和静态变量
    可以任意读写,举例如下:

    public class FunctionInterface {
        String str = "init";
        static Integer num = 0;
    
        public void testScope() {
            Converter<String,Integer> convert = (from) -> {
                //在这里可访问成员变量和静态变量
                str = from;
                num = Integer.valueOf(from);
                return num;
            };
    
            System.out.println(convert.convert("3453"));
            System.out.println(convert.convert("5678"));
        }        
    }
    

    访问接口的默认方法
    在匿名类中可以访问接口定义的默认方法,在Lambda中不可以访问。

    六.内置函数式接口

    Java8中内置了许多函数式接口,包括Comparator和Runnable等,它们被添加了@FunctionalInterface注解,以用来支持Lambda表达式。

    6.1Predicate断言

    查看源码,这个函数式接口中要实现的方法为:boolean test(T t); 即一个判断传入值真假的方法,当然判断的规则由你自己定义。
    如定义一个判断字符串长度是否大于10的Predicate:

    import java.util.function.Predicate;
    
    public class PredicateDemo {
        public static void main(String[] args) {
            Predicate<String> predicate = s -> s.length() > 10;
    
            System.out.println(predicate.test("hello"));
            System.out.println(predicate.test("hello,world!"));
        }
    }
    

    6.2 Function

    查其源码,需要实现一个R apply(T t)的方法。这个接口提供链式调用、组合的功能。

    6.3 Supplier

    Supplier<Person> personSupplier = Person::new;
    personSupplier.get();

    6.4 Consumer

    ??
    Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
    greeter.accept(new Person("Luke", "Skywalker"));

    6.5 Optional

    参考资料

    七.Stream流

    什么是Stream流?
    参考资料
    Stream流提供了一种对集合Collection的方便的操作。分为“中间操作”和“终端操作”两种。中间操作的结果还是返回一个Stream,可以继续操作;而终端操作会返回一个结构不能继续流操作了。

    要使用Sream首先要通过Collection的Stream方法获取一个Stream对象。

    7.1 Filter过滤 中间操作

    筛选出集合中满足一定条件的元素。Stream有一个filter方法,入参是一个Predicate,筛选结果是Predicate.test为true的集合的Stream。下面来看一个筛选出String集合中以"s"开头的String的程序:

    List<String> list = Arrays.asList("hello","world","apple","people","sea",
                                      "watch","table","book","school","help");
    list
        .stream() //获取stream
        .filter(s -> s.startsWith("s"))  //设置filter。中间操作
        .forEach(System.out::println);   //打印出流中的元素。终端操作
    

    7.2 Sorted排序 中间操作

    可以给sorted()方法传入一个Comparator用来自定义排序,否则将使用默认排序规则。

    list
        .stream()
        .sorted((a,b) -> b.compareTo(a))
        .forEach(System.out::println);
    

    7.3 Map

    map方法入参为一个Function函数式接口。调用map方法将对集合中的每一个元素执行一下Function中的apply方法,并返回由其返回值组成的集合的流。

    举例:将表示数字的字符串集合全部转换为数字再加一后输出。

    List<String> list = Arrays.asList("10","100","1000");
    
    System.out.println("---- test map ----");
    list
        .stream()
        .map(Integer::valueOf)  //转换为整数
        .map(a -> a + 1)        //执行加一操作
        .forEach(System.out::println);
    

    7.4Match匹配

    是种终端操作,结果不是stream对象,而是boolean值
    根据Predicate指定的规则判断集合中是否有匹配的,有的话返回true。
    有三种形式,anyMatch:有一个匹配就返回true。allMatch:全部匹配返回true。noneMatch:全部不匹配返回true。

    boolean anyMatch(Predicate<? super T> predicate);
    boolean allMatch(Predicate<? super T> predicate);
    boolean noneMatch(Predicate<? super T> predicate);
    

    7.5 Count计数

    终端操作,统计stream中元素的个数。

    long count = 
        list
            .stream() //获取stream
            .filter(s -> s.startsWith("s"))  //设置filter。中间操作
            .count();
    

    7.6 Reduce

    list[0]和list[1]执行操作,得到的结果为result。result再和list[2]执行操作,得到的结果result。依次进行,对所有元素执行一遍。

    根据上述描述也可以看出,这里的“操作”必须满足两个入参、返回值是同一类型的。

    reduce方法的入参是:BinaryOperator<T> 这里的T就是集合的元素类型。

    举例:求Integer集合中所有元素的和。

    List<Integer> list = Arrays.asList(1,2,3,4,5);
    
    System.out.println("---- test reduce ----");
    Optional<Integer> sum = 
        list
            .stream()
            .reduce((a,b) -> a + b);
    
    sum.ifPresent(System.out::println);
    

    注意:reduce的返回值为Optional<T>

    相关文章

      网友评论

        本文标题:Java8新特性总结

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