Использование дженериков Java в интерфейсах, возвращающих коллекции. Лучшая практика? Ловушки? - PullRequest
5 голосов
/ 10 февраля 2010

Сегодня я натолкнулся на какой-то код, который мне показался сомнительным.Вот упрощенный пример (не реалистичный).

public interface IListable {
    //returns first n items from list
    public ArrayList getFirstNThings(int n);

    //returns last n items from list
    public ArrayList getLastNThings(int n);
}

Затем есть такой разработчик:

public GroceryList implements IListable {
    private ArrayList<GroceryItem> groceries;

    public GroceryList() {
        this.groceries = new ArrayList<GroceryItem>();
    }

    public ArrayList<GroceryItem> getFirstNThings(int n) {
        ArrayList<GroceryItem> firstNThings = new ArrayList<GroceryItem>();
        for (int i=0; i < n; i++) {
            firstNThings.add(this.groceries.get(i));
        }
        return firstNThings
     }

     public ArrayList<GroceryItem> getLastNThings(int n) {
         ArrayList<GroceryItem> lastNThings = new ArrayList<GroceryItem>();
         for (int i=this.groceries.size(); i < this.groceries.size()-n; i--) {
           lastNThings.add(this.groceries.get(i-1);
         }
         return lastNThings;
      }
}

Игнорируйте любые проблемы с реализацией, которые вы можете найти в этом (я нашел несколько тоже),Я понял, что интерфейс не использует какой-либо параметр общего типа для ArrayList (т.е. ArrayList), но реализует метод интерфейса (то есть ArrayList ).Другие разработчики могут возвращать ArrayLists с любыми другими параметрами типа, нет?

Итак, мои вопросы: это проблема?Должен ли я что-либо рефакторинг?Стоит ли оно того?В чем преимущество?С какими проблемами я могу столкнуться, если у меня есть метод, определенный в интерфейсе, тип возвращаемого значения которого является необработанным, но фактические разработчики метода возвращают различные параметризованные типы?

Ответы [ 2 ]

5 голосов
/ 10 февраля 2010

, если оба метода IListable всегда возвращают один и тот же тип, используйте вместо этого:

public interface IListable<T> {
  //returns first n items from list
  public ArrayList<T> getFirstNThings(int n);

  //returns last n items from list
  public ArrayList<T> getLastNThings(int n);
}

если это не вариант, попробуйте использовать? вместо. Хотя это в основном то же самое, оно избегает уродливых предупреждений.

public interface IListable {
  //returns first n items from list
  public ArrayList<?> getFirstNThings(int n);

  //returns last n items from list
  public ArrayList<?> getLastNThings(int n);
}

Как правило, не является проблемой использование более конкретного возвращаемого типа в реализации, чем в супертипе или интерфейсе. Если вы имеете дело с IListable, вам нужно обработать любой тип объекта в возвращаемом списке. Если вы имеете дело с GroceryList, вы ожидаете только GroceryItems. Это верно не только для аргументов родового типа возвращаемых типов, но и для самого возвращаемого типа. Так что, если интерфейс указывает List<Foo> get(), можно реализовать его как ArrayList<Foo> get().

0 голосов
/ 01 июня 2017

Рекомендуется никогда не возвращать List<?> с чистым подстановочным знаком в вашем открытом коде, так же как вы не должны возвращать null.

Обобщения подстановочных знаков в Java принесут заражение всем кодировщикам, использующим ваш код. Вы можете сделать это в коде Close для решения локальной проблемы.

Обычно вы избегаете возврата подстановочных знаков ковариации и контравариантности, таких как List<? extends User> и List<? super User>

Вы можете сделать это, если знаете, что делаете, и прочитали все о PECS и ограниченных подстановочных знаках . Не делайте этого только потому, что он компилируется.

...