Лучшие практики для возврата нескольких значений?

Допустим, я хочу разработать функцию, которая возвращает информацию о данной акции. Функция получает название акции в качестве параметра типа String, а затем возвращает несколько значений. Он может вернуть следующие значения:

int price
int profitability
double currentTrend
int mostRecentSpike
long timeOfRecentSpike

Как видите, все они относятся к разным примитивным типам. Мне интересно, как лучше всего вернуть эти значения с точки зрения оптимизации. Итак, если бы я создал такой пользовательский объект:

class Stock {
    int price;
    int profitability;
    double currentTrend;
    int mostRecentSpike;
    long timeOfRecentSpike;
    public Stock(int price, int profitability, double currentTrend, int mostRecentSpike, long timeOfRecentSpike) {
        this.price = price;
        this.profitability = profitability;
        this.currentTrend = currentTrend;
        this.mostRecentSpike = mostRecentSpike;
        this.timeOfRecentSpike = timeOfRecentSpike;
    }
}

и вернул это, было бы лучше, чем альтернатива, в которой я просто вернул это:

new Object[] {price, profitability, currentTrend, mostRecentSpike, timeOfRecentSpike}

а затем преобразовал все в соответствующие примитивные типы? Хотя я понимаю, что читаемость будет снижена при возврате и преобразовании Object [], меня больше всего беспокоит производительность с точки зрения ЦП, памяти и сериализации.

  • Что будет более интенсивно для ЦП?
  • Что займет больше памяти?
  • Что лучше всего сочетать с сериализацией?

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

"с точки зрения оптимизации" - почему? С какими проблемами производительности вы столкнулись?
luk2302 22.05.2018 19:56

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

markspace 22.05.2018 19:56

Верните Stock, чтобы поля сохранили свой тип и семантическое значение.

Andy Turner 22.05.2018 19:58

Fwiw, Google широко использует AutoValue именно для этой цели.

Andy Turner 22.05.2018 20:02

«Так что, даже если разница незначительна в этом небольшом примере, в моей реальной ситуации она будет гораздо более значительной». Самая большая проблема с возвратом всего содержимого Object[] состоит в том, что вы теряете семантическую информацию. Вторая по величине проблема заключается в том, что вам нужно упаковать все примитивы, что приводит к накладным расходам для каждого элемента массива. Использование настраиваемого класса позволяет вам хранить вещи как примитивы, поэтому накладные расходы вы берете только один раз на каждое возвращаемое значение.

Andy Turner 22.05.2018 20:06

@AndyTurner не лучше ли хранить их в коробочном формате? Итак, каждый int теперь является целым числом, long теперь Long и т. д.?

Kael Eppcohen 22.05.2018 20:08

@KaelEppcohen, если вас беспокоит использование памяти, нет. int занимает 4 байта; Integer 12. Таким образом, вы можете сохранить свои 3 поля int в пространстве, которое потребуется для хранения 1 как целого числа.

Andy Turner 22.05.2018 20:10

@Andy Integer - как минимум 16 ...

Oleksandr Pyrohov 22.05.2018 20:11

@ Александр, моя ошибка, я думал только о накладных расходах.

Andy Turner 22.05.2018 20:15
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
9
318
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Что ж, с точки зрения оптимизации, лучшая практика - вернуть объект Stock, потому что приведение приведет к гораздо большему использованию процессора и памяти и даже может привести к исключениям, таким как classCastException, если в любом случае вы пропустите какие-либо переменные.

Так,

return new Stock(price, profitability, currentTrend, mostRecentSpike, timeOfRecentSpike);

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

Andy Turner 22.05.2018 20:11

Пока ты говоришь

it will scale up to be much more significant in my actual situation.

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

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

Ответ принят как подходящий

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

markspace:

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

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

Пользовательский класс также улучшает читаемость.

Энди Тернер:

С помощью Object [] каждое введенное значение станет объектом, и когда вы извлечете элементы из этого массива, вам нужно будет упаковать их из объекта в их непримитивный аналог (Long, Double, Integer), который имеет некоторые накладные расходы. С настраиваемым классом вы будете хранить все как примитив, поэтому нет необходимости в боксе и, как следствие, нет накладных расходов.

Также, если вы думали об использовании непримитивных значений внутри своего пользовательского класса, это хуже с точки зрения памяти. Наличие поля типа int примерно в 4 раза эффективнее памяти, чем хранение его как Integer.

Другие вопросы по теме