3

Im still learning and have noticed many inconsistencies when it comes to coding. I take it Java is pretty much like Photoshop in the way that a single task can be done many different ways and still have the job done.

One of my main questions is when it comes to Scanner and Random.

In one source they have Scanner in the scope of the whole class

public class test {
    private static Scanner input = new Scanner(System.in);
}

In another source they have it like this

public class test {
   private static Scanner input;

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

What is the difference with this? Is there a right way and a wrong way?

user3079061
  • 229
  • 4
  • 12
  • 2
    Please note that there is no much difference between the two examples. input is scoped the whole class in both cases. – gd1 Jan 08 '14 at 22:12
  • But a difference would be if I was to call private static Scanner input = new Scanner(system.in) inside of a method. It would make it so once that method is called the object is made and then after the method finishes it would then be handled with GC, right? – user3079061 Jan 08 '14 at 22:15
  • You don't write "private static Scanner input = ..." within a method, "Scanner input = ..." will do. I suggest you to read the Java trails and proceed step by step. – gd1 Jan 08 '14 at 22:17
  • 1
    Example 2 only works, when this class is used as a program starting point (main method is called), otherwise input never gets instantiated, which could possibly be unflexible, if you want to use this class (simple wrapper to read a file for example) as a library in another project. Because its static, there is no other way as in example one to instantiate a class property in a reliable way. – Jürgen Zornig Jan 08 '14 at 22:18
  • I sort of have the same question as OP. I never really understood the difference between initiating an object in the constructor or doing it when you declare it as a field. – Embattled Swag Jan 08 '14 at 22:19
  • So, Jurgen Zornig, I should be calling the Scanner inside of main instead of making it a private static, correct? – user3079061 Jan 08 '14 at 22:20
  • @Embattled the property is static, which means its a class property. There is no constructor for classes, only for objects. – Jürgen Zornig Jan 08 '14 at 22:20
  • possible duplicate of [Best Practice: Initialize class fields in constructor or at declaration?](http://stackoverflow.com/questions/24551/best-practice-initialize-class-fields-in-constructor-or-at-declaration) – Embattled Swag Jan 08 '14 at 22:20
  • @EmbattledSwag In this case, it's not being initialized inside the constructor... and can't be since it's a `static` variable, which belongs to the class itself instead of an instance of the class. – Powerlord Jan 08 '14 at 22:23
  • @Powerlord I understand in the examples OP posted it's different, but what I'm referencing in my first comment is what's in the question of the duplicate I found. – Embattled Swag Jan 08 '14 at 22:24
  • @user3079061 That depends if you need scanner as a classproperty (=static) in the whole scope of the class (=private) or outside of it (=protected or public), or if it should be a field of an object ( then instantiate in the constructor), or if it should only be accessible in the main method (then it shouldn be a field anyway, but a local variable in the scope of the main method) – Jürgen Zornig Jan 08 '14 at 22:25
  • So, if I am doing something very simple. No methods besides main. Where should Scanner and/or Random be located? – user3079061 Jan 08 '14 at 22:28
  • With no other methods in the class its enough (its intended) to declare scanner and/or random as local variables in the main method. – Jürgen Zornig Jan 08 '14 at 22:29
  • @JürgenZornig awesome! I had a feeling that it would be like that. Another question, just trying to wrap my head around it. If I have multiple methods that use Scanner/Random, should I then declare it in each method or once in the class? – user3079061 Jan 08 '14 at 22:30
  • 1
    then you should declare it in the scope of the class, instatiate only once (if it really is the same scanner for sure) and then use itin your methods. Scanner is shared then... – Jürgen Zornig Jan 08 '14 at 22:33

4 Answers4

1

There is a difference here!

If you want to access your scanner without invoking any method, then place it in field or static block.

Your example

private static Scanner input = new Scanner(System.in);

is only equal to this

private static Scanner input;

static {
   input = new Scanner(System.in);
}

Initialization time is different. Method main is special method in which this is not visible, because this method start your program ;)

MariuszS
  • 30,646
  • 12
  • 114
  • 155
  • With non-static (dynamic/instanced) variables this would not be the case, as the values would be initialized in both cases upon construction. But for static it holds. – SpacePrez Jan 08 '14 at 22:27
1

The two ways you've initialized the Scanner are similar, but not quite the same.

The first always works because you're initializing the static variable when it's being created.

The second only works when test is the startup class, because public static void main(String[] args) is always called in an application's startup class.

The problem arises if you try to use a method of the test class from another class, like this:

public class test {
   private static Scanner input;

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

   public static void myMethod() {
       input.hasNext();
   }
}

and in a separate file

public class AnotherTest {
    public static void main(String[] args) {
        test.myMethod();
    }
}

As soon as you run java AnotherTest, it will bomb with a NullPointerException on the input.hasNext() because test's main is never run and thus input is never initialized.

Edit: Side note, class names in Java are almost always capitalized.

Powerlord
  • 87,612
  • 17
  • 125
  • 175
  • Incidentally, this is avoiding non-static variables and methods to make this example simpler. non-static variables would involve initializing variables in the class constructors as well. – Powerlord Jan 08 '14 at 22:31
  • Best sum up of discussion above ;) – Jürgen Zornig Jan 08 '14 at 22:36
  • This is so confusing.... I have been stuck on this whole initalizing since I started learning in my free time. Would a way to make it work properly be creating an object of test inside of AnotherTest, or is that completely off? – user3079061 Jan 08 '14 at 22:38
  • Scanner then would only exist one time (as class variable in the class test) also when you create millions of test objects.... thats what static means. If you delete the keyword "static" and init scanner in the constructor, every test object would have it's own scanner – Jürgen Zornig Jan 08 '14 at 22:44
1

You are right, there are for sure many ways to do things and all of them might solve the problem equally good for some use cases.

In your example code, the only difference is basically at what time in the class lifecycle the static variable gets a value declared to it, the scanner-object.

Think of statics to be a part of the class, the template, rather than the object that is constructed with the class as a template of how it should look and function.

I would believe that there are two good reasons for when you need to think of where and when you are initiating your variables. One is when it comes to thread safety. " is it ok for several threads to be able to access the very same class-member, the scanner? ". A variable declared inside of a method is not accessible outside the method and it isn't accessible by any other threads either.

The other reason is design and structure. We all want to have code that like good and is easy to read and understand. Which is more clear for someone reading your code?

Of course, the thread safety-matter has to be considered before thinking of the design and structure. Just because it would be easier to read some code when all variables are declared at a class level, it doesn't necessarily have to be written like that if it makes the application to fail.

Nadrendion
  • 247
  • 1
  • 7
0

Ultimately, the code you're writing is not what the computer executes when you run the program. If it was an interpreted language like Python or Lua that would be the case, but with a compiled language (not getting involved in the ways Java is special) the language is actually completely converted by the compiler program into an entirely different program in machine code.

As a result, in many cases you can write things several different ways that the compiler will end up writing out as machine code the same way.

There is a distinction here with static variables, as they are initialized immediately, but otherwise the difference here is mostly one of style and appearance, don't worry about it too much. The compiler will understand both and produce largely the same code.

Un-initialized variables are set to defaults (null for objects) which are then set in the constructor, and it may be slightly more efficient to set them during the initialization.

Final values should be initialized, and static, but otherwise its mostly a matter of your preference.

SpacePrez
  • 1,086
  • 7
  • 15
  • Not completely right (as stated above). First: constructors are only called on object instantiation, so if you don't create an object, constructor is never called, and therefore the class variable isn't instantiated. Thats why its an bad idea to init a class variable in a constructor. Second: static variables are not initialized immediately if I do not do it (as in example 1). In example 2 it would be null, except when the main method is called....thats the point. – Jürgen Zornig Jan 08 '14 at 22:42
  • @JürgenZornig Class variables are static, I already said for static you want it that way. Instance variables it doesn't matter. – SpacePrez Jan 08 '14 at 22:45
  • Okay, sorry, then I didn't fully understand your answer as you intended it. – Jürgen Zornig Jan 08 '14 at 22:50