天天看点

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));
    }