Java assertions or exceptions

Assert vs Exceptions [closed]

Want to improve this question? Update the question so it focuses on one problem only by editing this post.

I have read about when to use assert and when to use an exception. Assertions are intended to be used as a means of detecting programming errors, aka bugs. Some say assert is for debugging purposes only and its trigger condition should not happen. By contrast, an exception can indicate other kinds of error or «exceptional» condition: invalid user input, missing files, heap full, etc. From my understanding, exceptions can do everything asserts can do except they cannot be disabled. If all asserts were replaced by exceptions, it would be functionally the same. So, is the ability to disable asserts the only reason why they should be used or are there other reasons? Thanks.

Think of an assertion as «check & possibly an exception» vs a simple «exception». So it’s a short-cut that for that logic, as well as a clear declaration (self-documenting code) that an specific condition is being «asserted to be true».

7 Answers 7

Asserts are used by test cases to make sure that what you built doesn’t, in the future, render something unexpected. You can assert to make sure exceptions are thrown upon false input, for instance.

Many times in programming changing one thing means you have to change other pieces of your code. Assertations make sure that what you change doesn’t break code you’ve written in the past.

Читайте также:  Python printing list elements

Exceptions are good. They are expected and handled via exceptions. You have exceptions for incorrect login and password, for instance.

You can assert that upon an incorrect login or password, the expected exception is raised.

An assert contains three main things. What you’re testing (function name for instance, i.e. sign_in ), what goes in (function parameters i.e. ), and what comes out ( assertTrue(‘user_name’ in response, ‘Expecting user_name to be in response!’) ).

Exceptions are normal, logical alternatives in code. Asserts are tests to make sure logical paths are followed when they should be.

According to the python unittest framework, you can assert that exceptions are thrown:

import random import unittest class TestSequenceFunctions(unittest.TestCase): def setUp(self): self.seq = range(10) def test_shuffle(self): # make sure the shuffled sequence does not lose any elements random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, range(10)) # should raise an exception for an immutable sequence self.assertRaises(TypeError, random.shuffle, (1,2,3)) def test_choice(self): element = random.choice(self.seq) self.assertTrue(element in self.seq) def test_sample(self): with self.assertRaises(ValueError): random.sample(self.seq, 20) for element in random.sample(self.seq, 5): self.assertTrue(element in self.seq) if __name__ == '__main__': unittest.main() 

Источник

Как использовать assertions в Java

Как использовать утверждения в Java

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

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

Загрузите исходный код примеров для этой статьи. Создано Джеффом Фризеном для JavaWorld.

Что такое ассерты в Java?

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

В JDK 1.4 ассерты были введены как новый механизм для тестирования и отладки кода. По сути, ассерты — это компилируемые сущности, которые выполняются в runtime, если вы включили их для тестирования программы. Вы можете запрограммировать ассерты так, чтобы они уведомляли вас об ошибках ещё до того как они произошли и программа “упала”, что значительно сокращает время на отладку неисправной программы.

Ассерты используются для определения требований, исполнение которых делают программу правильной. И делается это при помощи проверки условий (логических выражений) на true. Если же выражение выдаёт false, разработчик получает уведомление об этом. Использование утверждений может значительно повысить вашу уверенность в правильности кода.

Как написать ассерт на Java

Ассерты реализуются с помощью оператора assert и класса java.lang.AssertionError. Этот оператор начинается с ключевого слова assert и продолжается логическим выражением. Синтаксически это выражается следующим образом:

Если значение BooleanExpr истинно, ничего не происходит и выполнение продолжается. Однако, если выражение оценивается как ложное, бросается AssertionError, как, например, в этом коде:

Листинг 1: AssertDemo.java (версия 1)

public class AssertDemo < public static void main(String[] args) < int x = -1; assert x >= 0; > >

ассерт здесь говорит о том, что по мнению разработчика переменная x должна быть больше или равна 0. Однако это явно не так; выполнение оператора assert приводит к выбросу AssertionError.

Скомпилируйте этот код (javac AssertDemo.java) и запустите его с включенными ассертами (java -ea AssertDemo) (прим.пер.: все популярные среды программирования позволяют включать ассерты через настройку). Вы увидите следующий результат:

Exception in thread "main" java.lang.AssertionError at AssertDemo.main(AssertDemo.java:6)

Это сообщение несколько загадочно, так как не указывает, что привело к AssertionError. Если вам нужно более информативное сообщение, используйте assert с таким синтаксисом:

Здесь expr любое выражение, включая вызов метода (прим.пер.: в соответствии с лучшими современными практиками рекомендуется отказаться от вызовов методов из ассертов), которое должно возвращать значение — вы не можете вызвать метод void. Удобно использовать просто строку, описывающую причину сбоя, как показано ниже:

Листинг 2: AssertDemo.java (версия 2)

public class AssertDemo < public static void main(String[] args) < int x = -1; assert x >= 0: "x < 0"; >>

Запустите этот код с включенными ассертами. На этот раз вы увидите чуть больше информации, объясняющей причину выброса AssertionError:

Exception in thread "main" java.lang.AssertionError: x < 0 at AssertDemo.main(AssertDemo.java:6)

Для любого из этих примеров, выполнение AssertDemo без -ea опции (enable assertions) не приведет к бросанию исключения. Если ассерты отключены, они не выполняются, хотя и присутствуют в файле класса.

Предварительные условия и постусловия

Ассерты проверяют предварительные и постусловия на true, и предупреждают разработчика, когда происходит нарушение:

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

Предварительные условия

Вы можете обеспечить выполнение предварительных условий для общедоступных конструкторов и методов, выполнив явные проверки и выбрасывая исключения при необходимости. Для private вспомогательных методов вы можете обеспечить выполнение предварительных условий, используя ассерты. Рассмотрим листинг 3.

Листинг 3: AssertDemo.java (версия 3)

import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; class PNG < /** * Create a PNG instance, read specified PNG file, and decode * it into suitable structures. * * @param filespec path and name of PNG file to read * * @throws NullPointerException when filespec is * null */ PNG(String filespec) throws IOException < // Enforce preconditions in non-private constructors and // methods. if (filespec == null) throw new NullPointerException("filespec is null"); try (FileInputStream fis = new FileInputStream(filespec)) < readHeader(fis); >> private void readHeader(InputStream is) throws IOException < // Confirm that precondition is satisfied in private // helper methods. assert is != null : "null passed to is"; >> public class AssertDemo < public static void main(String[] args) throws IOException < PNG png = new PNG((args.length == 0) ? null : args[0]); >>

Создание экземпляра класса PNG в этом коде является необходимым для чтения и декодирования PNG (Portable Network Graphics) файлов изображений. Конструктор явно сравнивает filespec с null , выбрасывая NullPointerException , если он равен null . Смысл в том, чтобы обеспечить соблюдение предусловия, которое предполагает, что filespec не может быть равным null .

Однако нецелесообразно указывать assert filespec != null; , потому что предварительное условие, упомянутое в документации Javadoc конструктора, не будет (технически) проверяться, когда ассерты отключены (в данном случае, эта проверка будет просто страховкой, потому что FileInputStream() и без нас бросит NullPointerException , но негоже зависеть от недокументированного поведения).

С другой стороны, assert будет хорош во вспомогательном private методе readHeader() , который в конечном итоге завершится чтением и декодированием 8-байтового заголовка PNG файла. Предварительное условие здесь также состоит в том, что параметр is не должен быть равен null .

Постусловия

Постусловия обычно указываются через ассерты, независимо от того, является ли метод (или конструктор) общедоступным. Рассмотрим такой код:

Листинг 4: AssertDemo.java (версия 4)

public class AssertDemo < public static void main(String[] args) < int[] array = < 20, 91, -6, 16, 0, 7, 51, 42, 3, 1 >; sort(array); for (int element: array) System.out.printf("%d ", element); System.out.println(); > private static boolean isSorted(int[] x) < for (int i = 0; i < x.length - 1; i++) if (x[i] >x[i + 1]) return false; return true; > private static void sort(int[] x) < int j, a; // For all integer values except the leftmost value . for (int i = 1; i < x.length; i++) < // Get integer value a. a = x[i]; // Get index of a. This is the initial insert position, which is // used if a is larger than all values in the sorted section. j = i; // While values exist to the left of a's insert position and the // value immediately to the left of that insert position is // numerically greater than a's value . while (j >0 && x[j - 1] > a) < // Shift left value -- x[j - 1] -- one position to its right -- // x[j]. x[j] = x[j - 1]; // Update insert position to shifted value's original position // (one position to the left). j--; >// Insert a at insert position (which is either the initial insert // position or the final insert position), where a is greater than // or equal to all values to its left. x[j] = a; > assert isSorted(x): "array not sorted"; > >

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

Этот пример демонстрирует важную характеристику ассертов — их выполнение, обычно, ресурсозатратно. По этой причине в промышленной версии программы ассерты обычно отключены. В методе isSorted() необходимо сканировать весь массив, что может занять много времени в случае большого массива.

Ассерты против исключений в Java

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

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

Ассерты не заменяют исключения. В отличие от исключений, ассерты не поддерживают восстановление после ошибок (ассерты обычно немедленно останавливают выполнение программы — AssertionError не предназначены для перехвата); они часто отключены в промышленном коде; и они обычно не отображают удобные для пользователя сообщения об ошибках (хотя это не проблема assert). Важно знать, когда использовать исключения, а не ассерты.

Когда использовать исключения

Предположим, вы написали sqrt()метод, который вычисляет квадратный корень из своего параметра. В контексте действительных чисел невозможно извлечь квадратный корень из отрицательного числа. Следовательно, вы используете ассерт для отказа от исполнения метода, если аргумент отрицательный. Рассмотрим следующий фрагмент кода:

public double sqrt(double x) < assert x >= 0 : "x is negative"; // . >

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

public double sqrt(double x) < if (x < 0) throw new IllegalArgumentException("x is negative"); // . >

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

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

Этот рассказ «Как использовать ассерты в Java» был первоначально опубликован JavaWorld .

Источник

Оцените статью