淺談對Java雙冒號::的理解
本文為個人理解,不保證完全正確。
官方文檔中將雙冒號的用法分為4類,按照我的個人理解可以分成2類來使用。
官方文檔
官方文檔中將雙冒號的用法分為了以下4類:
用法 | 舉例 |
---|---|
引用靜態(tài)方法 | ContainingClass::staticMethodName |
引用特定對象的實例方法 | containingObject::instanceMethodName |
引用特定類型的任意對象的實例方法 | ContainingType::methodName |
引用構(gòu)造函數(shù) | ClassName::new |
以下是我的理解
個人理解
雙冒號的作用
在使用雙冒號前我們要先搞清楚一個問題:為什么要使用雙冒號?也就是雙冒號的作用是什么。
雙冒號的設(shè)計初衷是為了化簡Lambda表達(dá)式,不熟悉Lambda表達(dá)式的同學(xué)可以先了解一下。
Lambda表達(dá)式的形式有兩種:
包含單獨(dú)表達(dá)式 :parameters -> an expression
list.forEach(item -> System.out.println(item));
包含代碼塊:parameters -> { expressions }
list.forEach(item -> { int numA = item.getNumA(); int numB = item.getNumB(); System.out.println(numA + numB); });
使用雙冒號可以省略第一種Lambda表達(dá)式中的參數(shù)部分,即item ->和調(diào)用方法的參數(shù)這兩部分。
例如:
//不使用雙冒號 list.forEach(item -> System.out.println(item)); //使用雙冒號 list.forEach(System.out::println);
雙冒號的使用條件
使用雙冒號有兩個條件:
條件1
條件1為必要條件,必須要滿足這個條件才能使用雙冒號。
Lambda表達(dá)式內(nèi)部只有一條表達(dá)式(第一種Lambda表達(dá)式),并且這個表達(dá)式只是調(diào)用已經(jīng)存在的方法,不做其他的操作。
條件2
由于雙冒號是為了省略item ->這一部分,所以條件2是需要滿足不需要寫參數(shù)item也知道如何使用item的情況。
有兩種情況可以滿足這個要求,這就是我將雙冒號的使用分為2類的依據(jù)。
情況 | 舉例 |
---|---|
Lambda表達(dá)式的參數(shù)與調(diào)用函數(shù)的參數(shù)完全一致 | list.forEach(item -> System.out.println(item)) |
調(diào)用的函數(shù)是參數(shù)item對象的方法且沒有參數(shù) | list.stream().map(item -> item.getId()) |
一些栗子
Lambda表達(dá)式的參數(shù)與調(diào)用函數(shù)的參數(shù)完全一致時
靜態(tài)方法調(diào)用
//化簡前 list.forEach(item -> System.out.println(item)); //化簡后 list.forEach(System.out::println);
非靜態(tài)方法調(diào)用
StringBuilder stringBuilder = new StringBuilder(); //化簡前 IntStream.range(1, 101).forEach(item -> stringBuilder.append(item)); //化簡后 IntStream.range(1, 101).forEach(stringBuilder::append);
調(diào)用構(gòu)造方法
官方給出的例子
先定義一個方法,這個方法的作用是將一個集合的內(nèi)容復(fù)制到另一個集合
public <T, SOURCE extends Collection<T>, DEST extends Collection<T>> DEST transferElements(SOURCE sourceCollection, Supplier<DEST> collectionFactory) { DEST result = collectionFactory.get(); result.addAll(sourceCollection); return result; }
調(diào)用這個方法
//化簡前 Set<Person> rosterSetLambda = transferElements(roster, () -> new HashSet<>()); //化簡后 Set<Person> rosterSet = transferElements(roster, HashSet::new);
稍微解釋一下:
調(diào)用時傳入的Lambda表達(dá)式相當(dāng)于是對Supplier的繼承,并重寫Supplier的get()方法,下面是Supplier的源碼:
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
在transferElements()方法中調(diào)用collectionFactory.get()時相當(dāng)于調(diào)用重寫后的方法{return new HashSet<>();}
我自己寫的一個例子
第一個類:
@Data public class ModelA { private String id; public ModelA(String id) { this.id = id; } public ModelA() { } }
第二個類
class ClassB { private final List<ModelA> list = new ArrayList<>(); public void add(String string, Function<String, ModelA> function) { list.add(function.apply(string)); } }
測試代碼
ClassB classB = new ClassB();d //化簡前 classB.add("ddd", item -> new ModelA(item)); //化簡后 classB.add("ddd", ModelA::new);
調(diào)用的函數(shù)是參數(shù)item對象的方法且沒有參數(shù)時
//化簡前 List<String> stringList = list.stream().map(item -> item.getId()).collect(Collectors.toList()); //化簡后 List<String> stringList = list.stream().map(ModelA::getId).collect(Collectors.toList());
一種特殊情況
除了上述兩種情況可以使用雙冒號化簡Lambda表達(dá)式外,還存在一種特殊情況也可以使用雙冒號。
當(dāng)Lambda表達(dá)式的參數(shù)有兩個(形如(a,b) -> an expression)時,調(diào)用a的方法參數(shù)為b時,例如:
String[] stringArray = {"Barbara", "James", "Mary", "John"}; //化簡前 Arrays.sort(stringArray, (a,b) -> a.compareToIgnoreCase(b)); //化簡后 Arrays.sort(stringArray, String::compareToIgnoreCase);
到此這篇關(guān)于淺談對Java雙冒號::的理解的文章就介紹到這了,更多相關(guān)Java雙冒號::內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
編譯大型Java項目class沖突導(dǎo)致報錯的解決方案
這篇文章給大家盤點(diǎn)編譯大型項目class沖突導(dǎo)致報錯的解決方案,文中通過代碼示例介紹的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下2023-10-10JDBC中PreparedStatement詳解以及應(yīng)用場景實例介紹
PreparedStatement對象代表的是一個預(yù)編譯的SQL語句,用它提供的setter方法可以傳入查詢的變量,這篇文章主要給大家介紹了關(guān)于JDBC中PreparedStatement詳解以及應(yīng)用場景實例介紹的相關(guān)資料,需要的朋友可以參考下2024-02-02Java實現(xiàn)用位運(yùn)算維護(hù)狀態(tài)碼
位運(yùn)算是一種非常高效的運(yùn)算方式,在算法考察中比較常見,那么業(yè)務(wù)代碼中我們?nèi)绾问褂梦贿\(yùn)算呢,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧2024-03-03springboot集成Swagger的方法(讓你擁有屬于自己的api管理器)
在大型的項目中,如果你有非常多的接口需要統(tǒng)一管理,或者需要進(jìn)行接口測試,那么我們通常會在繁雜地api中找到需要進(jìn)行測試或者管理的接口,接下來通過本文給大家介紹springboot集成Swagger的方法讓你擁有屬于自己的api管理器,感興趣的朋友一起看看吧2021-11-11簡介Java的Hibernate框架中的Session和持久化類
這篇文章主要介紹了Java的Hibernate框架中的Session和持久化類,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12springboot優(yōu)雅獲取前端參數(shù)的方法詳解
現(xiàn)在的項目基本上都是前后端分離的項目,如何打通前后端,接收前端傳過來的參數(shù)呢,這篇文章小編就來和大家詳細(xì)介紹一下springboot如何優(yōu)雅的獲取前端參數(shù)吧2024-03-03Java中計算集合中元素的出現(xiàn)次數(shù)統(tǒng)計
本文主要介紹了Java中計算集合中元素的出現(xiàn)次數(shù)統(tǒng)計,使用Collections類配合HashMap來統(tǒng)計和java lamb 計算這兩種方式,具有一定的參考價值,感興趣可以了解一下2024-02-02