目前Java 8的新特性Lambda 結合 RxJava 在一起使用可以簡化大量的代碼,下面簡單介紹在AndroidStudio中配置Gradle使得支持Java 8。
Android 使用Java8 配置
添加插件retrolambda
在project層的build.gradle配置
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'me.tatarka:gradle-retrolambda:3.2.5' //添加插件retrolambda
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
配置android{}區塊Jav//java版本8
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
配置完成之後的build.gradle文件
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'me.tatarka:gradle-retrolambda:3.2.4' //for java 8 lamda
}
}
apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.mrljdx.sample"
minSdkVersion 10
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
//java版本8
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
.....//省略其他配置
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
//java 8 配置
retrolambdaConfig 'net.orfjackal.retrolambda:retrolambda:+'
}
配置proguard.pro混淆文件
## see https://github.com/evant/gradle-retrolambda for java 8
-dontwarn java.lang.invoke.*
Lambda表達式
lambda表達式取代了匿名內部類,取消了模板,允許程序猿用函數式風格編寫代碼,使代碼可讀性更高,儘管剛開始你會看不懂,但是你應該嘗試,畢竟這是新的東西,我已從中獲益。
格式
基本格式是:() -> {}
有下面三種具體表達:
1.(params) -> expression
2.(params) -> statement
3.(params) -> {statement}
使用Java 8 lambda表達式進行事件處理
傳統的點擊事件,應用匿名內部類:
Button button = new Button(mContext);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, "button click", Toast.LENGTH_SHORT).show();
}
});
}
如果按照之前Studio配置好了的話會有提示:
使用lambda表達式之後是這樣的
button.setOnClickListener(v -> Toast.makeText(mContext, "button click", Toast.LENGTH_SHORT).show());
一行代碼就搞定了,清晰可見,把行爲傳到了函數裏,這裏注意v不可省略,是函數onClick的參數;
傳統實現Runnable接口是這樣的:
new Thread(new Runnable() {
@Override
public void run() {
Log.i("TAG", "haha");
}
}).start();
使用lambda表達式之後是這樣的:
new Thread(() -> {
Log.i("TAG", "haha");
}).start();
使用lambda表達式對列表進行迭代
List<String> features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
System.out.println(feature);
}
// Java 8之後:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
features.forEach(n -> System.out.println(n));
// 使用Java 8的方法引用更方便,方法引用由::雙冒號操作符標示,
// 看起來像C++的作用域解析運算符
features.forEach(System.out::println);
輸出結果:
Lambdas
Default Method
Stream API
Date and Time API
使用lambda表達式和函數式接口Predicate
除了在語言層面支持函數式編程風格,Java 8也添加了一個包,叫做 java.util.function。它包含了很多類,用來支持Java的函數式編程。其中一個便是Predicate,使用 java.util.function.Predicate 函數式接口以及lambda表達式,可以向API方法添加邏輯,用更少的代碼支持更多的動態行爲。下面是Java 8 Predicate 的例子,展示了過濾集合數據的多種常用方法。Predicate接口非常適用於做過濾。
public static void main(args[]){
List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
System.out.println("Languages which starts with J :");
filter(languages, (str)->str.startsWith("J"));
System.out.println("Languages which ends with a ");
filter(languages, (str)->str.endsWith("a"));
System.out.println("Print all languages :");
filter(languages, (str)->true);
System.out.println("Print no language : ");
filter(languages, (str)->false);
System.out.println("Print language whose length greater than 4:");
filter(languages, (str)->str.length() > 4);
}
public static void filter(List names, Predicate condition) {
for(String name: names) {
if(condition.test(name)) {
System.out.println(name + " ");
}
}
}
輸出結果:
Languages which starts with J :
Java
Languages which ends with a
Java
Scala
Print all languages :
Java
Scala
C++
Haskell
Lisp
Print no language :
Print language whose length greater than 4:
Scala
Haskell
// 更好的辦法
public static void filter(List names, Predicate condition) {
names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
System.out.println(name + " ");
});
}
如何在lambda表達式中加入Predicate
上個例子說到,java.util.function.Predicate 允許將兩個或更多的 Predicate 合成一個。它提供類似於邏輯操作符AND和OR的方法,名字叫做and()、or()和xor(),用於將傳入 filter() 方法的條件合併起來。例如,要得到所有以J開始,長度爲四個字母的語言,可以定義兩個獨立的 Predicate 示例分別表示每一個條件,然後用 Predicate.and() 方法將它們合併起來,如下所示:
// 甚至可以用and()、or()和xor()邏輯函數來合併Predicate,
// 例如要找到所有以J開始,長度爲四個字母的名字,你可以合併兩個Predicate並傳入
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
.filter(startsWithJ.and(fourLetterLong))
.forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));
…還有很多使用方法詳細查看:Java8 lambda表達式10個示例
比較
既然lambda表達式即將正式取代Java代碼中的匿名內部類,那麼有必要對二者做一個比較分析。
第一個關鍵的不同點就是關鍵字 this。匿名類的 this 關鍵字指向匿名類,而lambda表達式的 this 關鍵字指向包圍lambda表達式的類。
第二是編譯方式。Java編譯器將lambda表達式編譯成類的私有方法。使用了Java 7的 invokedynamic 字節碼指令來動態綁定這個方法。