Collections.emptyList () ส่งคืนรายการ <Object> หรือไม่


269

ฉันมีปัญหาในการนำทางกฎของ Java สำหรับอนุมานพารามิเตอร์ประเภททั่วไป พิจารณาคลาสต่อไปนี้ซึ่งมีพารามิเตอร์รายการทางเลือก:

import java.util.Collections;
import java.util.List;

public class Person {
  private String name;
  private List<String> nicknames;

  public Person(String name) {
    this(name,Collections.emptyList());
  }

  public Person(String name,List<String> nicknames) {
    this.name = name;
    this.nicknames = nicknames;
  }
}

คอมไพเลอร์ Java ของฉันมีข้อผิดพลาดดังต่อไปนี้:

Person.java:9: The constructor Person(String, List<Object>) is undefined

แต่Collections.emptyList()ผลตอบแทนที่พิมพ์ไม่ได้<T> List<T> List<Object>การเพิ่มนักแสดงไม่ได้ช่วยอะไร

public Person(String name) {
  this(name,(List<String>)Collections.emptyList());
}

อัตราผลตอบแทน

Person.java:9: inconvertible types

ใช้EMPTY_LISTแทนemptyList()

public Person(String name) {
  this(name,Collections.EMPTY_LIST);
}

อัตราผลตอบแทน

Person.java:9: warning: [unchecked] unchecked conversion

ในขณะที่การเปลี่ยนแปลงต่อไปนี้ทำให้ข้อผิดพลาดหายไป:

public Person(String name) {
  this.name = name;
  this.nicknames = Collections.emptyList();
}

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

สำหรับสินเชื่อพิเศษ: เมื่อมันเหมาะสมที่จะใช้EMPTY_LISTเมื่อเทียบกับemptyList()?


1
สำหรับคำถามที่เกี่ยวข้องกับ Java Generics ฉันขอแนะนำ " Java Generics and Collections " โดย Maurice Naftalin, Philip Wadler
Julien Chastang

คำตอบ:


447

ปัญหาที่คุณกำลังเผชิญหน้าคือแม้ว่าวิธีการที่emptyList()ผลตอบแทนที่คุณไม่ได้ให้มันกับชนิดเพื่อให้เป็นค่าเริ่มต้นกลับมาList<T> List<Object>คุณสามารถระบุพารามิเตอร์ type และให้รหัสทำงานตามที่คาดไว้เช่นนี้

public Person(String name) {
  this(name,Collections.<String>emptyList());
}

ตอนนี้เมื่อคุณทำการกำหนดแบบตรงคอมไพเลอร์สามารถหาพารามิเตอร์ประเภททั่วไปสำหรับคุณได้ มันเรียกว่าการอนุมานประเภท ตัวอย่างเช่นหากคุณทำสิ่งนี้:

public Person(String name) {
  List<String> emptyList = Collections.emptyList();
  this(name, emptyList);
}

แล้วโทรได้อย่างถูกต้องจะส่งกลับemptyList()List<String>


12
เข้าใจแล้ว มาจากโลก ML มันแปลกสำหรับฉันที่ Java ไม่สามารถอนุมานประเภทที่ถูกต้อง: ชนิดของพารามิเตอร์ที่เป็นทางการและประเภทคืนของ emptyList จะไม่สามารถใช้งานได้อย่างชัดเจน แต่ฉันเดาว่าประเภทผู้ด้อยโอกาสทำได้แค่ "ก้าวทารก"
Chris Conway

5
ในบางกรณีอาจเป็นไปได้ว่าคอมไพเลอร์อาจอนุมานพารามิเตอร์ประเภทที่ขาดหายไปในกรณีนี้ แต่สิ่งนี้อาจเป็นอันตรายได้ หากวิธีการหลายรุ่นมีอยู่ด้วยพารามิเตอร์ที่แตกต่างกันคุณอาจท้ายเรียกผิด และคนที่สองอาจจะไม่ได้อยู่เลย ...
บิลมิเชลล์

13
สัญกรณ์นั้น "Collections. <String> emptyList ()" นั้นแปลกมาก แต่ก็สมเหตุสมผล ง่ายกว่า Enum <E ขยาย Enum <E>> :)
Thiago Chaves

12
ไม่จำเป็นต้องระบุพารามิเตอร์ใน Java 8 อีกต่อไป (เว้นแต่จะมีความกำกวมในประเภททั่วไปที่เป็นไปได้)
Vitalii Fedorenko

9
ตัวอย่างที่สองแสดงการอนุมานประเภทได้ดี แต่จะไม่รวบรวมแน่นอน การเรียกไปthisเป็นคำสั่งแรกในตัวสร้าง
Arjan

99

คุณต้องการใช้:

Collections.<String>emptyList();

หากคุณดูที่แหล่งที่มาของรายการที่ว่างคุณเห็นว่ามันเป็นเพียงแค่ทำ

return (List<T>)EMPTY_LIST;

26

เมธอด emptyList มีลายเซ็นนี้:

public static final <T> List<T> emptyList()

ว่า<T>ก่อนที่คำว่ารายการหมายความว่ามันจะอ้างถึงค่าของพารามิเตอร์ T ทั่วไปจากชนิดของตัวแปรผลที่ได้รับมอบหมายให้ ดังนั้นในกรณีนี้:

List<String> stringList = Collections.emptyList();

ค่าส่งคืนจะถูกอ้างอิงอย่างชัดเจนโดยตัวแปรชนิดList<String>ดังนั้นคอมไพเลอร์สามารถคิดได้ ในกรณีนี้:

setList(Collections.emptyList());

Objectไม่มีตัวแปรผลตอบแทนที่ชัดเจนสำหรับรวบรวมเพื่อการใช้งานที่จะคิดออกประเภททั่วไปเพื่อให้เป็นค่าเริ่มต้น

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