匿名类(Anonymous Class)
- 当接口、抽象类的实现类,在整个项目中只使用过一次,可以考虑使用匿名类
// Person per = new Person();
// per.run();// Person Run
// 如果一个类只在一个地方使用、 可以使用匿名类
Runable person = new Runable() {
@Override
public void run() {
System.out.println("Person run");
}
};
person.run();
// 如果需要初始化之后立即执行某个函数 可以
new Runable() {
@Override
public void run() {
System.out.println("Person run");
}
}.run();
匿名类的使用注意
匿名类跟局部类很相似
- 匿名类不能定义除了编译时常量之外的
static
成员 - 匿名类只能访问
final
或者有效final的局部变量 - 匿名类可以直接访问外部类的所有成员(包括private成员)
- 匿名类只有在实例相关的代码块中才能直接访问外部类的实例成员(实例变量、实例方法)
- 匿名类不能自定义构造方法,但可以有初始化块
匿名类的常见用途
代码传递
public interface MyBlock {
void execute();
}
public class Times {
// 计算代码耗时
public static void test(MyBlock block){
long begin = System.currentTimeMillis();
block.execute();
long end = System.currentTimeMillis();
double duration = (end - begin) / 1000.0;
System.out.println("耗时:" + duration + "s");
}
}
Times.test(new MyBlock(){
@Override
public void execute() {
int age = 10;
for (int i = 0; i < age; i++) {
System.out.println(i);
}
}
});
回调
类似于OC中的回调
public interface NetBlock {
void success(Object response);
void failure();
}
public class Network {
public static void get(String url, NetBlock callBack){
// 模仿一个url请求
boolean res = true;
if (res) {
Object resp = null;
callBack.success(resp);
} else {
callBack.failure();
}
}
}
Network.get("https://xxxxx", new NetBlock(){
@Override
public void success(Object response) {
System.out.println("请求成功");
}
@Override
public void failure() {
System.out.println("请求失败");
}
});
过滤器
匿名函数可以实现类似于filter
的功能
Lambda
Lambda表达式是Java 8 开始有的语法
函数式接口(Functional Interface):只包含一个抽象方法的接口
@FunctionalInterface // 表示这是一个函数式接口
public interface Testable {
void test();
}
- 当匿名类实现的是函数式接口时,可以使用lambda来简化
(参数列表) -> {
reture xxx;
}
// 普通写法
Times.test(new MyBlock(){
@Override
public void execute() {
int age = 10;
for (int i = 0; i < age; i++) {
System.out.println(i);
}
}
});
// lambda表达式
Times.test(() -> {
int age = 10;
for (int i = 0; i < age; i++) {
System.out.println(i);
}
});
Supplier的使用
有时使用Supplier
传参,可以避免代码的浪费执行(有必要时再执行代码)
public static void main(String[] args) {
getFirstNotEmptyString("jack", makeString());
}
static String makeString() {
return String.format("%d %d %d", 1, 2, 3);
}
static String getFirstNotEmptyString(String s1, String s2) {
if (s1 != null || s1.length() != 0) return s1;
if (s2 != null || s2.length() != 0) return s2;
return null;
}
上面的示例中,我们确定了第一个参数不为空,也就没必要执行第二个参数的代码,但是现在makeString
方法仍然会被调用。
可以考虑使用Supplier
这个函数式接口
public static void main(String[] args) {
getFirstNotEmptyString("jack", makeString());
getFirstNotEmptyString("jack", new Supplier<String>() {
@Override
public String get() {
return makeString();
}
});
// lambda简化
getFirstNotEmptyString("jack", () -> makeString());
}
static String makeString() {
return String.format("%d %d %d", 1, 2, 3);
}
// 第二个参数的代码会执行
static String getFirstNotEmptyString(String s1, String s2) {
if (s1 != null || s1.length() != 0) return s1;
if (s2 != null || s2.length() != 0) return s2;
return null;
}
static String getFirstNotEmptyString(String s1, Supplier<String> s2Supplier ) {
if (s1 != null || s1.length() != 0) return s1;
String s2 = s2Supplier.get();
if (s2 != null || s2.length() != 0) return s2;
return null;
}
Lambda的使用注意
- lambda只能访问
final
或者有效final
的局部变量 - Lambda没有引入新的作用域
@FunctionalInterface
public interface Testable {
void test(int v);
}
public class OuterClass {
private int age = 1;
public class InnerClass {
private int age = 2;
void innerTest() {
Testable t = v -> {
System.out.println(v); // 3
System.out.println(age); // 2
System.out.println(this.age); // 2
System.out.println(InnerClass.this.age); // 2
System.out.println(OuterClass.this.age); // 1
};
// 由于Lambda没有引入新的作用域 所以表达式里的代码有些类似于直接写在表达式的外面
/* 类似于把代码写在这里
System.out.println(v); // 3
System.out.println(age); // 2
System.out.println(this.age); // 2
System.out.println(InnerClass.this.age); // 2
System.out.println(OuterClass.this.age); // 1
*/
t.test(3);
}
}
public static void main(String[] args) {
new OuterClass().new InnerClass().innerTest();
}
}
方法引用(Method Reference)
如果Lambda中的内容仅仅是调用某个方法,可以使用方法引用
种类 | 用法 |
---|---|
引用静态方法 | ClassName::staticMethodName |
引用特定对象的实例方法 | ObjectName::instanceMethodName |
引用特定类型的任意对象的实例方法 | ClassName::methodName |
引用构造方法 | ClassName::new |
引用当前类中定义的实例方法 | this::instanceMethodName |
引用父类中定义的实例方法 | super::instanceMethodName |
方法引用本质是一个语法糖,其本质还是那么复杂
public interface Testable {
int test(int v1, int v2);
}
public class Main {
public static void main(String[] args) {
// lambda表达式
Testable t1 = (v1, v2) -> {
return Math.max(v1, v2);
};
// 稍微精简下
Testable t2 = (v1, v2)-> Math.max(v1, v2);
// 使用方法引用简化
Testable t3 = Math::max;
System.out.println(t1.test(30, 50)); // 50
System.out.println(t2.test(30, 50)); // 50
System.out.println(t3.test(30, 50)); // 50
}
}
引用特定对象的实例方法
public interface Testable {
void test(int v);
}
public class Person {
public void setAge(int age) {
System.out.println("Person - age = " + age);
}
}
public class Main {
static void execute(Testable t, int v) {
t.test(v);
}
public static void main(String[] args) {
//
execute(v -> new Person().setAge(v),10);
//
execute(new Person()::setAge, 10);
}
}
网友评论