Действительно ли-1 магическое число? Антишаблон? Запах кода? Кавычки и инструкции от полномочий [дубликат]

12
задан Community 23 May 2017 в 12:31
поделиться

10 ответов

Это обычная идиома в языках, в которых типы не включают проверки диапазона. Значение «вне границ» используется для обозначения одного из нескольких условий. Здесь возвращаемое значение указывает на две вещи: 1) был найден символ и 2) где он был найден.Использование -1 для не найдено и неотрицательного индекса для найдено кратко кодирует оба из них в одно значение, а также тот факт, что не найдено не нужно возвращать индекс.

В языке со строгой проверкой диапазона, таком как Ада или Паскаль, метод может быть реализован как (псевдокод)

   bool indexOf(c:char, position:out Positive);

Положительный является подтипом int, но ограничен неотрицательными значениями.

Это отделяет флаг «найдено / не найдено» от позиции. Позиция предоставляется как выходной параметр - по сути, другое возвращаемое значение. Это также может быть параметр входа-выхода, чтобы начать поиск с заданной позиции. Использование -1 для обозначения того, что не найдено, здесь недопустимо, поскольку оно нарушает проверки диапазона для положительного типа.

В java есть следующие альтернативы:

  • генерировать исключение: это не лучший выбор, так как отсутствие символа не является исключительным условием.
  • разделить результат на несколько методов, например логический indexOf (char c); int lastFoundIndex (); . Это означает, что объект должен сохранять состояние, что не будет работать в параллельной программе, если только состояние не будет сохранено в локальном хранилище потока или не будет использоваться синхронизация - все это связано со значительными накладными расходами.
  • возвращает позицию и флаг найденного отдельно: например, логический indexOf (char c, Position pos) . Здесь создание объекта позиции может рассматриваться как ненужные накладные расходы.
  • создают многозначный возвращаемый тип

, такой как

class FindIndex {
   boolean found;
   int position;
}

FindIndex indexOf(char c);

, хотя он четко разделяет возвращаемые значения, но страдает накладными расходами на создание объекта.Некоторые из них можно смягчить, передав FindIndex в качестве параметра, например

FindIndex indexOf(char c, FindIndex start);

Между прочим, несколько возвращаемых значений должны были быть частью java (oak), но они были исключены до версии 1.0, чтобы сократить время выпуска. Джеймс Гослинг говорит , что он хотел бы, чтобы они были включены. Это все еще желанная функция .

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

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

   // get everything after the first c
   int index = str.indexOf('c');
   String afterC = str.substring(index);

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

11
ответ дан 2 December 2019 в 05:53
поделиться

И Java, и JavaScript используют -1 , когда индекс не найден. Поскольку индекс всегда равен 0-n , выбор кажется довольно очевидным.

//JavaScript
var url = 'example.com/foo?bar&admin=true';
if(url.indexOf('&admin') != -1){
  alert('we likely have an insecure app!');
}

Я считаю этот подход (который я использовал при расширении элементов типа Array для получения метода .indexOf () ) вполне нормальным.

С другой стороны, вы можете попробовать подход PHP, например. strpos () , но ИМХО это сбивает с толку, так как есть несколько типов возврата (возвращает FALSE, если не найдено)

3
ответ дан 2 December 2019 в 05:53
поделиться

например, почему 51% означает все для акционеров компания, так как она лучше всех и имеет смысл, а не -2 или -3 ...

1
ответ дан 2 December 2019 в 05:53
поделиться

Является ли -1 магическим числом?

В данном контексте нет. В -1 нет ничего особенного, кроме того факта, что это гарантированно недопустимое значение индекса в силу того, что оно отрицательное.

Антипаттерн?

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

Запах кода?

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

Цитаты и рекомендации властей

Насколько мне известно, нет. Однако замечу, что это «устройство» используется в различных стандартных классах. Например, String.indexOf (...) возвращает -1 , чтобы сказать, что символ или подстрока не могут быть найдены.


Насколько мне известно, это просто «алгоритмическое устройство», которое может быть полезно в некоторых случаях. Я уверен, что если вы посмотрите литературу, вы увидите примеры использования -1 (или 0 для языков с массивами, основанными на единице) таким образом, возвращаясь к 1960-е и раньше.

Выбор -1 вместо какого-либо другого отрицательного числа - это просто вопрос личного вкуса, и (ИМО) не стоит анализировать. В этом контексте.


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

Обратной стороной является то, что если «условие», представленное как -1 (или что-то еще), является не «ошибкой» / «исключительным условием», то возвращается специальное значение разумно и правильно.

4
ответ дан 2 December 2019 в 05:53
поделиться

Используется, потому что это первое недопустимое значение, с которым вы сталкиваетесь в массивах с отсчетом от 0. Как вы знаете, не все типы могут содержать null или ничего, поэтому нужно «что-то», чтобы ничего не значить.

Я бы сказал, что это не официально, это просто стало условным (неписаным), потому что это очень разумно для ситуации. Лично я бы тоже не назвал это проблемой. Дизайн API также зависит от автора, но рекомендации можно найти в Интернете .

1
ответ дан 2 December 2019 в 05:53
поделиться

Хорошей практикой является определение конечной переменной класса для всех постоянных значений в вашем коде. Но общепринято использовать 0, 1, -1, "" (пустая строка) без явного объявления.

1
ответ дан 2 December 2019 в 05:53
поделиться

Это наследование от языка C, где можно было возвращать только одно примитивное значение. В java вы также можете возвращать один объект.

Поэтому для нового кода верните объект базового типа с подтипом, указывающим на проблему, которая будет использоваться с instaceof, или выбросьте исключение "not Found".

Для существующих специальных значений сделайте -1 константой в ваших кодовых именах соответственно - NOT_FOUND - чтобы читатель мог определить значение без необходимости проверять javadocs.

1
ответ дан 2 December 2019 в 05:53
поделиться

Та же практика, что и для null , применяется к -1 . Об этом много раз говорили.

например. Java api design - NULL или Exception

1
ответ дан 2 December 2019 в 05:53
поделиться

-1 в качестве возвращаемого значения немного некрасиво, но необходимо. Альтернативы для сигнализации условия "не найдено", IMHO, гораздо хуже:

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

  • Можно использовать составной объект result объект с (found,index), но это требует выделения объекта и более сложный код со стороны вызывающей стороны для проверки результата.

  • Можно выделить две отдельные вызовы функций для contains и indexOf - однако это снова довольно громоздко для вызывающей стороны а также приводит к снижению производительности поскольку оба вызова будут O(n) и требуют полного обхода String.

Лично мне никогда не нравится ссылаться на константу -1: мой тест на ненайденное значение всегда выглядит примерно так:

int i = someString.indexOf("substring");
if (i>=0) {
  // do stuff with found index
} else {
  // handle not found case
}
2
ответ дан 2 December 2019 в 05:53
поделиться

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

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

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

someCollection.objectAtIndex(someCollection.indexOf(someObject)) == someObject

То, что вы, вероятно, получите, является исключением, потому что -1 находится за пределами допустимого диапазона, в то время как фактическая причина, по которой это правдоподобное соотношение не соответствует действительности, что someObject не является элементом someCollection , и поэтому внутренний вызов должен вызывать исключение.

Каким бы чистым и надежным он ни был, он имеет два ключевых недостатка:

  • Обычно обе операции обычно обходятся вам в O (n) (если у вас нет обратной карты в коллекции), так что вы Лучше, если ты сделаешь только один.
  • Это действительно довольно многословно.

В конце концов, решать вам. Это вопрос философии.Я бы назвал это «семантическим взломом» для достижения краткости и скорости за счет надежности. Ваш звонок;)

привет
back2dos

1
ответ дан 2 December 2019 в 05:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: