Есть ли более быстрый / простой способ создания объектов из отсканированных входных данных

#java

#java

Вопрос:

Представьте, что вы хотите создать неизвестное количество экземпляров класса. Вы решаете использовать ArrayList (если есть лучший вариант, я был бы очень признателен, если бы кто-нибудь мог объяснить это) Вы хотите разрешить создавать экземпляры класса с помощью системного ввода.

 import java.util.ArrayList;
import java.util.Scanner;

class MyClass {

    static ArrayList<MyClass> myArrayList = new ArrayList<>();
    int field1;
    int field2;
    int field3;

    public MyClass(int field1, int field2, int field3) {
    // contructor statements
    }
  

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

     static void createNewInstance() {
    
    Scanner myScanner = new Scanner(System.in);

    System.out.println("Enter field 1");
    int f1 = myScanner.nextInt();
    System.out.println("Enter field 2");
    int f2 = myScanner.nextInt();
    System.out.println("Enter field 3");
    int f3 = myScanner.nextInt();

    myArrayList.add(new MyClass(f1, f2, f3));
    }
}

  

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

Комментарии:

1. Узким местом здесь являются операции ввода-вывода. Сканер работает медленно, но не настолько медленно. Эти переменные, скорее всего, будут использоваться повторно, поэтому проблем там тоже нет… Вы могли бы попробовать измерить поведение с помощью myArrayList.add(new MyClass(myScanner.nextInt(), myScanner.nextInt(), myScanner.nextInt())); и убедиться, что оно такое же, как для кода, который у вас уже есть.

2. Это определенно случай «преждевременной оптимизации». Ограничивающим фактором здесь будет просто ввод данных конечным пользователем. Ничто другое, что вы делаете хорошо или плохо, не окажет такого большого влияния, как ожидание пользователя. Ваш код в порядке (за исключением того, что я бы не помещал код, связанный со сканером, в MyClass , но в выделенный класс пользовательского интерфейса, но это соображение дизайна и не связано с производительностью).

Ответ №1:

В «нормальной» ситуации вы никогда не будете создавать подобные объекты — существует множество способов, которыми приложение получает объекты (чтение из пакета, получение HTTP-запросов, десериализация …), и я никогда не видел, чтобы «на производстве» запрашивал пользователя «теперь дайте мне значение первого поля …» и т.д. и значения сканирования

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

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

Не переусердствуйте с этим

Комментарии:

1. Я думаю, вы еще не разработали готовое к производству консольное / терминальное приложение 🙂 Также любой инструмент сериализации будет внутренне использовать множество локальных переменных для анализа переданного obejct.

2. Я работаю в отрасли почти 10 лет и не видел такого случая в Java — ofc, это не значит, что таких приложений не существует 🙂 Об этом сериализаторе — вам вообще должно быть все равно, даже такие классы, как java.lang.String или ArrayList , имеют много-много локальных переменных — вы когда-нибудь слышали, что это проблема? 🙂

3. Точно! Это тоже моя точка зрения… Выделение локальных переменных — это скорее хорошо, чем зло, поскольку это улучшает читаемость кода и облегчает отладку, если это необходимо. Что касается консольных приложений, я их тоже не видел 9 лет, но сейчас я разрабатываю такое…

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

Ответ №2:

Во-первых, давайте упомянем, что Преждевременная оптимизация — это корень всего зла

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

«Укажите свои номера, разделенные на,»

А затем, после использования scanner.nextLine() , вы можете разделить строку и получить свои номера (и подтвердить, что были заданы все 3 номера).

Комментарии:

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

Ответ №3:

Builder pattern и, возможно, Project Lombok — ваши друзья!

 public static void main(String[] args) {
    MyClass obj = createNewInstance();
}

public static MyClass createNewInstance() {
    Scanner scan = new Scanner(System.in);

    MyClass.MyClassBuilder builder = MyClass.builder();
    builder.field1(scan.nextInt());
    builder.field2(scan.nextInt());
    builder.field3(scan.nextInt());
    return builder.build();
}

@Builder
@RequiredArgsConstructor
public static class MyClass {

    private final int field1;
    private final int field2;
    private final int field3;

}
  

Другой вариант — поместить Scanner непосредственно в конструктор (но это НЕ ОЧЕНЬ ХОРОШО с точки зрения принципов проектирования объектов)

 public static void main(String[] args) {
    MyClass obj = new MyClass(new Scanner(System.in));
}

public static class MyClass {

    private final int field1;
    private final int field2;
    private final int field3;

    public MyClass(Scanner scan) {
        field1 = scan.nextInt();
        field2 = scan.nextInt();
        field3 = scan.nextInt();
    }

}
  

Комментарии:

1. и в чем здесь разница? все еще три дополнительных поля, просто обернутые в object