Java函數(shù)式Lambda編程的使用學(xué)習(xí)(圖文教程)
函數(shù)式編程指的是使用Lambda函數(shù)替代某些匿名內(nèi)部類(lèi),從而讓程序代碼更簡(jiǎn)潔,可讀性更好
1.Lambda表達(dá)式
1.1 定義
- JDK 8開(kāi)始新增的一種語(yǔ)法形式,它表示函數(shù)
- 可以用于替代某些匿名內(nèi)部類(lèi),從而讓程序更簡(jiǎn)潔,可讀性更好
Tips:Lambda表達(dá)式只能替代函數(shù)式接口的匿名內(nèi)部類(lèi)
(被重寫(xiě)方法的形參列表)->
{
被重寫(xiě)方法的方法體代碼
}
函數(shù)式接口:
- 有且僅有一個(gè)抽象方法的接口
- 注意:將來(lái)見(jiàn)到的大部分函數(shù)式接口,上面都可能會(huì)有一個(gè)@FunctionalInterface的注解,該注解用于約束當(dāng)前接口必須是函數(shù)式接口
public class Lambdademo {
public static void main(String[] args) {
Animal a = new Animal() {
@Override
public void eat() {
System.out.println("狗吃骨頭");
}
};
a.eat();
System.out.println("============================");
Swim s1=new Swim() {
@Override
public void swim() {
System.out.println("學(xué)生游泳賊快");
}
}
Swim s2=()->{
System.out.println("學(xué)生游泳賊快");
}
}
}
abstract class Animal{
abstract void eat();
}
//函數(shù)式接口:有且僅有一個(gè)抽象方法的接口
@FunctionalInterface//聲明函數(shù)式接口的注解
interface Swim{
void swim();
}
分析這段代碼:
Animal由于只是抽象類(lèi)不是接口,所以不能使用Lambda表達(dá)式替代
而Swim是接口,且只有一個(gè)抽象方法所以能被Lambda表達(dá)式替代
**為什么這個(gè)Lambda能替代?**因?yàn)槟芡茢喑錾舷挛?,Swim s2能推斷出是一個(gè)接口,后面的方法體代碼能代碼能推斷出只有一個(gè)抽象方法,所以能推斷出原來(lái)的代碼如s1。
1.2 實(shí)例
1.2.1 用comparator接口的匿名內(nèi)部函數(shù)類(lèi)實(shí)現(xiàn)對(duì)數(shù)組進(jìn)行排序
在匿名內(nèi)部類(lèi)中使用comparator接口的匿名內(nèi)部函數(shù)類(lèi)實(shí)現(xiàn)對(duì)數(shù)組進(jìn)行排序代碼中可以看到編譯器用灰色標(biāo)記Comparator提示可以進(jìn)行Lambda表達(dá)式進(jìn)行簡(jiǎn)化,進(jìn)入該方法的聲明,該方法有聲明函數(shù)式接口的注解,說(shuō)明該匿名內(nèi)部類(lèi)可以使用Lambda表達(dá)式進(jìn)行化簡(jiǎn)
import com.fqw.anonymousclass.Student;
import java.util.Arrays;
import java.util.Comparator;
public class Lambdademo1 {
public static void main(String[] args) {
Student[] students=new Student[6];
students[0]=new Student("張三", 18, 1.75);
students[1]=new Student("李四", 23, 1.80);
students[2]=new Student("王五", 20, 1.65);
students[3]=new Student("趙六", 17, 1.70);
students[4]=new Student("錢(qián)七", 22, 1.65);
students[5]=new Student("孫八", 16, 1.75);
//輸出排序前的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2)
{
return o1.getAge()-o2.getAge();//升序
}
});
System.out.println("=======================================");
//輸出排序后的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
}
}


簡(jiǎn)化后的代碼
import com.fqw.anonymousclass.Student;
import java.util.Arrays;
import java.util.Comparator;
public class Lambdademo1 {
public static void main(String[] args) {
Student[] students=new Student[6];
students[0]=new Student("張三", 18, 1.75);
students[1]=new Student("李四", 23, 1.80);
students[2]=new Student("王五", 20, 1.65);
students[3]=new Student("趙六", 17, 1.70);
students[4]=new Student("錢(qián)七", 22, 1.65);
students[5]=new Student("孫八", 16, 1.75);
//輸出排序前的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
Arrays.sort(students, (Student o1, Student o2)->{
return o1.getAge()-o2.getAge();//升序
});
System.out.println("=======================================");
//輸出排序后的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
}
}
1.2.2 登錄窗口登錄
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Lambdademo2 {
public static void main(String[] args) {
//需求:創(chuàng)建一個(gè)登錄窗口,登錄窗口中包含一個(gè)登錄按鈕
JFrame win = new JFrame("登錄窗口");
win.setSize(300, 200);
win.setLocationRelativeTo(null);//居中顯示
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//創(chuàng)建一個(gè)面板,把按鈕添加到面板中
JPanel panel = new JPanel();
win.add(panel);
//創(chuàng)建一個(gè)按鈕
JButton button = new JButton("登錄");
panel.add(button);
//java要求必須給按鈕添加一個(gè)點(diǎn)擊事件監(jiān)聽(tīng)器對(duì)象,這樣就可以監(jiān)聽(tīng)用戶(hù)事件,做出反應(yīng)
button.addActionListener((ActionEvent e) -> {
System.out.println("登錄成功");
});
win.setVisible(true);
}
}
1.3 省略規(guī)則(進(jìn)一步簡(jiǎn)化Lambda表達(dá)式的寫(xiě)法)
- 參數(shù)類(lèi)型全部可以省略不寫(xiě)
- 如果只有一個(gè)參數(shù),參數(shù)類(lèi)型省略的同時(shí)“()”也可以省略,但多個(gè)參數(shù)不能省略“()”
- 如果Lambda表達(dá)式只有一行代碼,大括號(hào)可以不寫(xiě),同時(shí)要省略分號(hào)”;”,如果這行代碼是return語(yǔ)句,也必須去掉return
根據(jù)簡(jiǎn)化規(guī)則簡(jiǎn)化后的代碼:
import com.fqw.anonymousclass.Student;
import java.util.Arrays;
import java.util.Comparator;
public class Lambdademo1 {
public static void main(String[] args) {
Student[] students=new Student[6];
students[0]=new Student("張三", 18, 1.75);
students[1]=new Student("李四", 23, 1.80);
students[2]=new Student("王五", 20, 1.65);
students[3]=new Student("趙六", 17, 1.70);
students[4]=new Student("錢(qián)七", 22, 1.65);
students[5]=new Student("孫八", 16, 1.75);
//輸出排序前的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
Arrays.sort(students, ( o1, o2) -> o1.getAge()-o2.getAge());
System.out.println("=======================================");
//輸出排序后的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
}
}
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Lambdademo2 {
public static void main(String[] args) {
//需求:創(chuàng)建一個(gè)登錄窗口,登錄窗口中包含一個(gè)登錄按鈕
JFrame win = new JFrame("登錄窗口");
win.setSize(300, 200);
win.setLocationRelativeTo(null);//居中顯示
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//創(chuàng)建一個(gè)面板,把按鈕添加到面板中
JPanel panel = new JPanel();
win.add(panel);
//創(chuàng)建一個(gè)按鈕
JButton button = new JButton("登錄");
panel.add(button);
//java要求必須給按鈕添加一個(gè)點(diǎn)擊事件監(jiān)聽(tīng)器對(duì)象,這樣就可以監(jiān)聽(tīng)用戶(hù)事件,做出反應(yīng)
button.addActionListener(e -> System.out.println("登錄成功"));
win.setVisible(true);
}
}
2.方法引用(了解)
2.1 靜態(tài)方法引用
類(lèi)名::靜態(tài)方法
使用場(chǎng)景:如果某個(gè)Lambda表達(dá)式里只調(diào)用一個(gè)靜態(tài)方法,并且“->”前后參數(shù)的形式一致,就可以使用靜態(tài)方法
1.首先,在類(lèi)中定義一個(gè)靜態(tài)的方法,如學(xué)生類(lèi)中定義一個(gè)比較年齡的靜態(tài)類(lèi)
package com.fqw.method1reference;
public class Student {
//姓名、年齡、身高
private String name;
private int age;
private double height;
public Student() {}
public Student(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public static int compareAge(Student s1, Student s2){
return s1.getAge() - s2.getAge();
}
}
2.接著,使用靜態(tài)方法引用
package com.fqw.method1reference;
import java.util.Arrays;
public class Demo1{
public static void main(String[] args) {
Student[] students=new Student[6];
students[0]=new Student("張三", 18, 1.75);
students[1]=new Student("李四", 23, 1.80);
students[2]=new Student("王五", 20, 1.65);
students[3]=new Student("趙六", 17, 1.70);
students[4]=new Student("錢(qián)七", 22, 1.65);
students[5]=new Student("孫八", 16, 1.75);
//輸出排序前的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
//Arrays.sort(students, ( o1, o2) -> o1.getAge()-o2.getAge);
//Arrays.sort(students, ( o1, o2) -> Student.compareAge(o1,o2));
//靜態(tài)方法引用 類(lèi)名::靜態(tài)方法
Arrays.sort(students, Student::compareAge);
System.out.println("=======================================");
//輸出排序后的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
}
}
2.2 實(shí)例方法引用
對(duì)象名::實(shí)例方法
使用場(chǎng)景:如果某個(gè)Lambda表達(dá)式里只是通過(guò)對(duì)象名稱(chēng)調(diào)用一個(gè)實(shí)例方法,并且“->”前后參數(shù)的形式一致,就可以使用實(shí)例方法
package com.fqw.method1reference;
public class Student {
//姓名、年齡、身高
private String name;
private int age;
private double height;
public Student() {}
public Student(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public int compareByHeight(Student o1,Student o2){
return Double.compare(o1.getHeight(), o2.getHeight());
}
}
package com.fqw.method1reference;
import java.util.Arrays;
public class Demo2 {
public static void main(String[] args) {
Student[] students=new Student[6];
students[0]=new Student("張三", 18, 1.75);
students[1]=new Student("李四", 23, 1.80);
students[2]=new Student("王五", 20, 1.65);
students[3]=new Student("趙六", 17, 1.70);
students[4]=new Student("錢(qián)七", 22, 1.65);
students[5]=new Student("孫八", 16, 1.75);
//輸出排序前的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
//實(shí)例方法引用 對(duì)象名::靜態(tài)方法
Student t=new Student();
//Arrays.sort(students, ( o1, o2) -> t.compareByHeight(o1,o2));
Arrays.sort(students, t::compareByHeight);
System.out.println("=======================================");
//輸出排序后的學(xué)生數(shù)組
for (int i=0;i<students.length;i++){
Student student = students[i];
System.out.println(student.getName()+","+ student.getAge()+","+ student.getHeight());
}
}
}
2.3 特定類(lèi)型方法的引用
特定類(lèi)的名稱(chēng)::方法
使用場(chǎng)景:如果某個(gè)Lambda表達(dá)式里只調(diào)用一個(gè)特定類(lèi)型的實(shí)例方法,并且前面參數(shù)列表中的第一個(gè)參數(shù)是作為方法的主調(diào),后面的所有參數(shù)都是作為該實(shí)例方法的入?yún)⒌?,則此時(shí)就可以使用特定類(lèi)型的方法引用
場(chǎng)景:有一個(gè)字符串?dāng)?shù)組,里面有一些人的名字,都是英文名字,請(qǐng)按照名字的英文首字母排序,忽略首字母大小
import java.util.Arrays;
import java.util.Comparator;
public class Demo3 {
public static void main(String[] args) {
//有一個(gè)字符串?dāng)?shù)組,里面有一些人的名字,都是英文名字,請(qǐng)按照名字的英文首字母排序,忽略首字母大小
String[] names=new String[]{"Tom","lisi","angela","zhaoliu","Mike","Jack","Bob","Andy","caocao","Rose"};
// Arrays.sort(names, new Comparator<String>() {
// @Override
// public int compare(String o1, String o2) {
// return o1.compareToIgnoreCase(o2);
// }
// });
//Arrays.sort(names, (o1,o2)->o1.compareToIgnoreCase(o2));
Arrays.sort(names, String::compareToIgnoreCase);
System.out.println(Arrays.toString(names));
}
}
2.4 構(gòu)造器引用
類(lèi)名::new
使用場(chǎng)景:如果某個(gè)Lambda表達(dá)式里只是創(chuàng)建對(duì)象,并且“->”前后參數(shù)的形式一致,就可以使用構(gòu)造器引用
package com.fqw.method1reference;
public class Demo4 {
public static void main(String[] args) {
// CarFactory cf=new CarFactory() {
// @Override
// public Car getCar(String name){
// return new Car(name);
// }
// };
// CarFactory cf=name -> new Car(name);
CarFactory cf=Car:: new ;
Car c1=cf.getCar("奧迪");
System.out.println(c1.getName());
}
}
interface CarFactory{
Car getCar(String name);
}
class Car{
private String name;
public Car() {
}
public Car(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
相關(guān)文章
自定義注解實(shí)現(xiàn)Spring容器注入Bean方式(類(lèi)似于mybatis的@MapperScans)
本文介紹了如何通過(guò)自定義注解@MyService和@MyServiceScans在SpringBoot項(xiàng)目中自動(dòng)將指定包下的類(lèi)注入Spring容器,詳細(xì)解釋了創(chuàng)建自定義注解、定義包掃描器ClassPathBeanDefinitionScanner的作用與實(shí)現(xiàn)2024-09-09
解決@PostConstruct注解導(dǎo)致的程序無(wú)法啟動(dòng)(@PostConstruct的執(zhí)行)
這篇文章主要介紹了解決@PostConstruct注解導(dǎo)致的程序無(wú)法啟動(dòng)(@PostConstruct的執(zhí)行)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
如何更優(yōu)雅的關(guān)閉java文本、網(wǎng)絡(luò)等資源
這篇文章主要介紹了如何更優(yōu)雅的關(guān)閉java文本、網(wǎng)絡(luò)等資源,在 finally 的關(guān)閉代碼中,還要再來(lái)一個(gè) try/catch,看著是不是很難受,很不優(yōu)雅,很想干掉這個(gè) finally!,需要的朋友可以參考下2019-06-06
IntelliJ IDEA連接MySQL數(shù)據(jù)庫(kù)詳細(xì)圖解
今天小編就為大家分享一篇關(guān)于intellij idea連接mysql數(shù)據(jù)庫(kù)詳細(xì)圖解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10
springboot3.x中Jakarta包無(wú)法引入的問(wèn)題
最近想將一些項(xiàng)目升級(jí)到springboot3.x和java17的時(shí)候,發(fā)現(xiàn)項(xiàng)目依賴(lài)中有Jakarta的包,但是代碼標(biāo)紅提示沒(méi)有相關(guān)的類(lèi),本文就來(lái)介紹一下解決方法,感興趣的可以了解一下2024-02-02
Log4j2?重大漏洞編譯好的log4j-2.15.0.jar包下載(替換過(guò)程)
Apache?開(kāi)源項(xiàng)目?Log4j?的遠(yuǎn)程代碼執(zhí)行漏洞細(xì)節(jié)被公開(kāi),由于?Log4j?的廣泛使用,該漏洞一旦被攻擊者利用會(huì)造成嚴(yán)重危害,下面小編給大家?guī)?lái)了Log4j2?重大漏洞編譯好的log4j-2.15.0.jar包下載,感興趣的朋友一起看看吧2021-12-12
Java數(shù)組常用排序算法實(shí)例小結(jié)
這篇文章主要介紹了Java數(shù)組常用排序算法,結(jié)合實(shí)例形式總結(jié)分析了java數(shù)組常用的4種排序算法,包括冒泡排序、數(shù)組遞增排序、快速排序及選擇排序,需要的朋友可以參考下2017-12-12
Java如何使用elasticsearch進(jìn)行模糊查詢(xún)
這篇文章主要介紹了Java如何使用elasticsearch進(jìn)行模糊查詢(xún),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02

