ฉันจะแก้ไข "นิพจน์ประเภทรายการต้องการการแปลงที่ไม่ได้ตรวจสอบ ... '?


137

ในตัวอย่าง Java:

SyndFeedInput fr = new SyndFeedInput();
SyndFeed sf = fr.build(new XmlReader(myInputStream));
List<SyndEntry> entries = sf.getEntries();

บรรทัดสุดท้ายจะสร้างคำเตือน

"นิพจน์ประเภทListต้องการการแปลงที่ไม่เลือกเพื่อให้เป็นไปตามList<SyndEntry>"

วิธีใดที่เหมาะสมในการแก้ไขปัญหานี้

คำตอบ:


96

เนื่องจากgetEntriesส่งคืนข้อมูลดิบListมันสามารถเก็บอะไรก็ได้

วิธีการที่ปราศจากคำเตือนคือการสร้างใหม่List<SyndEntry>จากนั้นโยนแต่ละองค์ประกอบของsf.getEntries()ผลลัพธ์SyndEntryก่อนที่จะเพิ่มลงในรายการใหม่ของคุณ Collections.checkedListไม่ได้ทำการตรวจสอบนี้สำหรับคุณแม้ว่ามันจะมีความเป็นไปได้ที่จะใช้ให้ทำเช่นนั้น

เมื่อทำการแคสต์ของคุณเองแสดงว่าคุณกำลัง "ปฏิบัติตามเงื่อนไขการรับประกัน" ของ Java generics: หากมีการClassCastExceptionยกค่าขึ้นมันจะเชื่อมโยงกับการแคสต์ในซอร์สโค้ดไม่ใช่การแคสต์ที่มองไม่เห็นที่แทรกโดยคอมไพเลอร์


9
ขอบคุณ - ข้อมูลเชิงลึกที่น่าสนใจเกี่ยวกับ "การรับประกัน" และการแสดงที่มองไม่เห็นซึ่งทำโดยคอมไพเลอร์เทียบกับนักแสดงที่ทำอย่างชัดเจนในรหัสของฉันเอง
user46277

1
ใช่คุณค่าของยาชื่อสามัญที่ไม่ได้ reified นั้นค่อนข้าง จำกัด แต่นั่นเป็นสิ่งหนึ่งที่มีให้ เพื่อชี้แจงสิ่งนี้ต้องการให้โค้ดของคุณรวบรวมโดยไม่มีคำเตือนด้านความปลอดภัยประเภท
erickson

สวัสดี erickson ฉันยอมรับว่านี่เป็นทางออกที่ดีที่สุด ตรวจสอบคำตอบของฉันstackoverflow.com/questions/367626/…สำหรับเวอร์ชันทั่วไปของโซลูชันนี้
Bruno De Fraine

115

นี่เป็นปัญหาทั่วไปเมื่อจัดการกับ Pre-Java 5 APIs ในการแก้ปัญหาโดยอัตโนมัติจาก ericksonคุณสามารถสร้างวิธีการทั่วไปต่อไปนี้:

public static <T> List<T> castList(Class<? extends T> clazz, Collection<?> c) {
    List<T> r = new ArrayList<T>(c.size());
    for(Object o: c)
      r.add(clazz.cast(o));
    return r;
}

สิ่งนี้ช่วยให้คุณทำ:

List<SyndEntry> entries = castList(SyndEntry.class, sf.getEntries());

SuppressWarningsเพราะการตรวจสอบการแก้ปัญหานี้ว่าองค์ประกอบแน่นอนมีชนิดองค์ประกอบที่ถูกต้องโดยใช้วิธีการโยนมันมีความปลอดภัยและไม่จำเป็นต้องมี


5
เกี่ยวกับวิธีการที่แนะนำโดย Bruno สิ่งนี้จะไม่ส่งผลกระทบต่อประสิทธิภาพของแอปพลิเคชันเมื่อมี Lists ที่มีองค์ประกอบมากมายหรือไม่? Java จะต้องร่ายแต่ละอัน
will824

2
หากคุณต้องการค้ำประกันนั่นคือต้นทุน มีตัวเลือกอื่นที่ราคาไม่แพงหรือไม่? เห็นได้ชัดว่าหากคุณสามารถควบคุมวิธีการส่งคืนคอลเลกชันดิบที่เรียกใช้หรือแม้กระทั่งการเรียกใช้เมธอดหรือเข้าถึงคอลเล็กชันโดยใช้วิธีการเรียกเก็บเงินแบบขี้เกียจ สิ่งใดที่พิจารณาคอลเล็กชันทั้งหมดหลังจากการเรียกใช้เมธอด?
และ

28

ดูเหมือนว่าSyndFeedจะไม่ใช้ยาชื่อสามัญ

คุณอาจมีการร่ายที่ไม่ปลอดภัยและการป้องกันคำเตือน:

@SuppressWarnings("unchecked")
List<SyndEntry> entries = (List<SyndEntry>) sf.getEntries();

หรือโทรCollections.checkedList - แม้ว่าคุณจะยังคงต้องระงับคำเตือน:

@SuppressWarnings("unchecked")
List<SyndEntry> entries = Collections.checkedList(sf.getEntries(), SyndEntry.class);

เนื่องจากพวกเขาทั้งสองระงับคำเตือนข้อดีของข้อใดข้อหนึ่งหรือความชอบ? ขอบคุณ! นอกจากนี้: นักแสดงจำเป็นหรือไม่หากมีการปราบปรามที่ไม่ถูกตรวจสอบ
Dan Rosenstark

3
@Yar: Collections.checkedListจะป้องกันการเพิ่มองค์ประกอบที่ไม่ใช่ SyndEntry ในภายหลัง โดยส่วนตัวแล้วฉันไม่ได้ใช้งานcheckedListมากนัก แต่แล้วฉันก็มักจะไม่เข้าสู่สถานการณ์การคัดเลือกนักแสดงที่ไม่ถูกตรวจสอบนี้อยู่ดี ...
Jon Skeet

9

คุณเขียนSyndFeed?

ไม่sf.getEntriesกลับรายการหรือList<SyndEntry>? ฉันเดาว่ามันจะส่งคืนListและเปลี่ยนเป็นส่งคืนList<SyndEntry>จะแก้ไขปัญหาได้

หากSyndFeedเป็นส่วนหนึ่งของไลบรารีฉันไม่คิดว่าคุณสามารถลบคำเตือนได้โดยไม่ต้องเพิ่ม@SuppressWarning("unchecked")คำอธิบายประกอบในวิธีการของคุณ


คุณยังสามารถเพิ่มแคสต์แบบโจ่งแจ้ง
Uri

4
นักแสดงจะสร้างคำเตือนอีกครั้งเนื่องจากรหัสไม่ปลอดภัย
erickson

SyndFeedมาจากrometools.github.io/rome/ROMEReleases/ROME1.0Release.html ดูเหมือนว่าปัญหาจะได้รับการแก้ไขในเวอร์ชันล่าสุดของกรุงโรมเช่นเดียวกับที่พบในmvnrepository.com/artifact/com.rometools/rome/1.9.0
daloonik

2

หากคุณใช้ Guava และสิ่งที่คุณต้องทำคือวนซ้ำตามค่าของคุณ:

for(SyndEntry entry: Iterables.filter(sf.getEntries(), SyndEntry.class){
  ...
}

หากคุณต้องการรายชื่อจริงคุณสามารถใช้ได้

List<SyndEntry> list = Lists.newArrayList(
    Iterables.filter(sf.getEntries(), SyndEntry.class));

หรือ

List<SyndEntry> list = ImmutableList.copyOf(
    Iterables.filter(sf.getEntries(), SyndEntry.class));

1
SyndFeedInput fr = new SyndFeedInput();
SyndFeed sf = fr.build(new XmlReader(myInputStream));
List<?> entries = sf.getEntries();

2
แม้ว่ารหัสที่ให้ไว้ที่นี่จะช่วยแก้ปัญหาได้ แต่ฉันขอแนะนำให้คุณอธิบายสั้น ๆ ว่าทำไมจึงเป็นเช่นนั้น โปรดอธิบายว่าเหตุใดคำตอบที่โพสต์จึงช่วยแก้ปัญหาได้
sbrattla

1

หากคุณดู javadoc สำหรับคลาสSyndFeed(ฉันเดาว่าคุณกำลังอ้างถึงคลาสcom.sun.syndication.feed.synd.SyndFeed) เมธอด getEntries () จะไม่ส่งคืนjava.util.List<SyndEntry>แต่จะส่งกลับเพียงjava.util.Listแต่ผลตอบแทนเพียง

ดังนั้นคุณต้องมีนักแสดงที่ชัดเจนสำหรับสิ่งนี้



0

ง่ายยิ่งขึ้น

return new ArrayList<?>(getResultOfHibernateCallback(...))


จากนั้นคุณจะจัดการกับการหล่อที่เหมาะสม (การหล่อซ้ำ?) ในเวลาใช้งานสำหรับแต่ละองค์ประกอบใน ArrayList <?>
นี่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.