Должны ли аргументы метода Java использоваться для возврата нескольких значений? - PullRequest
26 голосов
/ 07 апреля 2009

Поскольку аргументы, отправленные методу в Java, указывают на исходные структуры данных в методе вызывающего, намерены ли его разработчики использовать их для возврата нескольких значений, как это является нормой в других языках, таких как C?

Или это опасное неправильное использование общего свойства Java, что переменные являются указателями?

Ответы [ 9 ]

15 голосов
/ 07 апреля 2009

Давным-давно у меня был разговор с Кеном Арнольдом (один раз член команды Java), это было бы на первой конференции Java One, вероятно, в 1996 году. Он сказал, что они думают добавить несколько возвращаемых значений чтобы вы могли написать что-то вроде:

x, y = foo();

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

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

Это обычная практика (как и желание программистов на C модифицировать аргументы ... в конце концов они обычно видят способ Java сделать это. Просто подумайте об этом, как о возвращении структуры.: -)

(Изменить на основании следующего комментария)

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

Думаю, если я правильно вас понимаю, то, вероятно, я бы поступил так:

// could go with the Pair idea from another post, but I personally don't like that way
class Line
{
    // would use appropriate names
    private final int intVal;
    private final String stringVal;

    public Line(final int iVal, final String sVal)
    {
        intVal    = iVal;
        stringVal = sVal;
    }

    public int getIntVal()
    {
        return (intVal);
    }

    public String getStringVal()
    {
        return (stringVal);
    }

    // equals/hashCode/etc... as appropriate
}

и затем используйте ваш метод так:

public void foo(final File file, final List<Line> lines)
{
    // add to the List.
}

и затем назовите это так:

{
    final List<Line> lines;

    lines = new ArrayList<Line>();
    foo(file, lines);
}
7 голосов
/ 07 апреля 2009

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

  • служит абстракцией (т.е. класс Point вместо массива из двух длин)
  • каждое поле имеет имя
  • можно сделать неизменным
  • значительно упрощает развитие API (т. Е. Возвращение 3 вместо 2 значений, изменение типа некоторого поля и т. Д.)

Я всегда выбирал бы возвращение нового экземпляра вместо фактического изменения переданного значения. Мне это кажется намного понятнее и поддерживает неизменность.

С другой стороны, если это внутренний метод, я думаю, может быть использовано любое из следующего:

  • массив (new Object[] { "str", longValue })
  • список (Arrays.asList(...) возвращает неизменный список)
  • класс пары / кортежа, например this
  • статический внутренний класс с открытыми полями

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

5 голосов
/ 07 апреля 2009

Хотелось бы, чтобы в JDK был класс Pair<E,F>, в основном по этой причине. Существует Map<K,V>.Entry, но создание экземпляра всегда было большой болью.

Теперь я использую com.google.common.collect.Maps.immutableEntry, когда мне нужно Pair

5 голосов
/ 07 апреля 2009

См. Этот RFE, выпущенный еще в 1999 году:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4222792

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

Используя такие языки, как Scala, вы можете возвращать кортежи, см .:

http://www.artima.com/scalazine/articles/steps.html

Вы также можете использовать Generics в Java для возврата пары объектов, но это все, AFAIK.

РЕДАКТИРОВАТЬ: кортежи

Просто чтобы добавить еще немного к этому. Ранее я реализовал пару в проектах из-за отсутствия в JDK. Ссылка на мою реализацию находится здесь:

http://pbin.oogly.co.uk/listings/viewlistingdetail/5003504425055b47d857490ff73ab9

Обратите внимание, что в нем нет хеш-кода или равных, который, вероятно, следует добавить.

Я также сталкивался с этим во время исследования этих вопросов, которое обеспечивает функциональность кортежей:

http://javatuple.com/

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

2 голосов
/ 07 апреля 2009

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

private void myFunc(Object a) {
    a = new Object();
}

приведет к временному и локальному изменению значения a, но это не изменит значение вызывающей стороны, например, с:

Object test = new Object();
myFunc(test);

После возврата myFunc у вас будет старый объект, а не новый.

Законно (и часто не одобряется) что-то вроде этого:

private void changeDate(final Date date) {
    date.setTime(1234567890L);
}

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

ПРИМЕЧАНИЕ. Обычно говорят, что метод должен выполнять одно из следующих действий:

  • Вернуть void и изменить его входящие объекты (например, Collections.sort()) или
  • Вернуть некоторые вычисления и вообще не изменять входящие объекты (например, Collections.min()) или
  • Возвращает «вид» входящего объекта, но не изменяет входящий объект (например, Collections.checkedList() или Collections.singleton())
  • Измените один входящий объект и верните его (Collections не имеет примера, но StringBuilder.append() является хорошим примером).

Методы, которые изменяют входящие объекты и , возвращающие отдельное возвращаемое значение, часто делают слишком много вещей.

0 голосов
/ 17 декабря 2009

У меня был объект Result, который каскадно проходит через серию проверяющих методов void в качестве параметра метода. Каждый из этих проверяющих void-методов будет мутировать объект параметра результата, чтобы добавить результат проверки.

Но это невозможно проверить, потому что теперь я не могу заглушить метод void для возврата значения заглушки для проверки в объекте Result.

Таким образом, с точки зрения тестирования представляется, что следует отдавать предпочтение возврату объекта, а не изменению параметра метода.

0 голосов
/ 08 апреля 2009

Вообще то, что сказал Эдди, но я бы добавил еще одно:

  • Мутирует один из входящих объектов и возвращает код состояния. Обычно это следует использовать только для аргументов, которые явно являются буферами, например Reader.read (char [] cbuf).
0 голосов
/ 07 апреля 2009

Обычно это не считается ужасно хорошей практикой, но в JDK бывают очень редкие случаи, когда это делается. Посмотрите, например, на параметр 'biasRet' в View.getNextVisualPositionFrom () и связанных с ним методах: это фактически одномерный массив, который заполняется «дополнительным возвращаемым значением».

Так зачем это делать? Ну, просто чтобы избавить вас от необходимости создавать дополнительное определение класса для «случайного дополнительного возвращаемого значения». Это грязный, не элегантный, плохой дизайн, не объектно-ориентированный, бла-бла. И мы все время от времени делали это ...

0 голосов
/ 07 апреля 2009

Конечно, есть методы, которые изменяют объект, переданный в качестве параметра (, см. Java.io.Reader.read (byte [] buffer) , но я не видел параметров, используемых альтернатива для возвращаемого значения, особенно с несколькими параметрами. Технически это может работать, но это нестандартно.

...