[英]How to check if a object is in Optional<Object> map - Java
pojoMappedByName
包含pojotest
和許多其他元素。 如何檢查pojoTest
是否在pojoMappedByName
?
我嘗試使用if(pojoMappedByName.containsValue(pojotest))
但它返回 false。 是不是因為類型是Optional<PojoClass>
而不是類型PojoClass
PojoClass pojotest = new PojoClass();
PojoClass.setName("Tommy");
Map<String, Optional<PojoClass>> pojoMappedByName;
如果可能,我想避免使用 for 循環
一種可能的解決方案是將其包裝在Optional
如下所示:
assertTrue(pojoMappedByName.containsValue(Optional.of(pojotest)));
Optional 不應該在那里。 Optional 最適合用作終端流操作的返回類型。 將其用作非流相關方法的返回類型有點爭議,但可能可以接受1 。 在其他任何地方使用它都是錯誤的——它不應該是字段的類型,不應該是方法參數的類型,也不應該出現在任何泛型類型中。 List<Optional<String>>
等 - 沒有這些。
你偶然發現了一個實際例子來說明為什么會這樣。 概括原則: Optional 不是泛型的類型系統的一部分,並且相對於您“包裝”的類型是正交的。 換句話說, String
和Optional<String>
與 guns 和 grandmas 一樣不同,這是一個問題,因為在您的腦海中它們感覺很相似。 即使在一個 optional 上調用.equals
本身也是可疑的,因為 Optional 試圖抓住“我傳達特定調用流終端的結果”的語義含義,我們可以就“這個終端結束的方式”甚至可以被視為等於不同的運行,它碰巧產生了相同的對象作為結果。
泛型對任何特定類型有 4 個不同的概念:
List<Number>
List<? extends Number>
List<? super Number>
List
(原始/遺留) 在類型系統中正確集成 optional 需要類似的處理:例如,您希望能夠編寫一個接受List<Optional<String>>
或List<String>
。 如果該方法始終將字符串中的元素視為可選的(例如,檢查 NONE 等),但如果它寫入列表,則只寫入實際的字符串(並且從不 Optional.NONE),則此方法可以處理任一形式.
這類似於List<? super Number>
List<? super Number>
可以調用.add(Number)
,但如果它調用.get(0)
,那是 Object 而不是 Number 類型。
Java 不支持這一點。
沒有辦法寫出這樣的方法。
因此,不要集成 optional - 鑒於您無法編寫該方法,您不希望List<Optional<String>>
在您的代碼庫中的任何位置。 相反,將Optional
視為一種轉瞬即逝的數據類型:如果您從任何地方獲得 Optional,請當場“展開”該可選項。 不要將它存儲在一個字段中,不要將它傳遞給另一個方法。 您應該考慮的唯一稍稍不那么短暫的概念是逐字返回它,將解包該可選項的責任放在您的調用者身上。 這是可以接受的。
如果您想加重這個錯誤並使您的代碼庫更糟,這將起作用。 但我強烈建議不要這樣做!
pojoMappedByName.containsValue(Optional.of(pojotest))
(Optional 的 equals 方法定義為:NONE 等於 NONE,如果a.equals(b)
成立,則任何 2 個 SOME 彼此相等,其中a
和b
是兩個可選項中包含的實際對象,這就是為什么有效。雖然這並不是一個好主意,但它更像是“在所有可用的解釋中,對選項之間的相等性可能意味着什么的最糟糕的選擇”。
[1] java 核心和主要庫中的很多方法都不能那樣工作。 例如,如果您認為Optional<T>
是事實上正確的方法,可以返回一個可以返回“不相關”或“未找到”概念的方法,那么顯然java.util.Map
的.get(key)
方法應該返回一個Optional<V>
。 它不會,也永遠不會,因為它不會是向后兼容的更改。 鑒於有大量代碼因此不能僅僅改變范式並且可能永遠不會改變,這個想法有很多阻力,並且生活在一個任何給定方法在概念上都可以返回“未找到”、“不可用”的世界中' 等 - 然后會強制您首先檢查文檔以查看是否返回T
並且null
表示未找到,或者是否返回Optional<T>
。 對生態系統強加這種二分法自然是有爭議的。 我還沒有聽說過一個可行的建議,即 Optional 已將所有主要庫(和核心庫)中的所有方法返回值替換為 null。 在一個存在之前,它仍然存在爭議,我強烈建議您不要去那里,並避免使用Optional<T>
作為方法的返回值,除非它們與流相關。 然而,一些庫和少數(但重要的少數)編程團隊正在這樣做。 與在List<Optional<T>>
或方法參數類型中使用 Optional 相比:只有極少數開發團隊在這樣做,並且沒有風格指南建議這樣做。
您可以獲取 HashMap 的所有值,使用流過濾操作查看您搜索的 pojo 是否存在,使用 count 查看搜索到的 pojo 的數量,如果為零則不存在,否則在您的 HashMap 中存在多個 pojo,嘗試正確覆蓋 PojoClass 中的 equals 方法。
@Data
@EqualsAndHashCode
class PojoClass {
private String name;
// getter + setter + equals +hashcode : generated by Lombok
}
public class Bounder {
static boolean pojoCounter(Map<String, Optional<PojoClass>> pojoMappedByName, PojoClass pojo) {
long x = pojoMappedByName.values().stream().
filter(e -> e.get().equals(pojo)).count();
if (x == 0) {
return false;
} else
return true;
}
public static void main(String[] args) throws IOException {
PojoClass NotAPojo = new PojoClass();
NotAPojo.setName("NotAPojo");
PojoClass pojotest = new PojoClass();
pojotest.setName("Tommy");
PojoClass pojotest1 = new PojoClass();
pojotest1.setName("Hammy");
PojoClass pojotest2 = new PojoClass();
pojotest2.setName("Mammy");
PojoClass pojotest3 = new PojoClass();
pojotest3.setName("Kammy");
Map<String, Optional<PojoClass>> pojoMappedByName = new HashMap<String, Optional<PojoClass>>();
pojoMappedByName.put("0", Optional.of(pojotest));
pojoMappedByName.put("1", Optional.of(pojotest1));
pojoMappedByName.put("2", Optional.of(pojotest2));
pojoMappedByName.put("3", Optional.of(pojotest3));
System.out.println("pojoMappedByName , pojotest : exists ? " + pojoCounter(pojoMappedByName, pojotest));
System.out.println("pojoMappedByName , pojotest1 exists ? " + pojoCounter(pojoMappedByName, pojotest1));
System.out.println("pojoMappedByName , pojotest2 exists ? " + pojoCounter(pojoMappedByName, pojotest2));
System.out.println("pojoMappedByName , pojotest3 exists ? " + pojoCounter(pojoMappedByName, pojotest3));
System.out.println("pojoMappedByName , NotAPojo exists ? " + pojoCounter(pojoMappedByName, NotAPojo));
}
}
輸出 :
pojoMappedByName , pojotest :存在嗎? 真的
pojoMappedByName , pojotest1 存在嗎? 真的
pojoMappedByName , pojotest2 存在嗎? 真的
pojoMappedByName , pojotest3 存在嗎? 真的
pojoMappedByName , NotAPojo 存在嗎? 錯誤的
您可以覆蓋 hashCode() 和 equals() 方法,並讓 PojoClass 中的 equals 函數具有獨特性,以使您的比較像 id
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof PojoClass))
return false;
PojoClass other = (PojoClass)o;
return this.id == other.id;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.