2015-02-09 3 views
0

Представьте метод, который принимает объект в качестве параметра и проверяет с помощью a для каждого цикла, чтобы разрешить некоторые другие значения внутри некоторой коллекции, которые можно найти/отфильтровать в соответствии с переданным в аргумент. Хорошо ли проверять в начале функции нулевой указатель и сразу же возвращать пустую коллекцию или нулевой указатель, или лучше просто оставить проверку нулевого указателя, поскольку для каждого цикла это позаботится, но функции потребуется больше времени для выполнения (из-за целого для каждой итерации). И скажем, что эта коллекция невелика (не так много времени).Проверка нулевого указателя Java для более быстрого выполнения кода

public ArrayList<Foo> find(Bar bar) { 
     if (bar == null) { // get rid of these part? 
      return null; // 
     }     // 

     ArrayList<Foo> foos = new ArrayList<Foo>(); 
     for (Foo f: Foo.values()) { 
      if (f.someBarCollection.contains(bar)) { 
       foos.add(f); 
      } 
     } 

     return foos; 
} 

Я думаю, что это лучше, чтобы проверить на нуль и вернуть мгновенную, если вы знаете, что это пустая трата времени делать какие-либо дальнейшие действия, потому что вы знаете, что они не нужны. Поэтому я предпочитаю семантику за счет более короткого кода, чтобы сделать вещи недвусмысленными.

EDIT: Позвольте мне подробнее остановиться. Результат функции совпадает с OR без нулевой контрольной части. Вопрос в том, должен ли я проверить его в любом случае, только ради лучшего выражения (и немного увеличения производительности, но это не проблема), но код будет длиннее (из-за дополнительной проверки)?

+2

1. верните интерфейс не тип реализации 2. используйте ключевое слово assert 3. верните пустую коллекцию, а не null. Вот так: что если коллекция содержит _null_? –

+0

Мы можем предположить, что коллекция не содержит null. – user2340939

+1

Используйте ключевое слово assert, только если для вызывающего пользователя неверно передать значение null. Если для вызывающего есть допустимое значение null, обрабатывайте его так же, как и вы (за исключением возврата пустой коллекции). –

ответ

0

Одна вещь, которую следует учитывать в будущем.

Если вы можете представить себе время, когда собрание законно contains(null), то пусть оно пробежит (и вернет пустую коллекцию) или выбросит исключение (возможно, IllegalArgumentException).Выброс исключения будет означать, что изменение не повлияет на поведение существующего законного кода.

Если вы не считает возвращение null для «пустой», когда bar!=null (обычно не рекомендуется) это немного непоследовательно, чтобы вернуть его к bar==null.

Совершенно верно, большинство других сообщений discourage null для 'empty'. Единственная причина, чтобы использовать это было бы производительность:

//WARNING - THIS CODE IS NOT FIRST CHOICE 
public ArrayList<Foo> find(Bar bar) { 
     ArrayList<Foo> foos = null; 
     for (Foo f: Foo.values()) { 
      if (f.someBarCollection.contains(bar)) { 
       if(foos==null){ 
        foos=new ArrayList<Foo>(); 
       } 
       foos.add(f); 
      } 
     } 
     return foos; 
} 

Collections.emptyList() ценен, но любой код вызова, который думает, что он может изменить список будет получить неприятный сюрприз UnsupportedOperationException. Таким образом, замена null на «пустая» может привести к обмену NullPointerException за (возможно, реже и труднее обнаружить) UnsupportedOperationException. Не так много прогресса, как хотелось бы.

Следующая альтернатива возвращения местного ArrayList пугает:

//DANGER - CODING HORROR! 

static final sEmpty=new ArrayList<Foo>(); 

public ArrayList<Foo> find(Bar bar) { 
     ArrayList<Foo> foos = null; 
     for (Foo f: Foo.values()) { 
      if (f.someBarCollection.contains(bar)) { 
       if(foos==null){ 
        foos=new ArrayList<Foo>(); 
       } 
       foos.add(f); 
      } 
     } 
     return foos==null?sEmpty:foos; 
} 

В этом случае невежественные код может добавлять элементы в якобы пустой ArrayList и заставить их быть возвращены при последующих вызовах find(). Отличный способ провести день - это найти это!

К сожалению, нам кажется, что мы далеки от Java, реализующего стиль C++ const, чтобы дифференцировать изменяемые и неизменные ссылки, чем когда-либо. Так что, по крайней мере, в некоторых случаях вы останетесь с возвращающимися маленькими сумасшедшими объектами или null для 'empty'.

В конце концов, библиотеки Java считают, что создание и уничтожение множества мелких объектов является приемлемым накладным расходами для простоты (посмотрите на примитивы «в штучной упаковке», такие как Integer). Многие современные JVM имеют коллекционные сборщики мусора, предназначенные для гармонизации с этим стилем.

Так что, если вы сомневаетесь, «принимая» null:

public ArrayList<Foo> find(Bar bar) { 
     if(bar==null){ 
      throw new IllegalArgumentException("bar==null"); 
     } 
     ArrayList<Foo> foos = new ArrayList<Foo>(); 
     for (Foo f: Foo.values()) { 
      if (f.someBarCollection.contains(bar)) { 
       foos.add(f); 
      } 
     } 
     return foos; 
} 

В противном случае идти с потоком:

public ArrayList<Foo> find(Bar bar) { 
     ArrayList<Foo> foos = new ArrayList<Foo>(); 
     for (Foo f: Foo.values()) { 
      if (f.someBarCollection.contains(bar)) { 
       foos.add(f); 
      } 
     } 
     return foos; 
} 

рассматривать только варианты, если этот метод является проверенным узкость.

+0

Хорошо, вы сделали отличный момент. Но если вы хотите, чтобы нулевое значение было недопустимым для аргумента функций, и вы решили сделать исключение в этом случае, не станет ли оно нечитаемым, потому что каждая функция, содержащая параметр с нулевым значением, будет содержать код исключения в своей сигнатуре и в начале его тела? Или этот дополнительный код достоин преимуществ, которые вы получаете от него? – user2340939

+1

Это, конечно, нецелесообразно ставить такой код в начале каждого метода. Однако он может выплачивать большие дивиденды в потребительском API. Я хочу сказать, что выброс исключений «зарезервировал» вам возможность расширить функциональность на более поздний срок. Но делать что-то безобидное, как возврат «null», устанавливает поведение, на которое кто-то может полагаться (будь то мудрый или нет). – Persixty

+0

По крайней мере, в ситуациях, где не было бы вреда, если бы был указан недопустимый параметр (null), но возвращаемое значение было бы не нулевым (пустая коллекция), мы можем избавиться от обработки исключений, потому что функция фактически дает осмысленное возвращаемое значение , даже при неизменном параметрическом значении (например, вы хотите получить все дочерние узлы дерева, но если вы укажете null как объект узла дерева, вы получите пустую коллекцию, так как в «null tree node нет детей») , Какова ваша точка зрения на эти ситуации? – user2340939

0

Это зависит от того, как часто (и вообще ли) вы ожидаете, что null будет передан этому методу.

5

Это зависит

В зависимости от вашего API, вы можете сделать следующее, когда параметр получил имеет null значение:

  • сгенерирует исключение. Возможно, IllegalArgumentException или настраиваемое исключение, описывающее причины этого плохого аргумента.
  • Возвращает значение null и позволяет клиенту обрабатывать результат в остальной части кода.
  • Верните пустой результат. В случае List (не ArrayList), вы можете вернуть Collections#emptyList.

Любой вариант, который вы используете для своих API/методов, обязательно задокументируйте его правильно в javadoc.

+0

Если OP хочет выбросить исключение, то он может использовать Guava: ['Preconditions # checkNotNull'] (http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common /base/Preconditions.html#checkNotNull%28T%29). – Tom

+0

@ Тома, которая зависит от реализации. Это зависит от того, используете ли вы Guava в своих проектах (я пока не использую его на моем компьютере). –

+0

коллекция может фактически содержать null? –

1

Уэтер, который вы проверяете или нет, скорее зависит от качества, чем от производительности. Тем не менее, чтобы сделать вещи проще на ваших клиентах, вы должны не возвращение null, но пустая коллекция.

В зависимости от варианта использования вы также можете создать исключение (если nulls не должно быть разрешено) и/или аннотировать аргумент bar с помощью @NonNull, чтобы разрешить использование сменных шашек.

1

Это зависит от ожидаемого значения bar. Если null является допустимым значением для bar, вы принимаете решение. В противном случае лучше исключить исключение.

+0

Да, null допустимо, я просто вернусь раньше, если это так, вот и все! – user2340939

+0

@ user2340939 это также зависит. Это другие критерии: код более понятен, когда он имеет единственную точку возврата, и вы можете легко его достичь, используя 'if (validArguments (arg1, arg2 ...)) {/ * текущая реализация метода * /}// здесь бросают исключение или возвращают все, что вам нужно/нужно'. –

Смежные вопросы