您的位置:首页 > 移动开发 > Android开发

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

2017-03-13 18:10 691 查看

前言

上一文: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 = 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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐