Должны ли примитивные типы или не примитивные типы быть предпочтительными в интерфейсах Java? - PullRequest
4 голосов
/ 31 марта 2010

(Я думал, что когда-то читал что-то об этом в книге, но теперь я не уверен, где его найти. Если этот вопрос напоминает вам о материале, который вы прочитали, пожалуйста, оставьте ссылку!)

Каковы плюсы и минусы примитивов в интерфейсах?

Другими словами, является ли один из них предпочтительнее другого и почему? Может быть, одно предпочтительнее другого в определенных контекстах?

public interface Foo {
    int getBar();
}

или

public interface Foo {
    Integer getBar();
}

Аналогично:

public interface Boz {
    void someOperation(int parameter);
}

или

public interface Boz {
    void someOperation(Integer parameter);
}

Очевидно, что существует проблема необходимости иметь дело с null s в непримитивном случае, но есть ли более глубокие опасения?

Ответы [ 6 ]

11 голосов
/ 31 марта 2010

Примитивные типы должны использоваться для эффективности и простоты, если нет особых причин использовать тип объекта (например, вам нужно null). Использование типов объектов может привести к различным тонким ошибкам, таким как ошибочное сравнение, если две ссылки относятся к одному и тому же объекту, вместо того, чтобы иметь одинаковое значение. Посмотрите, как собственные библиотеки Java используют примитивные типы, кроме контейнеров, которые принимают Object s.

2 голосов
/ 31 марта 2010

За исключением редких случаев, когда примитивы вызывают проблемы (у меня был некоторый "хороший" опыт работы с CORBA), я бы предложил использовать примитивы.

2 голосов
/ 31 марта 2010

Я бы сказал, что для примитивов обычно мало причин использовать примитивную оболочку в качестве возвращаемого типа. Один аргумент - это просто требования к памяти. С примитивным возвращаемым значением вам нужны только байты X для возвращаемого значения по сравнению с оберткой, где у вас есть служебные данные объекта. Единственное место, где вы можете сохранить это кэшированное значение для таких вещей, как Integer.valueOf (1), но, например, с целым числом, это работает только для значений -128 -> 127.

В то время как lexicore делает правильную точку с использованием нулевого значения в качестве возвращаемого значения в особом случае, во многих случаях вы можете сделать то же самое со значением примитива (например, что-то в API, которое говорит: «Integer.MIN_VALUE возвращается, когда результат не может быть вычислен ". Что во многих случаях является жизнеспособным для всех примитивов, кроме логических.

Также всегда есть опция исключений, так как можно утверждать, что интерфейс всегда должен быть четко определен для всех возможных входов и что вход, который может привести к тому, что возвращаемое значение будет неопределенным, является определением исключительного случая (и как такой, возможно, хороший случай для IllegalArgumentException).

И последнее (гораздо менее простое) решение заключается в добавлении какого-либо метода проверки состояния в интерфейс, который можно протестировать после вызова метода, который может не выполняться должным образом:

boolean b = (interface).doFoo();
if((interface).wasError()){
  //doFoo did not complete normally
}else{
  //do something fooish
}

, где wasError может автоматически очищаться в стиле флага прерывания Thread (обратите внимание, что этот подход будет подвержен ошибкам в многопоточном коде).

1 голос
/ 31 марта 2010

Используйте примитивы. Auto-boxing / -unboxing приведёт ваши int s к Integer s и так далее. Примитивы также размещаются в стеке, а не в куче. Используя классы-обертки, вы используете больше памяти и увеличиваете накладные расходы; зачем тебе это делать?

1 голос
/ 31 марта 2010

Я тоже думаю о таких вещах:

Предположим, что у нас есть этот тип:

public interface Foo {
    int getID();
}

Затем по какой-либо причине вводится тип идентификатора:

public interface Foo {
    FooID getID();
}

Теперь предположим, что какой-то клиент был написан до изменения, а клиент содержит такой код:

if (A.getID() == B.getID()) {
    someBehavior();
}

Где A и B равны Foos.

Этот код будет нарушен после изменения, потому что примитивное сравнение равенства (==) между int s, которое было приемлемо до изменения, теперь неправильно сравнивает ссылочные значения, а не вызывает equals(Object) для идентификаторов .

Если бы getID() произвел Integer с самого начала, правильный код клиента был бы (хорошо, правильный код клиента , возможно, был бы таким. Преобразования бокса были бы применены с == так что это бы тоже сработало):

if (A.getID().equals(B.getID())) {
    someBehavior();
}

Что по-прежнему верно после эволюции программного обеспечения.

Если бы изменение было «обратным», другими словами, если бы getID() первоначально произвёл некоторый тип FooID, то если бы он был изменен для получения int, компилятор жаловался бы на вызов equals(Object) на примитив и код клиента были бы исправлены.

Кажется, что есть чувство "будущего" с не примитивным типом. Согласен? Не согласен?

0 голосов
/ 31 марта 2010

Да, основное использование, которое вы можете видеть, это когда вы переносите объект по сети. ** Использование сериализации. **

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...