2010-07-22 2 views
7

У меня есть функция, которая возвращает значение int для заданной клавиши (от HashMap<String, Integer>). Если ключ не существует, я хочу вернуть то, что может проверить вызывающий. Кажется, что чаще всего это будет «возвращает -1, если ключ не существует« вид вещей. Тем не менее, я не могу зарезервировать -1 для этой цели в моем случае, потому что отрицательные числа являются допустимыми значениями для ключей, которые существуют do.Возвращает «null» на функцию примитивного возврата типа?

Единственные другие варианты я смог придумать, являются следующие:

  1. Изменить тип возврата к Integer класс обертку и проверить null
  2. возвращенной что-то очень маловероятно, такой как Integer.MIN_VALUE
  3. Сделать дополнительную функцию boolean keyExists(String key), которую всегда следует называть первым
  4. Переключить на float и использовать NaN вместо

Я пишу это на Java, но люди из похожих языков могут отправлять сообщения. Благодаря!

+1

# 4 интересно , Как вы проверяете NaN? NaN! = NaN истинно. –

+1

Float.isNaN (float);) IMHO float почти никогда не является хорошей идеей. попробуйте длинный или двойной вместо этого. –

ответ

14

Первый вариант, на мой взгляд, самый чистый. Магические числа, такие как -1 и Integer.MIN_VALUE, являются довольно грязными, особенно когда значения не являются интуитивными. Это идиоматическое решение C, которое разработчики Java будут вас ненавидеть. В зависимости от того, что вы на самом деле используете для этого, вы также можете бросить «KeyNotFoundException», если это происходит только в «исключительных» обстоятельствах.

+2

+1 для исключительного предложения потока –

+0

Я пошел с возвратом int, но выбрасывал исключение во время выполнения, если ключ не найден (тогда есть функция keyExists (key)). Как вы думаете, использование Integer было бы лучшим решением? Вероятно, это было бы более эффективно, потому что мой HashMap уже сохраняет значения как целые числа ... – idolize

+1

Не бросайте исключение во время выполнения (что-то, полученное из RuntimeException). Используйте регулярное исключенное исключение. Если вы когда-либо хотите сделать свою программу многопоточной, имейте в виду, что при вызове функции keyExists перед просмотром значения с помощью двух отдельных вызовов функций создается условие гонки, если вы не заблокируете какой-либо объект, прежде чем вы будете называть его каждый раз или просто опустите часть keyExists и заверните вызов в блок try/catch для KeyNotFoundException. – Hut8

1

Хотя это сильно зависит от приложения и знает ограничения, я предпочел бы # 1 выше. Причина в том, что тогда он явчен - всегда лучше иметь явную ситуацию, чем неявный - например MIN_VALUE - по моему опыту.

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

public class Wrapper { 
    private int value = Integer.MIN_VALUE; 
    private boolean isValid; 
    // appropriate getters and setters etc. 
} 

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

3

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

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

+1

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

+0

@mxrider: производительность - это проблема, поэтому вы хотите избежать исключений? Умм, что? Это звучит как преждевременная/ошибочная «оптимизация» для меня. Я бы сказал, напишите самый чистый код, а затем проверьте с помощью профилировщика, если с ним возникнут проблемы с производительностью. – Jonik

+0

Думаю, я должен перефразировать. Опираясь на try/catch в ситуациях, когда производительность важна (например, в цикле или таймере), может стать узким местом. Я на самом деле нуждался в использовании функции keyExists(), и моя функция getValue() выкидывает специальное исключение RuntimeException, если ключ не найден - таким образом мне не нужен try/catch, но я все еще придерживаюсь лучших практики. – idolize

0

Вариант 5: сгенерирует исключение

Хотя, в данном случае, я бы голосовать за помощью класса Integer.

0

Я думаю, вам следует комбинировать варианты # 1 и # 3, так как это соответствует поведению лежащего в основе HashMap. От HashMap в get method documentation:

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

0
  1. Изменить тип возврата к Integer класс обертку и проверить нуль.

Это наиболее распространенный вариант.

1

float небезопасен, поскольку не все значения int могут быть точными, представленными как значения int. long - это лучшие варианты, так как все значения int могут быть сохранены так долго, и у вас будет больше значений для не найденных.

Если вы используете карту у вас есть Integer объект в любом случае, так почему бы не вернуть, что (или нуль)

Если вы действительно хотите использовать примитивы (для эффективности ??) Я предлагаю вам взглянуть на TObjectIntHashMap вместо этого. Это использует примитивные значения int. Чтобы проверить на отсутствие, вы должны проверить, содержитKey() отдельно.

1

Две ситуации типичны:

  1. У вас есть высокое ожидание найти значение для конкретного ключа.
  2. Вы не уверены, имеет ли значение конкретный ключ .

Если предположение 1 неверно, то это может указывать на ошибку, поэтому защитите ваше предположение в методе доступа с утверждением.

Если применяется 2, как бы вы были уверены в том, что было возвращено? поэтому дайте метод тестирования, такой как «keyExists», и обязательно узнайте до доступа к карте.

В случае 1 проверка не требуется, что намного чище, но доступ не удастся, если вы ошибаетесь. С особыми случаями, такими как -1 или Integer.MIN_VALUE, очень сложно быть уверенным, что они не будут использоваться.

Языки, как Haskell, Scala и C# имеют специальные типы передать наличие/отсутствие значения, которое гораздо лучше, чем использование нулевой (если вы забыли проверить вы, вероятно, получите NullPointerException)

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