Уникнення нульового покажчика, коли необхідно повернути одне значення

По-перше, є купа питань про stackoverflow з нульових покажчиків - але не знайшла цього. Це воно існувало, і я не знайшов його, тоді пошкодуйте мою помилку.

Питання є загальним - якщо функція повертає лише один елемент, то, як мати справу з відсутнім випадком "елемента". Наприклад: зразок коду - це лише зразок.

public int findSmallestNumberGreaterThanX(int a[], int x) {
 //do what ever logic.
  if (numFound) { return smallesNumberGreaterThanX; }
  else {
    //what ??
   }
}

Якщо не було числа в масиві більше, ніж x - що робити?

  1. Ефективне java згадує повернути пустий масив замість нульового покажчика - але чи варто створювати масив, якщо функція повертає один елемент?

  2. Наступним варіантом є повернення null. Я бачив багато повідомлень, які відкидають ідею повернення null.

  3. Третій - повернути об'єкт {boolean found; значення int; }. Це звучить як переповнення.

Будь ласка, запропонуйте мені найкращий підхід тут.

3
Я виклав усі варіанти, які були розглянуті на інших питаннях щодо переповнення стека. Як видається, змішані відповіді - ніхто безпосередньо не звертається до цього конкретного сценарію - вибачає, але не може досягти жодного висновку.
додано Автор JavaDeveloper, джерело
Чи буде smallesNumberGreaterThanX містити x у будь-якому стані?
додано Автор Vishal K, джерело
можливий дублікат уникнення "! = null" заяв на Java?
додано Автор Elazar, джерело

7 Відповіді

Це залежить від того, яка функція повертається. Якщо він повертає значення, то будь-яке значення є дійсним, тому повернення значення не може бути використано для контролю дійсності.

Якщо ви повернете індекс значення, яке ви знайшли в масиві, то все, що знаходиться нижче нуля, можна вважати незаконним значенням і можна використовувати для коду помилки.

Можливо, ви можете додати параметр, який буде містити ваше повернене значення, і змінити свою функцію, щоб воно повернуло логічне значення, що вказує, чи знайдений номер чи ні

3
додано

Якщо ваше порівняння є суворим, ви можете повернути Integer.MIN_VALUE, оскільки це єдине значення, яке не можна повернути іншим способом. (оскільки він менший за всі інші значення, окрім себе).

3
додано
У цьому випадку Integer.MIN_VALUE діє як "дозорне" значення.
додано Автор Raedwald, джерело
а що, якщо x == Integer.MIN_VALUE?
додано Автор Elazar, джерело
+1, але ви повинні пояснити чому цей параметр є найкращим, а не іншими варіантами, зазначеними у запиті.
додано Автор Vulcan, джерело

Я бачу кілька способів вирішення цієї проблеми. Я рекомендую використовувати (1) або (2), і уникати (3) і (4).

(1): кинути виняток. Ваш метод виглядатиме так:

public int findSmallestNumberGreaterThanX(int a[], int x)
    throws NoSuchNumberException {
 //do what ever logic.
  if (numFound) { return smallestNumberGreaterThanX; }
  else {
    throw new NoSuchNumberException();
   }
}

і називатиметься, кажучи

try {
  int smallestNum = findSmallestNumberGreaterThanX(a, x);
  //use smallestNum
} catch(NoSuchNumberException e) {
  //handle case where there is no smallestNum
}

Ви також повинні створити клас NoSuchNumberException:

public class NoSuchNumberException extends Exception {

  public NoSuchNumberException() {}

  public NoSuchNumberException(String message) {
    super(message);
  }
}


(2): Slightly refactor your code.

Замість того, щоб робити все в одному методі, зробіть метод

public int findSmallestNumber(int a[]) {...}

а потім скажіть

int smallestNum = findSmallestNumber(a);
if (smallestNum > x) {
  //use smallestNum
} else {
  //handle case where there is no smallestNum > x
}


(3): Set your return type to Integer, and return null. Java will automatically cast between int and Integer, and null is a valid value for Integer. Just be sure to check for null wherever you use this method, because if you try to cast null to an int, it will break.


(4): return a number less than x. (I strongly recommend you do not use this solution unless you can also use that number somehow.) Since the number is less than x, it can be identified as an error condition.

3
додано
Дякуємо - але який з варіантів є найбільш рекомендованим .. у загальному випадку - елемент, який може бути єдиним об'єктом, плаваючим, все, що не є колекцією, потрібно повернути? I
додано Автор JavaDeveloper, джерело
Іноді не існує стандартного методу, з структурної точки зору мені подобається виняток більшості (ніяких спеціальних магічних чисел), але винятки дуже дорогі, тому на практиці я зазвичай використовую w -1 або null (залежно від того, чи повертаєш примітив або об'єкт
додано Автор Richard Tingle, джерело
@JavaDeveloper Я б сказав, що (1) або (2) буде рекомендовано. При структуруванні програми не обов'язково існує "правильна відповідь". Але якщо ви розробляєте загальний метод, який може повернути що-небудь, ви можете переглянути це. Вихідні дані були б непридатні, якщо ви точно не знаєте, що це таке (або якщо ви не використовуєте багато операторів instanceof, але це, як правило, виглядає вниз.) Хоча якщо ви дійсно хочете, ви можете просто повернути Object.
додано Автор Martin Wickham, джерело

Ще одне рішення, яке ще не згадано, полягає в тому, щоб мати спеціальний клас, що представляє значення зі збоями. В одному з наших проектів у нас було

public interface Option
    extends java.util.Collection
{
   //Throws an exception if empty.
    public T get();
   //Returns `deflt` if empty.
    public T getOrElse(T deflt);
    public boolean isEmpty();
}

Option represents either a single value of type T or no value. (It implements Collection so that it can be viewed as a collection of 0 or 1 elements, which allows you to use it for example in for comprehensions, but it's probably not important for your case.) It had two subclasses, one representing an empty Option і one representing a full one:

// ---

public final class None
    extends AbstractCollection
    implements Option
{
    public None() {}
   //...
}

і

public final class Some
    extends AbstractCollection
    implements Option
{
    private final T value;

    public Some(T value) {
        this.value = value;
    }

   //...
}

Повний код доступний тут . Це лише варіант класу Option Scala.

У вашому випадку ви будете використовувати його як

public Option findSmallestNumberGreaterThanX(int a[], int x) {
 //do what ever logic.
  if (numFound) { return new Some(smallesNumberGreaterThanX); }
  else { return new None(); }
}

Creating such an object has negligible overhead (unless you create millions of them), і gives a nice semantic distinction between a successful і a failed operation.

2
додано
Звучить добре .. але як це сильно відрізняється від опції 3 'Третій - повернути об'єкт {boolean found; значення int; }. Це звучить як надмірне. Замість інтерфейсу і 2 класу я б просто повернув один клас?
додано Автор JavaDeveloper, джерело
@JavaDeveloper Це схоже, ви могли б реалізувати Option внутрішньо, як ви пропонуєте. Цей варіант є поліморфним, тому ви можете використовувати його для будь-яких цілей. Це зовсім не перебільшення - деталі реалізації не так важливі, на кінцевому рахунку важлива ясність коду. Якщо ви уникнете null і використовуйте Option<...> , то завжди буде ясно, які значення є необов'язковими і які значення потрібні. Тут хороший підручник з Option Scala.
додано Автор Petr Pudlák, джерело

Є ще одне рішення, яке ще не згадано:

Instead of returning the element itself, return its index. If there is no such element, either return -1 or the array size. This approach is quite common in C++ with iterators.

2
додано

Якщо smallesNumberGreaterThanX не містить самого x , ви можете використовувати щось на зразок цього:

public int findSmallestNumberGreaterThanX(int a[], int x) {
 //do what ever logic.
  if (numFound) { return smallesNumberGreaterThanX; }
  else {
     return x;
   }
}

І поки ви називаєте метод, його можна використовувати так:

int var = findSmallestNumberGreaterThanX(a ,x);
if (var == x)
{
    System.out.println("No value found");
}
2
додано
Це неприпустиме рішення, якщо x дорівнює Integer.MIN_VALUE
додано Автор sasha.sochka, джерело

Дуже поширеним є повернення нуля для "не знайдено" результату. Повернення "спеціального" значення, такого як Integer.MIN_VALUE , є нормальним, тому що математично це не є легітимним результатом, але це було б нетрадиційним підходом, з яким викликається адресат.

У вас є два варіанти:

  1. Якщо ви не знайдете виключення, виключіть
  2. Змініть тип повернення на тип об'єкта та поверніть null

Варіант 1. взагалі не є гарною ідеєю, але якщо ви абсолютно повинні повернути int, тоді використовуйте його

Варіант 2. є більш загальним рішенням, задокументованим з javadoc

/**
 * @returns null if not found
 */
public Integer findSmallestNumberGreaterThanX(int a[], int x) {
   //do what ever logic.
    if (numFound)
        return smallesNumberGreaterThanX;
    return null;
}
0
додано
@DonRoby ой! Після всіх цих розмов я забув зробити найважливіші зміни. Виправлено зараз. Дякую
додано Автор Bohemian, джерело
Можливо, ви захочете змінити int на Integer у коді зразка, як зазначено у тексті відповіді.
додано Автор Don Roby, джерело
ІТ КПІ - Java
ІТ КПІ - Java
436 учасників