Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用通配符作为类型对空列表作出反应?_Java_List_Wildcard - Fatal编程技术网

Java 如何使用通配符作为类型对空列表作出反应?

Java 如何使用通配符作为类型对空列表作出反应?,java,list,wildcard,Java,List,Wildcard,我想在类中使用通配符作为类型设置列表: public List<?> setList(List<?> list){ this.list = list; } 公共列表集合列表(列表列表){ this.list=列表; } 但我只接受某些类型的列表元素。该示例仅包含字符串方法,但我将接受字符串、双精度或整数f.e 我知道这种方法: public void setList(List<?> list){ if(!list.isEmpty

我想在类中使用通配符作为类型设置列表:

 public List<?> setList(List<?> list){
      this.list = list;
 }
公共列表集合列表(列表列表){
this.list=列表;
}
但我只接受某些类型的列表元素。该示例仅包含字符串方法,但我将接受字符串、双精度或整数f.e

我知道这种方法:

 public void setList(List<?> list){
     if(!list.isEmpty())
         if(list.get(0).getClass().equals(String.class))
              this.list = list;
         else
              throw new IllegalArgumentException();
     else 
         // what to do?
 }
公共作废设置列表(列表){
如果(!list.isEmpty())
if(list.get(0.getClass().equals(String.class))
this.list=列表;
其他的
抛出新的IllegalArgumentException();
其他的
//怎么办?
}
如果列表不是空的,我可以检查第一个元素类。如果是String.class,我将设置列表,否则将引发异常

但是如果列表是空的,我该如何反应呢?因为类型擦除,我无法检查通配符的类型。所以,我不能实例化一个空列表


我应该只做
this.list=null?或者我应该只接受not empty列表并在其为空时抛出异常吗?我很感激你的建议。因为这段代码将被重用,使用它的人应该知道会发生什么。

我这里有三种方法:

  • 简单通用方法
您必须参数化保存列表的类。通过创建具有指定泛型类型的新实例。这将是一种类型安全的方法

public class ListHolder<T> {

    private List<T> list;

    public void setList(List<T> list) {
        this.list = list;
    }
    public static void main(String[] args) {
        ListHolder<String> sl = new ListHolder<String>();
        sl.setList(new ArrayList<String>());

        ListHolder<Double> dl = new ListHolder<Double>();
        dl.setList(new ArrayList<Double>());
    }
}
公共类列表持有者{
私人名单;
公共无效集合列表(列表){
this.list=列表;
}
公共静态void main(字符串[]args){
ListHolder sl=新的ListHolder();
sl.setList(新的ArrayList());
ListHolder dl=新的ListHolder();
dl.setList(新的ArrayList());
}
}
  • 基于动态权限的方法
在这里,我们用允许的类填充一个集合

public class ListHolder {
    private Set<Class<?>> allowed = new HashSet<Class<?>>();
    private List<?> list;

    public <T> void setList(List<T> list) {
        if (list.isEmpty()) {
            // problem is we can't check type here. Exception would be better
            list = Collections.<T> emptyList();
        } else {
            Class<?> clazz = list.get(0).getClass();
            if (allowed.contains(clazz)) {
                this.list = list;
            } else {
                throw new IllegalArgumentException("Type "
                        + clazz.getSimpleName() + " not allowed!");
            }
        }
    }

    public void allowClass(Class<?> clazz) {
        allowed.add(clazz);
    }
}
公共类列表持有者{
私有集>();
私人名单;
公共无效集合列表(列表){
if(list.isEmpty()){
//问题是我们不能在这里检查类型。例外情况会更好
list=Collections.emptyList();
}否则{
Class clazz=list.get(0.getClass();
如果(允许,包含(clazz)){
this.list=列表;
}否则{
抛出新的IllegalArgumentException(“类型”
+clazz.getSimpleName()+“不允许!”;
}
}
}
公共无效允许类(类clazz){
允许。添加(clazz);
}
}
  • 基于任务的静态方法
这里的检查在编译时进行

public class ListHolder {

    private List<?> list;

    public static final Allowed<String> STRING = new Allowed<String>();
    public static final Allowed<Double> DOUBLE = new Allowed<Double>();

    public <T> void setList(List<T> list, Allowed<T> permission) {
        if (permission == null)
            throw new NullPointerException("Permission is null!");
        this.list = list;
        if (list == null) // if you don't want list to be null
            this.list = Collections.<T>emptyList(); // added type parameter to make it clearer for reader
        // ...compiler does that implicitly
    }

    private static class Allowed<T> {
    }

    public static void main(String[] args) {
        ListHolder l = new ListHolder();

        List<String> strings = new ArrayList<String>();
        List<Double> doubles = new ArrayList<Double>();
        List<Integer> integers = new ArrayList<Integer>();

        l.setList(strings, ListHolder.STRING);
        l.setList(doubles, ListHolder.DOUBLE);
        //l.setList(integers, ListHolder.DOUBLE); Does not even compile
    }
}
公共类列表持有者{
私人名单;
public static final Allowed STRING=new Allowed();
公共静态最终允许双精度=新允许();
公共无效集合列表(列表列表,允许的权限){
if(权限==null)
抛出新的NullPointerException(“权限为null!”);
this.list=列表;
if(list==null)//如果不希望list为null
this.list=Collections.emptyList();//添加了类型参数,以便读者更清楚地了解它
//…编译器隐式地执行此操作
}
允许使用私有静态类{
}
公共静态void main(字符串[]args){
ListHolder l=新的ListHolder();
列表字符串=新的ArrayList();
List double=new ArrayList();
列表整数=新的ArrayList();
l、 setList(strings,ListHolder.STRING);
l、 setList(双倍,ListHolder.DOUBLE);
//l、 setList(整数,ListHolder.DOUBLE);甚至不编译
}
}

直接回答您的问题:空列表没有问题

由于类型擦除,在运行时列表、列表或简单列表之间没有区别

您甚至可以愚弄编译器并执行以下操作

List<String> stringList = new ArrayList<String>();
stringList.add("foo");
List rawList = stringList;
rawList.add(42);
List<Integer> integerList = rawList;

确实,在运行时你必须复制列表,因为你的函数得到了列表作为参考,它的内容以后可以在你的函数之外修改。

为什么不使用
对象作为类型而不是通配符?@Bart好吧,这将导致列表可以一次包含所有可能的类型。好的!如果我的一些想法不清楚,就问吧。我没有写太多,但我试图让代码自己说话。因为动态方法与我的代码完全相同,如果列表为空,我应该抛出哪个异常?因为在我看来,这是我要走的路。这让我想到,如果我的方法大体上是正确的,那么使用动态方法,你不能设置任何类型的空列表。第一种方法的缺点是必须为每种类型创建一个新实例。我更喜欢最后一个。需要处理类的人在编译时会知道,如果他使用了不兼容的类型,他也不必在运行时捕获任何异常(…空值没什么大不了的)。是的,这个方法更冗长。但是你可以用一个helper方法隐藏内部,例如,
setStringList(List List){setList(List,ListHolder.STRING);}
我知道没有空列表可以实例化,这就是为什么我想抛出一个异常,但是是哪一个?是的,但是你可以用后一种方法允许空列表,并且不会抛出异常。NPE很明显,如果您使用
setList(anylist,null)
调用该方法,就会抛出NPE。但是如果您想坚持您的方法/动态方法,我想在这种情况下,
IllegalArgumentException
将是合适的,但是您必须在java文档中仔细记录它。当然,还需要编写更多的测试用例,因为这种方法是动态的,在运行时会出现故障……这里的信息很好!谢谢你。明天我会仔细看看这个。
public <T> void setList(List<T> list, Class<T> clazz) {
    for (T t : list) {
        if(!clazz.equals(t.getClass())) {
            throw new YourPreferedKindOfException();
        }
    }
    this.list = list;
}
setList(stringList, String.class);