有没有更快/更简单的方法来从扫描的输入构建对象?

huangapple go评论85阅读模式
英文:

Is there a faster/simpler way of constructing objects from scanned inputs

问题

假设你想要创建一个未知数量的类实例。你决定使用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) {
        // 构造函数语句
    }

这里的问题是,如果你扫描输入,你不能直接将它们传递给构造函数,因为你需要在它们之间打印消息,然后再扫描输入。你被迫将所有字段的值存储在其他变量中,如下所示,你也可以在每次扫描它们时将字段设置为新对象的索引,但是这似乎会使代码变得缓慢和复杂。

    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));
    }
}

所以我想知道是否有一种方法可以直接将扫描的输入传递给构造函数,似乎将值存储为变量会需要一些计算,而且如果这些变量是基本类型,它们可能在栈中,而栈具有静态内存分配,所以它们会永久存在。在我看来,在大规模情况下,这不是一个很好的解决方案,但是我对程序性能的了解非常有限,所以我不太确定。我猜答案只是使用那个解决方案,其他的解决方案可能过于复杂,不值得使用。感谢阅读,抱歉我一直在努力用简洁的方式表达这个问题。

英文:

Imagine you want to create an unknown amount of instances of a class. You decide to use an ArrayList (if there is a better option I would very much appreciate if someone could explain this) You want to allow instances of the class to be created through the System Input.

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

class MyClass {

	static ArrayList&lt;MyClass&gt; myArrayList = new ArrayList&lt;&gt;();
	int field1;
	int field2;
	int field3;

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

Here is the problem, if you scan inputs, you cannot feed them into the constructor, as you need to print messages in between and then scan the input. You are forced to store the values of all the fields by assigning them to other variables as shown below, you can also set the fields at the index of the new object each time you scan them, but this seems like it would be slow and complicated code.

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

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

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

So I am wondering if there is a way to pass the scanned input directly into the constructor, it seems like storing the values as variables would take a bit of computation and also, if these variables are primitive, i think they would be in stack, which stack has static memory allocation, so they are permanently there. It seems to me like on a large scale, this is not such a great solution, but I am also extremely limited in my knowledge of program performance, so I am not exactly sure. I am guessing the answer is just use that solution, any others are just too complicated to be worth using. Thank you for reading, sorry I have struggled to word this question in a concise way.

答案1

得分: 2

在“正常”情况下,您永远不会创建这样的对象 - 应用程序接收对象的方式有很多种(从批处理读取,接收HTTP请求,反序列化...),而且我从未看到“在生产环境中”提示用户“现在给我第一个字段的值...”等并扫描值

储存值像变量一样需要一些计算

这一点完全不是问题 - 在Java中创建对象非常快,另外三个基本字段在性能方面根本不相关

不要过度设计

英文:

In "normal" situation you will never create objects like this - there are many many ways the application receiving objects (reading from batch, receiving HTTP requests, deserialization...) and I never saw "on production" prompting the user "now give me the value of the first field..." etc and scanning values

> it seems like storing the values as variables would take a bit of computation

and that's not a problem at all - creating objects in Java is super fast, additional three primitive fields are not relevant at all when it comes to the performance

Don't overengineer this

答案2

得分: 1

首先,让我们提到【过早优化是万恶之源】。

提到这一点之后,如果您仍然希望通过stdin获取用户输入,您可以要求用户一次性提供他的数字。

例如:

"请用逗号分隔您的数字"

然后,在使用scanner.nextLine()之后,您可以拆分该行并获取您的数字(并验证是否提供了所有的3个数字)。

英文:

Firstly, lets mention that Premature Optimization Is the Root of All Evil

Having mentioned that, if you still want to get your user input through the stdin, you could asks your user to provide his numbers at once.
e.g

"Provide your numbers seperated by ,"

And then, after using scanner.nextLine() you can split the line and get your numbers (and validate that all 3 numbers were given).

答案3

得分: 0

[构建者模式][2]可选择使用[Project Lombok][1]

    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]: https://projectlombok.org/
  [2]: https://en.wikipedia.org/wiki/Builder_pattern#:~:text=The%20builder%20pattern%20is%20a,Gang%20of%20Four%20design%20patterns.
英文:

Builder pattern and optionally Project Lombok are your friends!

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;
}

Another option is to put Scanner directly to the constructor (but this is NOT GOOD from Object Design Principles)

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();
}
}

huangapple
  • 本文由 发表于 2020年9月11日 14:58:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63842203.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定