Подтвердить что ты не робот

Передача значения null методу

Я посреди чтения отличного Clean Code

Одно обсуждение касается передачи нулей в метод.

public class MetricsCalculator {
    public double xProjection(Point p1, Point p2) {
        return (p2.x - p1.x) * 1.5;
    }
}
...
calculator.xProjection(null, new Point(12,13));

Он представляет различные способы обработки этого:

public double xProjection(Point p1, Point p2) {
    if (p1 == null || p2 == null) {
        throw new IllegalArgumentException("Invalid argument for xProjection");
    }
    return (p2.x - p1.x) * 1.5;
}

public double xProjection(Point p1, Point p2) {
    assert p1 != null : "p1 should not be null";
    assert p2 != null : "p2 should not be null";
    return (p2.x - p1.x) * 1.5;
}

Я предпочитаю подход утверждения, но мне не нравится тот факт, что утверждения по умолчанию отключены.

В книге, наконец, говорится:

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

На самом деле не идет речь о том, как вы будете применять это ограничение?

У любого из вас есть сильные мнения в любом случае.

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

Общее правило: если ваш метод не ожидает аргументов null, тогда вы должны бросить System.ArgumentNullException. Правильное отбрасывание Exception не только защищает вас от повреждения ресурсов и других плохих вещей, но и служит руководством для пользователей вашего кода, экономя время, затрачиваемое на отладку вашего кода.

Также прочитайте статью о Оборонительное программирование

Ответ 3

Также не для немедленного использования, но связано с упоминанием SpeС#... Есть предложение добавить "нуль-безопасные типы" в будущую версию Java: "Усовершенствованная обработка нулей - Нулевые типы" .

В соответствии с предложением ваш метод станет

public class MetricsCalculator {
    public double xProjection(#Point p1, #Point p2) {
        return (p2.x - p1.x) * 1.5;
    }
}

где #Point - это тип ссылок < <22 > для объектов типа Point.

Ответ 4

На самом деле не идет речь о том, как вы будете применять это ограничение?

Вы применяете его, бросая ArgumentExcexception, если они передают нулевое значение.

if (p1 == null || p2 == null) {
    throw new IllegalArgumentException("Invalid argument for xProjection");
}

Ответ 5

Я предпочитаю использование утверждений.

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

Ответ 6

SpeС# выглядит очень интересно!

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

/**
 * Checks to see if an object is null, and if so 
 * generates an IllegalArgumentException with a fitting message.
 * 
 * @param o The object to check against null.
 * @param name The name of the object, used to format the exception message
 *
 * @throws IllegalArgumentException if o is null.
 */
public static void checkNull(Object o, String name) 
    throws IllegalArgumentException {
   if (null == o)
      throw new IllegalArgumentException(name + " must not be null");
}

public static void checkNull(Object o) throws IllegalArgumentException {
   checkNull(o, "object");
} 

// untested:
public static void checkNull(Object... os) throws IllegalArgumentException {
   for(Object o in os) checkNull(o);  
}

Затем проверка переходит в:

public void someFun(String val1, String val2) throws IllegalArgumentException {
   ExceptionUtilities.checkNull(val1, "val1");
   ExceptionUtilities.checkNull(val2, "val2");

   /** alternatively:
   ExceptionUtilities.checkNull(val1, val2);
   **/

   /** ... **/
} 

Это может быть добавлено с помощью макросов редактора или обработки кода script. Изменить: Также может быть добавлена ​​подробная проверка этого способа, но я думаю, что значительно упростить автоматизацию добавления одной строки.

Ответ 7

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

Я нашел JetBrains '@Nullable и @NotNull подход аннотаций, чтобы разобраться с этим самым изобретательным, до сих пор. Это IDE конкретный, к сожалению, но действительно чистый и мощный, IMO.

http://www.jetbrains.com/idea/documentation/howto.html

Наличие этого (или чего-то подобного) в качестве стандарта java было бы действительно приятным.

Ответ 8

Я вообще предпочитаю не делать этого, потому что это просто замедляет работу. В любом случае NullPointerExceptions выдаются позже, что быстро приведет пользователя к обнаружению того, что они передают значение null методу. Раньше я проверял, но 40% моего кода оказалось проверкой кода, и в этот момент я решил, что это просто не стоит приятных сообщений об утверждении.

Ответ 9

Я согласен или не согласен с сообщением wvdschel, это зависит от того, что он конкретно говорит.

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

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

Ответ 10

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

@wvdschel ничего себе! Если писать код слишком много для вас, вы должны изучить что-то вроде PostSharp (или эквивалент Java, если он доступен) который может выполнять пост-обработку ваших сборок и вставлять проверочные параметры для вас.

Ответ 11

Хотя это не связано строго, вы можете взглянуть на SpeС#.

Я думаю, что он все еще находится в разработке (Microsoft), но некоторые CTP доступны, и это выглядит многообещающим. В основном это позволяет вам сделать это:

  public static int Divide(int x, int y)
    requires y != 0 otherwise ArgumentException; 
  {
  }

или

  public static int Subtract(int x, int y)
    requires x > y;
    ensures result > y;
  {
    return x - y;
  } 

Он также предоставляет другие функции, такие как типы Notnull. Он построен поверх .NET Framework 2.0 и полностью совместим с ним. Синтаксис, как вы можете видеть, это С#.

Ответ 12

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

Используя статический анализ вашего кода, findbugs могут затем указать места, где метод вызывается с потенциально нулевым значением.

Это имеет два преимущества:

  1. Аннотация описывает ваше намерение о том, как метод должен быть вызван, сопровождая документацию
  2. FindBugs может указывать на потенциальных проблем метода, позволяя вам отслеживать потенциальные ошибки.

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

Ответ 13

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

//  allocate null
var name : Option[String]
name = None

//  allocate a value
name = Any["Hello"]

//  print the value if we can
name match {
  Any[x] => print x
  _ => print "Nothing at all"
}

Ответ 14

Throwing С# ArgumentException или Java IllegalArgumentException прямо в начале метода выглядит для меня самым ясным решением.

Всегда следует быть осторожным с исключениями времени выполнения - исключения, которые не объявлены в сигнатуре метода. Поскольку компилятор не принуждает вас их поймать, очень легко забыть о них. Удостоверьтесь, что у вас есть какая-то "обработка всех исключений" для предотвращения внезапного прекращения работы программного обеспечения. Это самая важная часть вашего пользовательского опыта.

Ответ 15

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

Ответ 16

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

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