Android 使用Java8新特性之"方法引用"

    xiaoxiao2021-03-25  60

    文章目录

    前言方法引用的4种形式静态方法引用实例方法引用类实例方法引用需要在外部调用方法中,声明参数不需要在外部调用方法中,声明参数 构造方法引用 总结


    前言

    上一文:Android 使用Java8新特性之Lambda expression (附命令者模式简化) 说过lambda表达式,在android studio中的环境配置及应用。本文讲下Java8新特性之"方法引用"。 “方法引用”,它其实可以看成lambda表达式的一种简写形式。 再回顾一下lambda表达式的应用场景:简化仅含单一抽象方法接口的调用


    方法引用的4种形式

    方法引用的符号形式,形如, [className | class-instance]::[static-method | instance-method | construct-method] 即,以类名或类的实例对象为前缀,中间以两个冒号(::)连接,后跟静态方法 或 实例方法 或 构造方法

    分类:

    静态方法引用实例方法引用类实例方法引用构造方法引用

    静态方法引用

    类MethodReferenceActivity下有一静态方法:

    static int parz(String str) {//被lambda表达式或"方法引用"调用 return Integer.parseInt(str); }

    如果直接调用 MethodReferenceActivity::parz当然是不行的,因为"方法引用"是用来替换lambda表达式的,所以也将指代一个仅含单一抽象方法的接口。

    再有一个接口:

    public interface ToIntFunc<T> {//注:原生jdk中就有的方法,安卓中没有 int applyAsInt(T value); }

    再有一个使用ToIntFunc接口的静态方法:

    public static int parse(ToIntFunc<String> f, String num) { return f.applyAsInt(num); }

    调用parse()时使用lambda表达式:

    int parseValue = parse((value -> parz(value)), num);

    调用parse()时使用"方法引用":

    int parseValue = parse(MethodReferenceActivity::parz, num);

    实例方法引用

    将上面的方法parse方法声明中的static 去掉:

    public int parse(ToIntFunc<String> f, String num) { return f.applyAsInt(num); }

    调用parse()时使用"方法引用":

    int parseValue = parse(this::parz, num); //this指当前类的实例对象

    类实例方法引用

    需要在外部调用方法中,声明参数

    如有一个内部类Person:

    static class Person { public Person() { } public Person(String name) { this.name = name; } String name; Long birthday; public Long getBirthday() { return birthday; } public String getName() { return name; } public boolean compareByName(Person b) { int result = this.name.compareToIgnoreCase(b.name); if (result == 1) { return true; } else { return false; } } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", birthday=" + birthday + '}'; } public void printInfo() { System.out.println(toString()); } }

    有一个接口Compare:

    public interface Compare<T> { boolean compareTo(T v1, T v2); }

    外部的使用接口Compare的调用方法isLarge:

    public boolean isLarge(Compare<Person> c, Person p1, Person p2) { return c.compareTo(p1, p2); }

    使用lambda表达式和类实例方法引用:

    Person p1 = new Person("stone"); Person p2 = new Person("sun"); boolean result = isLarge((v1, v2) -> v1.compareByName(v2), p1, p2); System.out.println("p1 排序在 p2 后: " + result); result = isLarge(Person::compareByName, p1, p2); System.out.println("p1 排序在 p2 后: " + result);

    这里isLarge方法,除接口外,还要求传递两个Person的实例对象。这两个对象,被Compare接口中的compareTo方法使用。

    不需要在外部调用方法中,声明参数

    再来看如下一组代码:

    Integer[] ary = {2, 8, 1, 5, 6, 3, 4}; Arrays.sort(ary, (o1, o2) -> o1.compareTo(o2)); Arrays.sort(ary, Integer::compareTo);

    这是调用数组工具类Arrays.sort()来进行排序。 在【Arrays.sort(ary, Integer::compareTo);】中,"类实例方法引用"实际指代java.util.Comparator接口,接口中的静态方法为:int compare(T o1, T o2);而这里并没有传递o1、o2参数。o1,o2的实例化,实际上是在sort方法内部完成的。 就好比如下示例,

    /**内部实例化*/ public boolean isLarge(Compare<Person> c) { Person p1 = new Person("stone"); Person p2 = new Person("austin"); return c.compareTo(p1, p2); }

    使用lambda和类实例方法引用:

    isLarge((v1, v2) -> v1.compareByName(v2));//lambda expression isLarge(Person::compareByName);//method reference

    构造方法引用

    现有下面的代码:

    static class Person { String name; public Person() { } public Person(String name) { this.name = name; } } public interface GetType<T> { T get(String value); } public interface GetType2<T> { T get(); } public Person getPerson(String name, GetType<Person> data) { return data.get(name); } public Person getPerson(GetType2<Person> data) { return data.get(); }

    使用lambda和构造方法引用:

    getPerson("li si", value -> new Person(value));//lambda //会调用new Person(String name) 指代GetType getPerson("zhang san", Person::new); getPerson(() -> new Person());//lambda getPerson(Person::new);//会调用new Person() 指代GetType2

    总结

    不管是lambda表达式,还是"方法引用",它们都指代一个**仅含单一抽象方法接口的匿名内部类实例。**使用"方法引用"后,一看表达式,就能猜出方法引用的类别。同时配合AS,看调用方法的接口。 "方法引用"表达式的返回值与接口中方法的返回值一致。"方法引用"表达式所调用方法的参数,可以通过外部调用方法来传值。如果有参数,而没传值,可能在外部方法内部进行了初始化,如"类实例方法引用"第二个示例。

    lambda表达式,是可以有一个方法体的。现在有了"方法引用",就不用看起来那么"混乱"了。比如:

    button.setOnTouchListener((view, event)-> { if (event.getAction() == MotionEvent.ACTION_DOWN) { //do sth. return true; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { //do sth. return true; } return super.onTouchEvent(event); });

    只需要声明一个方法:

    private boolean handleEvent(View v, MotionEvent event) { //do sth. return true; }

    如下使用"方法引用"调用:

    button.setOnTouchListener(this::handleEvent);
    转载请注明原文地址: https://ju.6miu.com/read-40151.html

    最新回复(0)