จะไม่เพิ่มค่า Null ให้กับ LoadingCache ของ Guava ได้อย่างไร

ฉันต้องใช้ LoadingCache ของ Guava เพื่อแคชนิพจน์ xpath เป็นค่า xpath

ปัญหาคือไม่ใช่ว่า xpath ทั้งหมดจะมีค่า โดยส่วนใหญ่แล้วค่าจะเป็น null

ข้อมูลโค้ด:

private LoadingCache<String, List<String>> cachedXpaths = CacheBuilder.newBuilder()
        .expireAfterWrite(3, TimeUnit.MINUTES)
        .maximumSize(1000)
        .concurrencyLevel(5)
        .weakKeys()
        .build(new CacheLoader<String, List<String>>() {
            @Override
            public List<String> load(String key) throws Exception {
                return createListByKey(key);
            }
        });

private static List<String> createListByKey(String key) throws Exception {
    List<String> values = null;
    try {
        values = instance.getXpathValues(key);
    } catch (XPathExpressionException ignore) {
    }
    return values;
}

ผลลัพธ์:

testEncounterSection(com.epam.cdatest.section.EncountersSectionTest)  Time elapsed: 0.002 sec  <<< FAILURE!
com.google.common.util.concurrent.UncheckedExecutionException: com.epam.cdatest.exceptions.XpathHasEmptyValueException
    at com.epam.cdatest.parsers.XpathEvaluator.getXpathValues(XpathEvaluator.java:123)
    at com.epam.cdatest.parsers.XpathEvaluator.createListByKey(XpathEvaluator.java:53)
    at com.epam.cdatest.parsers.XpathEvaluator.access$000(XpathEvaluator.java:32)
    at com.epam.cdatest.parsers.XpathEvaluator$1.load(XpathEvaluator.java:46)
    at com.epam.cdatest.parsers.XpathEvaluator$1.load(XpathEvaluator.java:43)

จะหลีกเลี่ยงการโทร load() เมื่อค่า xpath ว่างเปล่าได้อย่างไร


person catch23    schedule 16.06.2015    source แหล่งที่มา
comment
เหตุใดคุณจึงต้องการหลีกเลี่ยงการเรียกไปที่ load() แทนที่จะส่งคืนรายการว่าง ที่จริงแล้ว แคชไม่ทราบว่าคีย์ใดไม่ได้รับอนุญาต และจะพยายามโหลดอย่างน้อยหนึ่งครั้ง ตัวโหลดจะต้องตัดสินใจว่าจะทำอย่างไรกับกุญแจ   -  person Thomas    schedule 16.06.2015
comment
@Thomas ข้ามรายการว่างนี้กลับมาได้อย่างไร หรือปรับแต่งแคชเพื่อลบรายการว่างก่อนอย่างไร?   -  person catch23    schedule 16.06.2015
comment
มันไม่ข้ามการเรียก return values แต่หลังจากนั้นแคชจะไม่โหลดค่าสำหรับคีย์นั้นอีกต่อไป และจะส่งกลับรายการว่างนั้นเสมอ ซึ่งบ่งชี้ว่าไม่มีค่า xpath สำหรับคีย์นั้น   -  person Thomas    schedule 16.06.2015
comment
เว้นแต่ว่าคุณจำเป็นต้องแยกความแตกต่างระหว่างสิ่งผิดกฎหมายกับไม่มีอะไรเลยจริงๆ ฉันขอแนะนำให้ส่งคืนรายการว่างในทั้งสองกรณี   -  person maaartinus    schedule 16.06.2015
comment
@maaartinus ฉันสงสัยว่าจะรู้ประสิทธิภาพของแคชนี้หากค่าสำหรับ List‹String› ว่างเปล่า แคชนี้จะลบออกไปไกลกว่าเมื่อเปรียบเทียบกับรายการที่มีค่าบางค่าหรือไม่ คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ไหม?   -  person catch23    schedule 16.06.2015
comment
@nazar_art มันจะจัดการมันในลักษณะเดียวกับค่าอื่น ๆ ซึ่งอาจเป็นสิ่งที่คุณต้องการหรือไม่ก็ได้ แต่ฉันเดาว่านี่เป็นสิ่งที่ถูกต้อง เนื่องจากเส้นทางที่ผิดกฎหมายอาจต้องใช้เวลาดำเนินการเท่ากับเส้นทางที่ถูกกฎหมาย (วัดผลหากคุณใส่ใจจริงๆ)   -  person maaartinus    schedule 16.06.2015


คำตอบ (1)


หากคุณต้องการแยกความแตกต่างระหว่างค่าว่าง List<String> และค่าว่าง เนื่องจาก LoadingCache ไม่รองรับค่าว่าง คุณสามารถใช้ LoadingCache<String, Optional<List<String>>>:

private LoadingCache<String, Optional<List<String>>> cachedXpaths = CacheBuilder.newBuilder()
        .expireAfterWrite(3, TimeUnit.MINUTES)
        .maximumSize(1000)
        .concurrencyLevel(5)
        .weakKeys()
        .build(new CacheLoader<String, Optional<List<String>>>() {
            @Override
            public Optional<List<String>> load(String key) {
                try {
                    // If getXpathValues() can also return null, use fromNullable()
                    return Optional.of(instance.getXpathValues(key));
                } catch (XPathExpressionException | XpathHasEmptyValueException ignore) {
                    // Maybe log something here as well
                    return Optional.absent();
                }
            }
        });

อัปเดต: หากคุณไม่คุ้นเคยกับ Optional มี Javadoc ซึ่งเป็นหน้าใน Wiki รวมถึงเอกสารทั้งหมดสำหรับ Java 8 ซึ่งขณะนี้มีคลาสที่เทียบเท่ากัน

TL; DR เป็น wrapper ที่สามารถทดสอบว่ามีเนื้อหาอยู่หรือไม่:

Optional<List<String>> optionalXpaths = cachedXpaths.getUnchecked(str);
if (optionalXpaths.isPresent()) {
    List<String> xpaths = optionalXpaths.get();
    // Do something with xpaths
}

หรืออีกทางหนึ่ง (แต่มันน่าเกลียดกว่า):

List<String> xpaths = cachedXpaths.getUnchecked(str).orNull();
if (xpaths != null) {
    // Do something with xpaths
}
person Frank Pavageau    schedule 16.06.2015