匿名類(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();
// 如果需要初始化之后立即執(zhí)行某個函數 可以
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傳參,可以避免代碼的浪費執(zhí)行(有必要時再執(zhí)行代碼)
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;
}
上面的示例中,我們確定了第一個參數不為空,也就沒必要執(zhí)行第二個參數的代碼,但是現在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);
}
// 第二個參數的代碼會執(zhí)行
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中的內容僅僅是調用某個方法,可以使用方法引用
| 種類 | 用法 |
|---|---|
| 引用靜態(tài)方法 | 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);
}
}