JDK8新特性-Lambda表达式详解-方法引用

84 阅读6分钟

是什么?

Lambda表达式是JDK8开始新增的一种语法形式:

作用:用于简化匿名内部类的代码写法(注意:与Object公共类相同的不计入抽象方法))但是可以有多个非抽象方法

(被重写方法的形参列表)->{
  //被重写方法的方法体代码
}

注意:Lambda表达式只能简化函数式接口的匿名内部类

什么是函数式接口?

  • 有且仅有一个抽象方法的接口
  • 注意:大部分的函数式接口,上面都会有一个@FunctionalInterface的注解,有这个注解的接口必定是函数式接口

一、省略规则

  • 参数类型可以省略不写
  • 如果只有一个参数,参数类型可以省略,同时括号()也可以省略
  • 如果Lambda表达式中的方法体代码中只有一行代码,可以省略大括号不写,同时省略分号,如果这行代码是return语句,也必须去掉return不写

二、基本用法

public class lambdaDemo {
    public static void main(String[] args) {
        //普通写法
     Swimming swi=new Swimming() {
        @Override
        public void swim() {
            //创建实现的对象匿名内部类
             System.out.println("I have you swimming");
         }
     };
        swi.swim();  //I have you swimming
​
        //lambda表达式写法
        Swimming swi1= ()->System.out.println("I have you swimming too");
        swi1.swim();  //I have you swimming too
    }
}
//是一个接口,有且仅有一个抽象方法
interface Swimming{
    void swim();
}

三、用lambda表达式简化setAll方法

//用lambda表达式简化setAll方法
int[] arr={123,343,12325,6,34,6};
//原始写法
Arrays.setAll(arr, new IntUnaryOperator() {
    @Override
    public int applyAsInt(int operand) {
        return operand+1;
    }
});
//用表达式
Arrays.setAll(arr,  operand->operand+1);
System.out.println(Arrays.toString(arr));

四、用lambda表达式简化comparetor接口的匿名形式

public class lambdaDemo {
    public static void main(String[] args) {
      //用lambda表达式简化comparetor接口的的匿名形式
        Studentsss stu1=new Studentsss("zhangsan",16);
        Studentsss stu2=new Studentsss("wangwu",89);
        Studentsss stu3=new Studentsss("lishi",23);
        Studentsss stu4=new Studentsss("hehie",54);
        Studentsss [] stus={stu1,stu2,stu3,stu4};
        //普通写法
        Arrays.sort(stus, new Comparator<Studentsss>() {
            @Override
            public int compare(Studentsss o1, Studentsss o2) {
                return o1.getAge()-o2.getAge();
            }
        });
        //用表达式
        Arrays.sort(stus, (Studentsss o1, Studentsss o2) ->{
        return o1.getAge()-o2.getAge();});
​
        //用表达式
        Arrays.sort(stus, (o1,o2) ->o1.getAge()-o2.getAge());
​
    }
}

五、四种方法方法引用

主要就是进一步简化Lambda表达式的

方法引用的标志性符号" :: "

主要分为四种引用的地方:

静态方法的引用

类名:: 静态方法(是重写方法中调用的静态方法,不是实现接口所以重写的抽象方法)

使用场景:如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用

静态方法/类方法(static修饰的方法)引用

注意事项:

  • 被引用的方法参数列表和函数式接口中抽象方法的参数一致
  • 接口的抽象方法没有返回值,引用的方法可以有返回值也可以
  • 没有接口的抽象方法有返回值,引用的方法必须有相同类型的返回值!!
  • 由于满足抽象参数列表与引用参数列表相同,所以可以写成静态方法引用的格式

案例:(将字符串转换成Integer类型)

package 常用API2;
​
public class LambdaDemo2 {
    public static void main(String[] args) {
        //方法引用:静态方法
        //正常写法
        myInterface myinter = new myInterface() {
            //重写接口的抽象方法
            @Override
            public Integer strInt(String str) {
                // 参数为String类型,返回值类型为int类型(会自动进行装箱)
                return Integer.parseInt(str); //底层为静态方法
            }
        };
        System.out.println(myinter.strInt("90")); //90
​
        //基本的表达式写法
        myInterface myinter1 = (String str) -> Integer.parseInt(str);
        // 参数为String类型,返回值类型为int类型(会自动进行装箱)
        myInterface myinter1 = str-> Integer.parseInt(str);
​
        //底层为静态方法;
        System.out.println(myinter1.strInt("88")); //88
​
        //静态方法写法
        myInterface myinter2 = Integer::parseInt;
        // 参数为String类型,返回值类型为int类型(会自动进行装箱)
        //底层为静态方法;
        System.out.println(myinter2.strInt("787")); //787
    }
}
//函数式接口
//用他创建匿名内部类的,然后只是调用一个静态方法
interface myInterface{
    Integer strInt(String str);
}

实例方法的引用

实例方法(非static修饰的方法)引用 语法:对象名:∶非静态方法名

注意事项: 被引用的方法参数列表和函数式接口中抽象方法的参数一致!!

接口的抽象方法没有返回值,引用的方法可以有返回值也可以没有

接口的抽象方法有返回值,引用的方法必须有相同类型的返回值! !

案例:给你一个字符串【数字】 判断是否是以.png结尾的

package 常用API2;
​
public class LambdaDemo3 {
    public static void main(String[] args) {
        String s="文本框.png";
        //方法引用,实例方法
        //基本用法
        myInterface1 myinter=new myInterface1() {
            @Override
            public Boolean strEnd(String str) {
                return s.endsWith(str); //底层是一个实例方法
            }
        };
        //使用实例方法引用: 类名:: 方法名字
        //原始写法
        myInterface1 mys1=str ->s.endsWith(str);
        System.out.println(mys1.strEnd(".png")); //true
​
        // 实例方法引用写法  对象名::实例方法
        myInterface1 myInterface2=s::endsWith;
        System.out.println(mys1.strEnd(".png")); //true
​
    }
}
//函数式接口
//用他创建匿名内部类的,然后只是调用一个实例方法
//判断字符串是否为 .png结尾
interface myInterface1{
    Boolean strEnd(String str);
}

特定类型方法的引用

特殊方法引用

语法:类型 :: 实例方法名

注意事项: 在抽象方法中,参数作为实例方法调用者,就可以简化,就是说如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,这此时就可以使用特定类型的方法引用

public class LambdaDemo4 {
    public static void main(String[] args) {
        String[] strs={"java","Fe","Python","hhhege"};
        //排序
        Arrays.sort(strs, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                //指定比较规则,比较忽视大小写
                //第一个参数作为该实例方法的主调,后面的作为方法的入参
                return o1.compareToIgnoreCase(o2);
            }
        });
        String[] strs1={"java","Fe","Python","hhhege"};
​
        //用特定方法的引用  类型 :: 实例方法名字
        Arrays.sort(strs1,String::compareToIgnoreCase);
        System.out.println(Arrays.toString(strs1));
    }
}

构造器引用

构造方法引用 语法:类名::new

注意事项: 被引用的类必须存在一个构造方法与函数式接口的抽象方法参数列表一致

案例:利用构造方法将String字符串转换成Integer类型

public class MyInterfaceTest {
    public static void main(String[] args) {
        // 采用匿名内部类的方式
        MyInterface my = new MyInterface() {
 
            @Override
            public Integer strToInt(String str) {
                // Integer integer = new Integer(str);
                // //创建一个构造方法将String类型转换成Integer类型(自动装箱)
                return new Integer(str); // 方法是一个构造方法
            }
        };
 
        // 采用lambda表达式对匿名内部类进行优化
        MyInterface my1 =  str ->  new Integer(str); 
        
        // 采用构造方法引用进行简化代码
        MyInterface my2 =  Integer::new; 
 
        // 调用方法输出结果
        System.out.println(my.strToInt("232434"));
        System.out.println(my1.strToInt("232434"));
        System.out.println(my2.strToInt("232434"));
    }
}
public interface MyInterface {
    //抽象方法  
    // 只是在抽象方法中创建一个新的对象
    Integer strToInt(String str);
}

六、总结

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读

优点:

  1. 代码简洁,开发迅速
  2. 方便函数式编程
  3. 非常容易进行并行计算
  4. Java 引入 Lambda,改善了集合操作

缺点:

  1. 代码可读性变差
  2. 在非并行计算中,很多计算未必有传统的 for 性能要高
  3. 不容易进行调试