попробовать / поймать против проверки на ноль в Java

java

20867 просмотра

10 ответа

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

public void printIt(Object1 a){
  if (a!=null){
     SubObject b= a.getB();
     if (b!=null){
         SubObject2 c=b.getC();
         if(c!=null){
             c.print();
         }
     }
  }
}

когда мне не нужно знать, что не удалось, и если что-то пустое, ничего не делать, подход может быть

public void printIt(Object1 a){
    try{
      a.getB().getC().print();
    }catch (NullPointerException e) {
    }
}

Что-то не так во второй форме, например, производительность или другие проблемы?

Автор: Addev Источник Размещён: 13.11.2019 11:31

Ответы (10)


21 плюса

Решение

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

Точно так же глубоко вложенные ifутверждения приводят к сложному для чтения коду, и под всем этим существует то же самое «нарушение», и цикломатическая сложность таких методов высока.

public void printIt(Object1 a) {
    if (null == a) {
        return;
    }

    SubObject b = a.getB();
    if (null == b) {
        return;
    }

    SubObject2 c = b.getC();
    if (null == c) {
        return;
    }

    c.print();
}

Я бы предпочел видеть LAM (Маленькие Вспомогательные Методы) в соответствующих местах, которые инкапсулируют проверки и в значительной степени устраняют необходимость в вопросе в целом.

Автор: Dave Newton Размещён: 18.03.2012 01:04

11 плюса

Да. Вторая версия будет иметь ужасную производительность.

Не используйте исключения для нормального потока управления. Действующий элемент Java 57: используйте исключения только для исключительных ситуаций.

== UPDATE ==

Даже без учета проблем производительности (исключения быстрее , чем они были когда - то, в соответствии с моим эталоном , но не так быстро , как простая , если чек), это действительно код-вонючие исключениями для использования стандартного потока программы , как это. Байт-код JVM имеет специальные оптимизации, которые он может выполнять для нулевых проверок, даже в ifвыражениях. Первый пример кода чрезвычайно предпочтителен.

Автор: Louis Wasserman Размещён: 18.03.2012 12:56

8 плюса

public void printIt(Object1 a){
    if(a==null){
        throw new IllegalArgumentException("a was null, but this is not allowed here."),
    }
    [...]

Быстро терпеть неудачу и терпеть неудачу сильно. Если шоуд не будет нулевым, бросьте исключение. Это сделает ваш код более стабильным и надежным.

Поэтому, если бы мне пришлось выбирать между вашим а) и вашим б), я бы выбрал а). Но если a не должно быть нулевым, вы могли бы скрыть ошибку.

Автор: Christian Kuetbach Размещён: 18.03.2012 01:02

7 плюса

Самая плохая часть второй версии заключается в том, что когда NPE происходит внутри getB(), getC()он будет игнорироваться. Как уже упоминалось, исключения для исключительных случаев.

Автор: khachik Размещён: 18.03.2012 01:00

2 плюса

Использование исключений - это всегда плохая идея с точки зрения производительности, независимо от того, насколько медленным был механизм, который был и есть сейчас. Всякий раз, когда генерируется исключение, полный стек будет развернут для создания трассировки стека. Таким образом, как сказала Лоис Вассерман, вы не должны полагаться на них для (регулярного) выполнения программы, а в исключительных случаях.

Вложенные if не являются определением красоты, но дадут вам возможность напечатать дополнительную информацию, такую ​​как «B is null» и т. Д.

Автор: sunside Размещён: 18.03.2012 01:01

2 плюса

Ответ - использовать версию А.

Обычно считается «плохой дизайн», чтобы использовать исключения для управления потоком. Исключения для «исключительных», особенно NPE, которых можно полностью избежать, используя нулевые проверки. Кроме того, используя нулевые проверки, вы можете указать (то есть журнал), какой термин является нулевым (вы не будете знать, где находится нулевое значение в вашей версии B).

Обратите внимание, что производительность больше не является проблемой, вызывая исключения (например, трассировка стека создается только при ее использовании). Это вопрос чистого кода.

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

Автор: Bohemian Размещён: 18.03.2012 01:02

2 плюса

Определенно (а), но вы должны реструктурировать метод, чтобы избежать вложения операторов if, как упоминалось в предыдущем ответе. Исключения не являются падением производительности, которым они были когда-то, но они все еще намного медленнее, чем проверка на ноль, и никогда не должны использоваться для управления потоком программ, подобным этому. Если объект может быть нулевым, вы должны проверить его, но если это не разрешено, вы должны быстро потерпеть неудачу в тот момент, когда вы назначаете ссылку на объект. Во многих случаях у вас могут быть реализации по умолчанию (пустой список - хороший пример), чтобы полностью избежать нулевых значений, что приводит к гораздо более чистому коду. Избегайте нулей, когда вы можете.

Автор: nicktalbot Размещён: 18.03.2012 02:39

1 плюс

Код никогда не должен включать обработчики исключений для непроверенных исключений. Проверка нуля всегда должна использоваться для ссылки на объект, которая может быть нулевой.

Автор: Noroi Размещён: 18.03.2012 02:13

0 плюса

Если вы переходите на Java 8, вы можете использовать Optional и Lambdas. Во-первых, вам нужно переписать ваши классы для возврата Optionalкаждого типа:

class Object1 {
    private SubObject b;

    Optional<SubObject> getB() {
        return Optional.ofNullable(b);
    }
}

class SubObject {
    private SubObject2 c;

    Optional<SubObject2> getC() {
        return Optional.ofNullable(c);
    }
}

class SubObject2 {
    @Override
    public String toString() {
        return "to be printed";
    }
}

Теперь вы можете сжать вызовы без риска исключений NullPointerException в сжатой форме:

a.getB()
    .flatMap(SubObject::getC)
    .ifPresent(System.out::println);

Смотрите статью Oracle Устали от исключений нулевого указателя? Подумайте об использовании Java SE 8 необязательно! для дополнительной информации.

Автор: matsev Размещён: 14.01.2015 10:26

0 плюса

Использование Java 8 необязательно:

Optional.ofNullable(a)
            .map(Object1::getB)
            .map(SubObject::getC)
            .ifPresent(Object2::print);
Автор: seenimurugan Размещён: 08.11.2017 04:45
Вопросы из категории :
32x32