Подтвердить что ты не робот

Должны ли аргументы метода Java возвращать несколько значений?

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

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

4b9b3361

Ответ 1

Долгое время у меня была беседа с Кеном Арнольдом (одно время членом команды 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);
}

Ответ 2

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

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

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

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

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

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

Ответ 3

См. эту 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.

EDIT: Кортежи

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

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

Обратите внимание: на этом нет хэш-кода или равно, что, вероятно, должно быть добавлено.

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

http://javatuple.com/

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

Ответ 4

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

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

Ответ 5

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

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() - хороший пример).

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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

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

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