Java基礎(chǔ)之JDK1.8新特性lambda表達式詳解
Lambda表達式
Lambda表達式允許把函數(shù)作為一個方法的參數(shù)(函數(shù)作為參數(shù)傳遞進方法中)。函數(shù)式接口有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。函數(shù)式接口可以被隱式轉(zhuǎn)換為lambda表達式。
各種函數(shù)式接口
java.lang.Runnable java.util.concurrent.Callable java.security.PrivilegedAction java.util.Comparator java.io.FileFilter
JDK1.8 新增加的函數(shù)接口:
java.util.function
java.util.function 包下包含了很多類,用來支持Java的函數(shù)式編程
| 接口 | &描述 |
|---|---|
| BiConsumer<T,U> | 代表了一個接受兩個輸入?yún)?shù)的操作,并且不返回任何結(jié)果 |
| BiFunction<T,U,R> | 代表了一個接受兩個輸入?yún)?shù)的方法,并且返回一個結(jié)果 |
| BinaryOperaror | 代表了一個作用于兩個同類型操作符的操作,并且返回了操作符同類型的結(jié)果 |
| BiPredicate<T,U> | 代表了一個兩個參數(shù)的boolean值方法 |
| BooleanSupplier | 代表了boolean值結(jié)果的提供方 |
| Consumer | 代表了接受一個輸入?yún)?shù)并且無返回的操作 |
| DoubleBinaryOperator | 代表了作用于兩個double值操作符的操作,并且返回了一個double值的結(jié)果 |
| DoubleConsumer | 代表了一個接受double值參數(shù)的操作,并且不返回結(jié)果 |
| DoubleFunction | 代表接受一個double值參數(shù)的方法,并且有返回值 |
| Comparator | 這個接口最主要的作用就是比較,其核心的方法是 compare(T o1, T o2),當(dāng) o1比o2小返回-1,當(dāng)o1等于o2返回0,當(dāng)o1大于o2返回1 |
Lambda的語法
(parameters) -> expression
或
(parameters) ->{ statements; }- 可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識別參數(shù)值
- 可選的參數(shù)圓括號:一個參數(shù)無需定義圓括號,但多個參數(shù)需要定義圓括號
- 可選的大括號:如果主體包括了一個語句,就不需要使用大括號
- 可選的返回關(guān)鍵字:如果主體只有一個表達式返回值,則編譯器會自動返回值,大括號需要指明表達式返回的一個數(shù)值。
Lambda 表達實例
//1. 不需要參數(shù),返回值為5
()->5;
//2. 接收一個參數(shù)(數(shù)字類型),返回其2倍的值
x ->2*x
//3.接受2個參數(shù)(數(shù)字),并返回他們的差值
(x,y)->x - y;
//4.接收2個int型整數(shù),返回他們的和
(int x,int y)->x+y;
//5. 接收一個String對象,并在控制臺打印,不返回任何值
(String s)->System.out.print(s);舉例說明
public class Java8Tester {
public static void main(String[] args) {
Java8Tester tester = new Java8Tester();
//類型聲明
MathOperation addition = (int a, int b) -> a + b;
//不用聲明類型
MathOperation subtraction = (a, b) -> a - b;
//大括號中的返回語句
MathOperation multipliaction = (int a, int b) -> {
return a * b;
};
//沒有大括號及返回語句
MathOperation division = (int a, int b) -> a / b;
System.out.println("10+5=" + tester.operate(10, 5, addition));
System.out.println("10-5=" + tester.operate(10, 5, subtraction));
System.out.println("10*5=" + tester.operate(10, 5, multipliaction));
System.out.println("10/5=" + tester.operate(10, 5, division));
//不用括號
GreetingService greetingService1 = message -> System.out.println("Hello " + message);
//用括號
GreetingService greetingService2 = (message) -> System.out.println("Hello " + message);
greetingService1.sayMessage("Runoob");
greetingService2.sayMessage("Google");
}
interface MathOperation{
int operation(int a, int b);
}
interface GreetingService{
void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation) {
return mathOperation.operation(a, b);
}
}變量作用域
lambda 表達式只能引用標記了final的外層局部變量,也就是說不能再lambda內(nèi)部修改定義在域外的局部變量,否則會編譯報錯。 在lambda表達式中,只能引用值不會改變的變量。 這是因為如果在lambda表達式中改變變量,并發(fā)執(zhí)行多個動作時就會不安全。對于目前為止我們看到的動作不會發(fā)生這種情況。
public class Java8Test2 {
final static String salutation = "Hello!";
public static void main(String[] args) {
GreetingService greetingService = message -> System.out.println(salutation + message);
greetingService.sayMessage("Runoob");
}
interface GreetingService {
void sayMessage(String message);
}
}處理lambda 表達式
使用lambda表達式的重點是延遲執(zhí)行。畢竟,如果想要立即執(zhí)行代碼,完全可以直接執(zhí)行,而無需把它包裝在一個lambda表達式中。之所以希望以后執(zhí)行代碼,這有很多原因,如:
- 在一個單獨的線程中運行代碼:
- 多次運行代碼;
- 在算法的適當(dāng)位置運行代碼(例如:排序中的比較操作);
- 發(fā)生某種情況時執(zhí)行代碼(如,點擊了一個按鈕,數(shù)據(jù)到達,等等);
- 只在必要時才運行代碼。
例如:假設(shè)你想要執(zhí)行一個動作n次,將這個動作和重復(fù)次數(shù)傳遞到一個 repeat 方法: repeat(10,()->System.out.println("Hello,world")) 要接受這個lambda表達式,需要選擇一個函數(shù)式接口。例如,我們可以使用 Runnable 接口:
public static void repeat(int n,Runnable action){
for(int i=0;i<n;i++){
action.run();
}
}如果要告訴動作出現(xiàn)在某次迭代中。
/**
* 在某次迭代中執(zhí)行動作
* @param n
* @param action
*/
public static void repeat(int n, IntConsumer action) {
for (int i = 0; i < n; i++) {
action.accept(i);
}
}變量作用域
lambda 表達式有3個部分
- 一個代碼塊;
- 參數(shù);
- 自由變量的值,這里指非參數(shù)而且不在代碼中定義的變量。
函數(shù)式接口
函數(shù)接口,是指內(nèi)部只有一個抽象方法的接口。但是可以有多個非抽象方法的接口,函數(shù)式接口可以被隱式轉(zhuǎn)換為lambda表達式。
使用實例1
public class PredicateTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
/**
*
* Predicate<Integer> dispatcher = n -> true;
n 是一個參數(shù)傳遞到Predicate接口的test方法
n 如果存在test方法返回true
*/
System.out.println("輸出所有數(shù)據(jù):");
//傳遞參數(shù)n
eval(list, n -> true);
// Predicate<Integer> dispatcher = n -> true;
// n 是一個參數(shù)傳遞到Predicate接口的test方法
// 如果n%2為0,test方法返回true
System.out.println("******輸出所有的偶數(shù):");
eval(list, n -> n % 2 == 0);
// Predicate<Integer> predicate2=n->n>3
// n是一個參數(shù)傳遞到Predicate接口的test方法
// 如果n大于3 test方法返回true
System.out.println("輸出大于3的所有數(shù)字:");
eval(list, n -> n > 3);
}
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for (Integer n : list) {
if (predicate.test(n)) {
System.out.println(n+" ");
}
}
}
}使用實例2
public class CompareTest {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "pear");
compareLength("apple", "banana", (n1, n2) -> -1);
compareLength("banana", "pear", (n1, n2) -> 1);
compareLength("banana", "banana", (n1, n2) -> 0);
words.sort(Comparator.comparingInt(String::length));
}
public static void compareLength(String n1, String n2, Comparator comparator) {
if (comparator.compare(n1, n2) == 0) {
System.out.println("n1==n2" + n1 + " " + n2);
}
if (comparator.compare(n1, n2) > 0) {
System.out.println("n1>n2" + n1 + " " + n2);
}
if (comparator.compare(n1, n2) < 0) {
System.out.println("n1<n2" + n1 + " " + n2);
}
}
}使用示例3(集合排序)
現(xiàn)在我們有一個集合list,集合的里的數(shù)據(jù)類型是HashMap。那么我們?nèi)绾胃鶕?jù)HashMap中的某個key給list排序呢?
public class ListSortTest {
public static void main(String[] args) {
List<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> map1 = new HashMap<>();
map1.put("id", 2);
map1.put("name", "張二");
list.add(map1);
Map<String, Object> map2 = new HashMap<>();
map2.put("id", 1);
map2.put("name", "張一");
list.add(map2);
Map<String, Object> map3 = new HashMap<>();
map3.put("id", 3);
map3.put("name", "張三");
list.add(map3);
//升序排列
Collections.sort(list, (o1, o2) -> {
int o1Id = (int) o1.get("id");
int o2Id = (int) o2.get("id");
if (o1Id > o2Id) {
return 1;
} else {
return -1;
}
});
//降序排列
Collections.sort(list, new Comparator<Map<String, Object>>() {
@Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
int o1Id = (int) o1.get("id");
int o2Id = (int) o2.get("id");
if (o1Id > o2Id) {
return -1;
} else {
return 1;
}
}
});
}
}使用示例4(按照對象屬性給list排序)
public class ListSortTest2 {
public static void main(String[] args) {
Student student1 = new Student(1, "張三");
Student student2 = new Student(2, "李四");
List<Student> studentList = new ArrayList<>();
studentList.add(student1);
studentList.add(student2);
//升序
studentList.sort((o1, o2) -> {
int o1Id = o1.getId();
int o2Id = o2.getId();
if (o1Id > o2Id) {
return 1;
} else {
return -1;
}
});
//降序
studentList.sort((o1, o2) -> {
int o1Id = o1.getId();
int o2Id = o2.getId();
if (o1Id > o2Id) {
return -1;
} else {
return 1;
}
});
}使用示例4
自定義一個函數(shù)式接口
public class SimpleLambda {
public static void main(String[] args) {
start(()-> System.out.println("調(diào)用函數(shù)式接口"));
}
public static void start(MyRunnable runnable) {
new Thread(runnable).start();
}
//1. 只能有一個抽象方法
//2.默認方法除外
//3.可以加FunctionalInterface注解,也可以不加
public interface MyRunnable extends Runnable {
default void myRun() {
}
}
}自定義一個函數(shù)式接口,傳入?yún)?shù),多種不同的代碼編寫特性:
public class SimpleLambda2 {
public static void main(String[] args) {
// 1.單行表達式,可以省略return
run(name -> String.format(name));
// 2.代碼塊
run(name -> {
String name1 = name;
return "序列化" + name1;
});
//3.方法引用,靜態(tài)方法引用
run(SimpleLambda2::toFormat);
//4.普通方法引用
run(new SimpleLambda2()::toFormat2);
}
static void run(Format format) {
format.format("飛哥");
}
static String toFormat(String param) {
return "序列化" + param;
}
String toFormat2(String param) {
return "序列化" + param;
}
public interface Format {
String format(String name);
}
}自定義一個函數(shù)式接口,帶泛型的方法型函數(shù)
public class SimpleLambda4 {
public static void main(String[] args) {
Apple apple = new Apple(1, "紅色", 12, "安徽");
Banner banner1 = doBuild(apple, apple1 -> {
Banner banner = new Banner();
banner.setPrice(apple1.getPrice());
banner.setColor(apple1.getColor());
return banner;
});
System.out.println(banner1);
}
public static Banner doBuild(Apple apple, Format format) {
return format.build(apple);
}
@FunctionalInterface
public interface Format<T extends Apple, R extends Banner> {
R build(T t);
}
}總結(jié)
本文詳細介紹了lambda表達式,lambda表達式是JDK1.8最重要的特性。基本上所有的內(nèi)部類都可以用lambda表達式來表示。靈活的運用lambda表達式和函數(shù)式接口可以大大的簡化的程序開發(fā)。
參考
[Java 8 函數(shù)式接口](
到此這篇關(guān)于Java基礎(chǔ)之lambda表達式(JDK1.8新特性)的文章就介紹到這了,更多相關(guān)JDK1.8新特性 lambda表達式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot整合Rabbitmq之Confirm和Return機制
這篇文章主要介紹了Springboot整合Rabbitmq之Confirm和Return詳解,本篇重點進行Confirm?機制和Return?機制的實現(xiàn)和說明,通過實例代碼相結(jié)合給大家詳細介紹,對Springboot整合Rabbitmq相關(guān)知識感興趣的朋友一起看看吧2022-02-02
使用dynamic datasource springboot starter實現(xiàn)多數(shù)據(jù)源及源碼分析
這篇文章主要介紹了使用dynamic-datasource-spring-boot-starter做多數(shù)據(jù)源及源碼分析,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09
Java編程實現(xiàn)快速排序及優(yōu)化代碼詳解
這篇文章主要介紹了Java編程實現(xiàn)快速排序及優(yōu)化代碼詳解,具有一定借鑒價值,需要的朋友可以了解下。2017-12-12

