首页 > 代码库 > Android 使用Java8新特性之"方法引用"

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

前言


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

方法引用的4种形式


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

分类:
1. 静态方法引用
2. 实例方法引用
3. 类实例方法引用
4. 构造方法引用

静态方法引用

类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 = http://www.mamicode.com/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 = http://www.mamicode.com/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);
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

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