【Java】Java 中的方法引用寫法

概述

方法引用(MethodReference)是Lambda表達式的另一種格式,在某些場景下可以提高代碼的可讀性

使用條件

只可以替換單方法的Lambda表達式

什么意思呢 ?

例如下面這個Lambda表達式就不可以使用方法引用替換,因為其不是單方法的,有好幾行呢。如果想要使用方法引用就需要將Lambda結構體重構為一個方法。

Predicate<Integer> p2 = integer -> {System.out.println("Hello World");return TestUtil.isBiggerThan3(integer);};

下面這個就可以使用方法引用替換了

Predicate<Integer> p2 = integer -> TestUtil.isBiggerThan3(integer);

使用場景

當使用方法引用替換Lambda表達式具有更好的可讀性時,考慮使用。

方法引用的類型

方法引用可以分為分四類,只要掌握了類型區別一切就變得易如反掌了。為行文方便,這里先列出要使用的類:

TestUtil 里面有一個靜態方法,一個實例方法。Student 是一個普通實體類,具體如下代碼所示

public class MethodReference {...//示例類public static class TestUtil {public static boolean isBiggerThan3(int input) {return input > 3;}public void printDetail(Student student) {System.out.println(student.toString());}}public static class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getStatus(String thing) {return String.format("%d歲的%s正在%s", age, name, thing);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}}
}

調用類的靜態方法

Lambda 表達式的那個單方法是某個類的靜態方法

有如下格式,args 是參數,可以是多個,例如(a1,a2,a3)

Lambda:

(args) -> Class.staticMethod(args)

Method Reference:

Class::staticMethod

符合上面形式的調用,不管有多少參數,都省略掉,編譯器自動會幫我們傳入

看看下面的實例代碼,其中 isBiggerThan3 是TestUtil 類的 static 方法。從上面的代碼你可以清晰的看到,方法從匿名類到 Lambda 再到方法引用的演變。

public void testStaticMethodRef() {//匿名內部類形式Predicate<Integer> p1 = new Predicate<Integer>() {@Overridepublic boolean test(Integer integer) {return TestUtil.isBiggerThan3(integer);}};//lambda表達式形式Predicate<Integer> p2 = integer -> TestUtil.isBiggerThan3(integer);//MethodReference形式Predicate<Integer> p3 = TestUtil::isBiggerThan3;Stream.of(1, 2, 3, 4, 5).filter(p3).forEach(System.out::println);
}

調用傳入的實例參數的方法

Lambda:

(obj, args) -> obj.instanceMethod(args)

Method Reference:

ObjectType::instanceMethod

看到我們 Lambda 的入參 obj 了嗎?它是一個類型,假設為 ObjectType,的實例對象。然后再看 Lambda 表達式,是在調用此實例 obj 的方法。這種類型的 Lambda 就可以寫成上面的形式了,看起來和靜態方法那個一樣。

來看看下面的實例代碼

public void testInstanceMethodRef1() {//匿名類BiFunction<Student, String, String> f1 = new BiFunction<Student, String, String>() {@Overridepublic String apply(Student student, String s) {return student.getStatus(s);}};//lambdaBiFunction<Student, String, String> f2 = (student, s) -> student.getStatus(s);//method referenceBiFunction<Student, String, String> f3 = Student::getStatus;System.out.println(getStudentStatus(new Student("erGouWang", 18), "study", f3));
}
private String getStudentStatus(Student student, String action, BiFunction<Student, String, String> biFunction) {return biFunction.apply(student, action);
}

調用已經存在的實例的方法

Lambda:

(args) -> obj.instanceMethod(args)

Method Reference:

obj::instanceMethod

我們觀察一下我們 Lambda 表達式,發現obj對象不是當做參數傳入的,而是已經存在的,所以寫成方法引用時就是實例::方法

來看看下面的實例代碼,可見 utilObj 對象是我們提前 new 出來的,是已經存在了的對象,不是 Lambda 的入參。

public void testInstanceMethodRef2() {TestUtil utilObj = new TestUtil();//匿名類Consumer<Student> c1 = new Consumer<Student>() {@Overridepublic void accept(Student student) {utilObj.printDetail(student);}};//Lambda表達式Consumer<Student> c2 = student -> utilObj.printDetail(student);//方法引用Consumer<Student> c3 = utilObj::printDetail;//使用consumeStudent(new Student("erGouWang", 18), c3);
}private void consumeStudent(Student student, Consumer<Student> consumer) {consumer.accept(student);
}

調用類的構造函數

Lambda:

(args) -> new ClassName(args)

Method Reference:

ClassName::new

當 Lambda 中的單方法是調用某個類的構造函數,我們就可以將其寫成如上形式的方法引用。

public void testConstructorMethodRef() {BiFunction<String, Integer, Student> s1 = new BiFunction<String, Integer, Student>() {@Overridepublic Student apply(String name, Integer age) {return new Student(name, age);}};//lambda表達式BiFunction<String, Integer, Student> s2 = (name, age) -> new Student(name, age);//對應的方法引用BiFunction<String, Integer, Student> s3 = Student::new;//使用System.out.println(getStudent("cuiHuaNiu", 20, s3).toString());
}private Student getStudent(String name, int age, BiFunction<String, Integer, Student> biFunction) {return biFunction.apply(name, age);
}

來看看下面的實例代碼,上面代碼值得注意的就是,Student 類必須有一個與 Lambda 入參相匹配的構造函數。例如此例中,(name, age) -> new Student(name, age); 需要兩個入參的構造函數,為什么呢?

因為我們的 Lambda 表達式的類型是 BiFunction,而其正是通過兩個入參來構建一個返回的。其簽名如下:

@FunctionalInterface
public interface BiFunction<T, U, R> {R apply(T t, U u);...
}

通過入參 (t,u) 來生成 R 類型的一個值。

我們可以寫一個如下的方法引用:

Function<String, Student> s4 = Student::new;

但是IDE就會報錯,提示我們的 Student 類沒有對應的構造函數,我們必須添加一個如下簽名的構造函數才可以

public Student(String name) {this.name = name;
}

補充

下面這段代碼是一個Spring Security的配置類,可以看到在這段代碼中用到了this::onAuthenticationSuccess,this::onAuthenticationFailure,this::onLogoutSuccess這樣的方法引用寫法。

具體來說,this::onAuthenticationSuccess 表示引用當前類中的 onAuthenticationSuccess 方法。

這里使用 this 表示當前對象(通常是一個類的實例),:: 是方法引用操作符,onAuthenticationSuccess 則是方法的名稱。

在 Spring Security 配置中,使用方法引用可以簡潔地傳遞方法作為參數,而不必顯式地編寫 lambda 表達式。在這種情況下,this::onAuthenticationSuccess 會將當前類的 onAuthenticationSuccess 方法作為參數傳遞給 successHandler 方法。

/*** @ClassName : SecurityConfiguration* @Description : Security配置* @Author : LYQ* @Date: 2024-02-17 19:24*/
@Configuration
public class SecurityConfiguration {@Autowiredprivate JwtUtils jwtUtils;@Autowiredprivate JwtAuthorizeFilter jwtAuthorizeFilter;@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.authorizeHttpRequests(conf -> conf.requestMatchers("/api/auth/**").permitAll().anyRequest().authenticated()).formLogin(conf -> conf.loginProcessingUrl("/api/auth/login").successHandler(this::onAuthenticationSuccess).failureHandler(this::onAuthenticationFailure)).logout(conf -> conf.logoutUrl("/api/auth/logout").logoutSuccessHandler(this::onLogoutSuccess)).exceptionHandling(conf -> conf.accessDeniedHandler(this::onAccessDeny).authenticationEntryPoint(this::onUnauthorized)).csrf(AbstractHttpConfigurer::disable).sessionManagement(conf -> conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).addFilterBefore(jwtAuthorizeFilter, UsernamePasswordAuthenticationFilter.class).build();}public void onAccessDeny(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");response.getWriter().write(RestBean.forbidden(accessDeniedException.getMessage()).asJsonString());}public void onUnauthorized(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {response.setContentType("application/json;charset=UTF-8");response.getWriter().write(RestBean.unauthorized(exception.getMessage()).asJsonString());}public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json");response.setCharacterEncoding("utf-8");User user = (User) authentication.getPrincipal();String token = jwtUtils.createJwt(user, 1, "MrVK");AuthorizeVO vo = new AuthorizeVO();vo.setExpire(jwtUtils.expireTime());vo.setRole("");vo.setToken(token);vo.setUsername("MrVK");response.getWriter().write(RestBean.success(vo).asJsonString());}public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().write(RestBean.unauthorized(exception.getMessage()).asJsonString());}public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");PrintWriter writer = response.getWriter();String authorization = request.getHeader("Authorization");if(jwtUtils.invalidateJwt(authorization)) {writer.write(RestBean.success("退出登錄成功").asJsonString());return;}writer.write(RestBean.failure(400, "退出登錄失敗").asJsonString());}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/717104.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/717104.shtml
英文地址,請注明出處:http://en.pswp.cn/news/717104.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

100243. 將元素分配到兩個數組中 I

說在前面 &#x1f388;不知道大家對于算法的學習是一個怎樣的心態呢&#xff1f;為了面試還是因為興趣&#xff1f;不管是出于什么原因&#xff0c;算法學習需要持續保持。 題目描述 給你一個下標從 1 開始、包含 不同 整數的數組 nums &#xff0c;數組長度為 n 。 你需要通…

C語言 快速排序——qsort函數的介紹

qsort函數 1. 函數介紹2. 函數使用2.1 整型排序2.2 字符排序2.3 字符串排序2.4 結構體排序 3. 用冒泡思想模擬qsort函數 我們以往使用冒泡排序和選擇排序等對數據進行排序時&#xff0c;有可能會遇到搞不清排序次數&#xff0c;運行時間過長等一些問題&#xff0c;并且這些排序…

aop監控spring cloud接口超時,并記錄到數據庫

引入pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0…

寶塔面板安裝各種組件以及部署應用服務

在linux服務器安裝寶塔面板 一、從寶塔官網下載exe安裝包&#xff0c;安裝命令從寶塔官網&#xff08;https://www.bt.cn/&#xff09;獲取 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh二、安…

自動駕駛加速落地,激光雷達放量可期(上)

1 激光雷達應用廣泛&#xff0c;汽車有望成最大催化 激光雷達&#xff08;LiDAR&#xff09;是一種主動遙感技術&#xff0c;通過測定傳感器發出的激光在傳感器與目標物體之間的傳播距離&#xff0c;來分析目標地物表面的反射能量大小、反射波譜的幅度、頻率和相位等信息&#…

Vue項目如何進行優化?

Vue項目優化 1.移除控制臺打印2.壓縮圖片3.CDN加速 1.移除控制臺打印 可以使用插件自動去除&#xff0c;插件包括babel-plugin-transform-remove-console、uglifyjs-webpack-plugin、terser-webpack-plugin。最后選擇了terser-webpack-plugin&#xff0c;腳手架vue-cli用這個插…

一文掃盲:訂單管理系統,訂單是公司生命線。

hello&#xff0c;我是貝格前端工場&#xff0c;本期給大家分享訂單管理系統的知識點&#xff0c;歡迎老鐵們點贊、關注&#xff0c;如有需求可以私信我們。 一、什么是訂單管理系統 單管理系統是一種用于管理和處理訂單的軟件系統。它通常用于企業、電子商務平臺、零售店等需…

高并發高可用--反向代理與負載均衡

高并發高可用架構是指能夠應對大量并發請求并保持高度可用的系統架構。為了實現這一目標&#xff0c;通常會采用一系列技術和策略&#xff0c;包括負載均衡、緩存、分布式系統、冗余部署、容錯處理等。 以下是一些構建高并發高可用架構的關鍵要點&#xff1a; 負載均衡&#…

GEE高階應用python wxee 和eemont——MODIS 中生成NDVI 數據的月度時序影像

結合 wxee 和 eemont eemont概述 谷歌地球引擎是一種基于云的服務,用于矢量和柵格數據的地理空間處理。地球引擎平臺擁有 JavaScript 和 Python API,可使用不同方法處理地理空間對象。谷歌地球引擎還提供了一個巨大的 PETABYTE 級柵格和矢量數據目錄,用戶可以在線處理這些…

技術小知識:面向對象和過程的區別 ⑤

一、思想區別 面相對象&#xff1a;始終把所有事情思考歸類、抽離封裝成對象來調用完成。 面向過程&#xff1a;直接平鋪展開按順序執行完成任務。 面向對象多了很多對象的創建、使用&#xff0c;銷毀的過程資源消耗。是一種模塊化編程思想。 https://www.cnblogs.com/kuangmen…

網絡爬蟲彈幕

1.分析網頁&#xff0c;獲取代碼&#xff0c;提取時間 想要提取出彈幕所在的節點&#xff0c;我們要使用 Beautiful Soup 解析模塊&#xff0c;需要從 bs4 中導入 BeautifulSoup 模塊 創建一個 BeautifulSoup 對象&#xff0c;傳入變量 xml 和解析器 lxml&#xff0c;將該對象賦…

Java自學day5

流程控制語句 流程控制語句:通過一些語句,控制程序的執行流程 順序結構 順序結構語句是Java程序默認的執行流程,按照代碼的先后順序,從上到下依次執行! package orderdemo;public class OrderDemo {public static void main(String[] args) {System.out.println("…

2.2 mul、div、and、or乘除指令及所有寄存器英文名

匯編語言 1. mul乘指令 兩個相乘的數&#xff0c;要么都是8位&#xff0c;要么都是16位 兩個8位數相乘 一個默認放在al中&#xff0c;另一個放在8位reg或內存字節單元中8位乘法&#xff0c;結果默認放在ax中例如&#xff1a;計算100*10 100和10小于255&#xff0c;可以做8位…

一(四)班課表

第二學期 課節時間星期一星期二星期三星期四星期五上午18:20-9:00數學數學數學京劇語文29:10-9:50勞動音樂語文語文音樂310:30-11:10語文語文美術道德與法治數學思維411:20-12:00科學輪滑美術體育英語下午513:20-14:00數學實踐活動音樂欣賞語文英語語文拓展614:10-14:50體育英語…

信息系統安全與對抗-作業2

目錄 1、使用自己姓名拼音創建一個賬戶&#xff0c; 并使用命令和圖形化查看 2、使用自己拼音打頭字母創建一個隱藏賬戶 &#xff0c;并使用命令和圖形化查看 3、使用命令啟動 telnet 服務 4、使用命令打開防火墻 23 端口 5、熟悉LINUX系統&#xff0c;使用命令行創建用戶…

Spring Cloud Nacos集成Seata2.0 AT模式

Spring Cloud Nacos集成Seata2.0 AT模式 以CentOS 7為例&#xff0c;介紹Spring Cloud Nacos集成Seata2.0 AT模式的流程。分成兩個步驟&#xff1a;1.安裝配置seata-server、2.項目集成seata-client 一、下載seata-server安裝包 根據自己的操作系統選擇要下載的安裝包格式&a…

2023年第十四屆藍橋杯大賽軟件類省賽C/C++大學A組真題

2023年第十四屆藍橋杯大賽軟件類省賽C/C大學A組部分真題和題解分享 文章目錄 藍橋杯2023年第十四屆省賽真題-平方差思路題解 藍橋杯2023年第十四屆省賽真題-更小的數思路題解 藍橋杯2023年第十四屆省賽真題-顏色平衡樹思路題解 藍橋杯2023年第十四屆省賽真題-買瓜思路題解 藍橋…

05-Linux部署MySQL

Linux部署MySQL 在今后的使用過程中&#xff0c;需要頻繁使用Linux系統&#xff0c;所以在Linux上安裝軟是必不可少的操作 。 前置要求 需要學習前四章知識&#xff0c;初識Linux、Linux基礎命令、Linux權限管理、Linux高階技巧這4個章節。需要開啟多態虛擬機&#xff0c;電…

KubeSphere簡介,功能介紹,優勢,架構說明及應用場景

KubeSphere 是在目前主流容器調度平臺 Kubernetes 之上構建的企業級分布式多租戶容器平臺&#xff0c;提供簡單易用的操作界面以及向導式操作方式&#xff0c;在降低用戶使用容器調度平臺學習成本的同時&#xff0c;極大減輕開發、測試、運維的日常工作的復雜度&#xff0c;旨…

每日一題 — 快樂數

202. 快樂數 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 可以借用判斷鏈表是否有環的思想&#xff1a; 定義快慢指針&#xff08;兩個變量賦值就行&#xff09;快指針走兩次&#xff0c;慢指針走一次快慢指針相遇&#xff0c;看是不是等于一 public int bitSum(…