簡體   English   中英

如何檢查對象是否在可選中<Object>地圖 - Java

[英]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 不是泛型的類型系統的一部分,並且相對於您“包裝”的類型是正交的。 換句話說, StringOptional<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 彼此相等,其中ab是兩個可選項中包含的實際對象,這就是為什么有效。雖然這並不是一個好主意,但它更像是“在所有可用的解釋中,對選項之間的相等性可能意味着什么的最糟糕的選擇”。

[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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM