天天看點

java8新特性(一)(Lambda表達式、函數式接口、方法引用、構造器引用和數組引用)

Lambda表達式

Lambda表達式的使用

  1. 舉例:(o1,o2) -> Integer.compare(o1,o2);
  2. 格式:

    -> :Lambda操作符 或 箭頭操作符

    -> 左邊:Lambda形參清單(其實就是接口中的抽象方法的形參清單)

    -> 右邊:Lambda體(其實就是重寫的抽象方法的方法體)

  3. Lambda表達式的使用:(分為6種情況)

    -> 左邊:Lambda形參清單的參數類型可以省略(類型推斷);如果Lambda形參清單隻有一個參數,其一對()也可以省略

    -> 右邊:Lambda體應該使用一對{}包裹;如果Lambda體隻有一條執行語句(可能是return語句),可以省略這一對{}和return關鍵字

  4. Lambda表達式的本質:作為函數式接口的執行個體(定義在下面)
  5. 是以以前用匿名實作類表示的現在都可以用Lambda表達式來寫

使用的6種情況:

情況一:

文法格式:無參,無傳回值

//文法格式一:無參,無傳回值
    public void test1(){
        Runnable r1=new Runnable() {
            @Override
            public void run() {
                System.out.println("我愛北京天安門");
            }
        };
        r1.run();
        System.out.println("*******************");
        
        Runnable r2=()-> System.out.println("我愛北京天安門");
        r2.run();
    }
           

情況二:

文法格式:需要一個參數,但無傳回值

//文法格式二:需要一個參數,但無傳回值
    public void test2(){
        Consumer<String> con=new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("我愛北京天安門");
        System.out.println("*******************");

        Consumer<String> con2=(String s)-> {System.out.println(s);};
        con2.accept("我愛北京天安門");
    }
           

情況三:

文法格式:資料類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷”

//文法格式三:資料類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷”
    public void test3(){
        Consumer<String> con=(String s)-> {System.out.println(s);};
        con.accept("我愛北京天安門");
        System.out.println("*******************");

        Consumer<String> con2=(s)-> {System.out.println(s);};
        con2.accept("我愛北京天安門");
    }
           

情況四:

文法格式:Lambda若隻需要一個參數時,參數的小括号可以省略

//文法格式四:Lambda若隻需要一個參數時,參數的小括号可以省略
    public void test4(){
        Consumer<String> con=(s)-> {System.out.println(s);};
        con.accept("我愛北京天安門");
        System.out.println("*******************");

        Consumer<String> con2=s-> {System.out.println(s);};
        con2.accept("我愛北京天安門");
    }
           

情況五:

文法格式:Lambda需要兩個或以上參數,多條執行語句,并且可以有傳回值

//文法格式五:Lambda需要兩個或以上參數,多條執行語句,并且可以有傳回值
    public void test5(){
        Comparator<Integer> com1=new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare(12,21));
        System.out.println("*******************");
        
        Comparator<Integer> com2=(o1,o2)->{
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        System.out.println(com2.compare(12,21));
    }
           

情況六:

文法格式:當Lambda體隻有一條語句時,return與大括号若有,都可以省略

//文法格式六:當Lambda體隻有一條語句時,return與大括号若有,都可以省略
    public void test7(){
        Comparator<Integer> com1=(o1,o2)->{
            return o1.compareTo(o2);
        };
        System.out.println(com1.compare(12,21));
        System.out.println("*******************");

        Comparator<Integer> com2=(o1,o2)->o1.compareTo(o2);
        System.out.println(com1.compare(12,21));
    }
    public void test8(){
        Consumer<String> con1=s->{
            System.out.println(s);
        };
        con1.accept("我愛北京天安門");
        System.out.println("*******************");

        Consumer<String> con2=s -> System.out.println(s);
        con2.accept("我愛北京天安門");
    }
           

函數式接口

如果一個接口中,隻聲明了一個抽象方法,此接口就稱為函數式接口。我們可以在一個接口上使用@FunctionalInterface注解,這樣做可以檢查它是否是一個函數式接口。

java内置四大核心函數式接口

函數式接口 參數類型 傳回類型 用途
Consumer< T> 消費型接口 T void 對類型T的對象應用操作,包含方法:void accept(T t)
Supplier< T> 供給型接口 T 傳回類型為T的對象,包含方法:T get()
Function< T,R> 函數型接口 T R 對類型為T的對象應用操作,并傳回結果。結果類型是R類型的對象。包含方法:R apply(T t)
Predicate< T> 斷定型接口 T boolean 确定類型為T的對象是否滿足限制,并傳回boolean值。包含方法:boolean test(T t)
  • Consumer< T> 消費型接口 :void accept(T t)
  • Supplier< T> 供給型接口:T get()
  • Function< T,R> 函數型接口:R apply(T t)
  • Predicate< T> 斷定型接口:boolean test(T t)

Demo1:

public void test1(){
        happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("花了"+aDouble);
            }
        });
        System.out.println("*******************");

        happyTime(500,money-> System.out.println("花了"+money));
    }
    public void happyTime(double money, Consumer<Double> consumer){
        consumer.accept(money);
    }
           

Demo2:

完成名字中帶京的判斷

public void test2(){
        List<String> list= Arrays.asList("北京","南京","天津","普京");

        List<String> filterStr1=filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("京");
            }
        });
        System.out.println(filterStr1);
        System.out.println("*******************");

        List<String> filterStr2=filterString(list,s -> s.contains("京"));
        System.out.println(filterStr2);
    }
    //根據給定的規則,過濾集合中的字元串。此規則由Predicate的方法決定
    public List<String> filterString(List<String> list, Predicate<String> pre){
        ArrayList<String> filterList = new ArrayList<>();
        for (String s:list){
            if (pre.test(s)){
                filterList.add(s);
            }
        }
        return filterList;
    }
           

方法引用

方法引用的了解:

方法引用可以看做是 Lambda表達式深層次的表達。換句話說,方法引用就是 Lambda表達式,也就是函數式接口的一個執行個體,通過方法的名字來指向一個方法。

方法引用的使用:

  1. 使用情境:當要傳遞給 Lambda體的操作,已經有實作的方法了,可以使用方法引用!
  2. 方法引用,本質上就是 Lambda表達式,而Lambda表達式作為函數式接口的執行個體。是以方法引用,也是函數式接口的執行個體。
  3. 使用格式: 類(或對象)::方法名
  4. 具體分為如下三種情況:(前兩個一個思路,第三個一個思路)

    對象::非靜态方法

    類::靜态方法

    類::非靜态方法

  5. 方法引用使用的要求:

    要求接口中的抽象方法的形參清單和傳回值類型與方法引用的方法的形參清單和傳回值類型相同!(針對于情況1和情況2)

    當函數式接口方法的第一個參數是需要引用方法的調用者,并且第二個參數是需要引用方法的參數(或無參數時):ClassName::methodName(針對于情況3)

情況一:對象::執行個體方法

//情況一:對象::執行個體方法
    //Consumer中void accept(T t)
    //PrintStream中的void println(T t)
    public void test1(){
        Consumer<String> con1=str-> System.out.println(str);
        con1.accept("北京");
        System.out.println("*****************");

        PrintStream ps=System.out;
        Consumer<String> con2=ps::println;
        con2.accept("北京");
    }
    //Supplier中T get()
    //Person中的String getName()
    public void test2(){
        Person per=new Person(1001,"Tom",23,5600);

        Supplier<String> sup1=()->per.getName();
        System.out.println(sup1.get());
        System.out.println("*****************");

        Supplier<String> sup2=per::getName;
        System.out.println(sup2.get());
    }
           

情況二:類::靜态方法

//情況二:類::靜态方法
    //Comparator中的int compare(T t1,T t2)
    //Integer中的int compare(T t1,T t2)
    public void test3(){
        Comparator<Integer> com1=(t1,t2)->t1.compareTo(t2);
        System.out.println(com1.compare(11, 12));
        System.out.println("*****************");

        Comparator<Integer> com2=Integer::compareTo;
        System.out.println(com2.compare(11, 12));
    }
    //Function中的R apply(T t)
    //Math中的Long round(Double d)
    public void test4(){
        Function<Double,Long> func1=new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        System.out.println("*****************");

        Function<Double,Long> func2=aDouble -> Math.round(aDouble);
        System.out.println(func2.apply(12.3));
        System.out.println("*****************");

        Function<Double,Long> func3=Math::round;
        System.out.println(func3.apply(12.3));
    }
           

情況三:類::執行個體方法(有難度)

//情況三:類::執行個體方法(有難度)
    //Comparator中的int compare(T t1,T t2)
    //String中的int t1.compareTo(t2)
    public void test5(){
        Comparator<String> com1=(s1,s2)->s1.compareTo(s2);
        System.out.println(com1.compare("abc","abd"));
        System.out.println("*****************");

        Comparator<String> com2= String::compareTo;
    }
    //BiPredicate中的boolean test(T t1,T t2)
    //String中的boolean t1.equals(t2)
    public void test6(){
        BiPredicate<String,String> pre1=(s1,s2)->s1.equals(s2);
        System.out.println(pre1.test("abc","abd"));
        System.out.println("*****************");

        BiPredicate<String,String> pre2=String::equals;
        System.out.println(pre2.test("abc","abd"));
    }
    //Function中的R apply(T t)
    //Person中的String getName()
    public void test7(){
        Person p=new Person(1001,"yyyzl",20,11111);

        Function<Person,String> fun1=e->e.getName();
        System.out.println(fun1.apply(p));
        System.out.println("*****************");

        Function<Person,String> fun2=Person::getName;
        System.out.println(fun2.apply(p));
    }
           

構造器引用和數組引用

一、 構造器引用

和方法引用類似,函數式接口中的抽象方法的形參清單和構造器的形參清單一緻。

抽象方法的傳回值類型即為構造器所屬的類的類型

二、數組引用

可以把數組看做是一個特殊的類,則寫法與構造器引用一緻。

構造器引用Demo:

//構造器引用
    //Supplier中的T get()
    //Person的空參構造器:Person()
    public void test1(){
        Supplier<Person> sup1=new Supplier<Person>() {
            @Override
            public Person get() {
                return new Person();
            }
        };
        System.out.println("********************");

        Supplier<Person> sup2=()->new Person();
        System.out.println(sup2.get());
        System.out.println("********************");

        Supplier<Person> sup3=Person::new;
        System.out.println(sup3.get());
    }
    //Function中的R apply(T t)
    //Person的一個參數的構造器:Person(int id)
    public void test2(){
        Function<Integer,Person> func1=id->new Person(id);
        Person p1=func1.apply(11);
        System.out.println(p1);
        System.out.println("********************");

        Function<Integer,Person> func2=Person::new;
        Person p2=func1.apply(11);
        System.out.println(p2);
    }
    //BiFunction中的R apply(T t,U u)
    //Person的兩個參數的構造器:Person(int id,String name)
    public void test3(){
        BiFunction<Integer,String,Person> func1=(id,name)->new Person(id,name);
        System.out.println(func1.apply(101, "yyyzl"));
        System.out.println("********************");

        BiFunction<Integer,String,Person> func2=Person::new;
        System.out.println(func1.apply(101, "yyyzl"));
    }
           

數組引用Demo:

//數組引用
    //Function中的R apply(T t)
    public void test4(){
        Function<Integer,String[]> func1=length->new String[length];
        String[] arr1=func1.apply(5);
        System.out.println(Arrays.toString(arr1));
        System.out.println("********************");

        Function<Integer,String[]> func2=String[]::new;
        String[] arr2=func2.apply(5);
        System.out.println(Arrays.toString(arr2));
    }