Some Java Practice
Let’s move beyond our “Hello, World” example and explore a simple temperature conversion program. We want our function to convert a Fahrenheit temperature to Celsius.
Temperature Conversion
Open the
TempConverter
file in thejava-web-dev-projects/datatypes/datatypes-examples
project in IntelliJ. Click through the folders until you find theTempConverter
class.Here’s what the file should look like. We will analyze the different statements in a moment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
import java.util.Scanner; public class TempConverter { public static void main(String[] args) { double fahrenheit; double celsius; Scanner input; input = new Scanner(System.in); System.out.println("Enter the temperature in Fahrenheit: "); fahrenheit = input.nextDouble(); input.close(); celsius = (fahrenheit - 32) * 5/9; System.out.println("The temperature in Celsius is: " + celsius + "°C"); } }
Build and run the program to verify that it works. Entering a Fahrenheit temperature of 212 yields the result,
The temperature in Celsius is: 100.0°C
.
There are several new concepts introduced in this example. We will look at them in the following order:
- Java
package
- The
import
statement - Declaring variables
- Collecting input with the Scanner class
Java Packages
Line 1 of the program above, package org.launchcode.java.demos.lsn1datatypes;
declares the package in which the file resides. For this simple program, your code could run without this line. However, you want to get used to always declaring the package of your Java classes.
Packages help to encapsulate your code. Encapsulation refers to the practice of shielding your code from outside influences. It’s an essential component of good object oriented programming, and package declaration in Java is just one application of this principle. Without declaring a package, a Java class exists within the default package. In larger applications, leaving all classes in the default package risks naming conflicts and bugs.
import
The import
statement in Java allows us to access the class, methods, and data stored in a different file. import
tells the compiler that we are going to use a shortened version of the class name. In this example, we are going to use the class java.util.Scanner
, but we can refer to it as just Scanner
. We could use the java.util.Scanner
class without any problem and without any import statement, provided that we always refer to it by its full name.
This idea bears repeating. In Java, you can use any available class WITHOUT having to import it, but you must use the full name of the class. “Available” classes include:
- All the classes you define in the
.java
and.class
files in your current working directory. - All the classes that get shipped with the software.
In the sample code, remove the import
statement in line 3, and change Scanner
on lines 9 & 11 to java.util.Scanner
. The program should still compile and run.
The class naming system in Java is very hierarchical. The full name of the Scanner
class is really java.util.Scanner
. You can think of this name as having two parts:
java.util
is called the package,Scanner
is the class name.
We’ll talk more about the class naming system a bit later.
Declaring Variables
In the example above, lines 7 - 9 contain variable declarations:
|
|
Since Java is a statically typed language, we must always declare the data type for any variable. Lines 7 & 8 establish that fahrenheit
and celsius
will hold values of type double
. In line 9, the variable input references a Scanner
object.
If later in the code we try to initialize fahrenheit
with a string:
fahrenheit = "xyz"
The compiler throws an error because fahrenheit
is declared to be a double.
The following error is common for new Java programmers. Suppose we forget to include the declaration for celsius
. What happens when we try to compile and run our program?
Edit your
TempConverter
class by removing line 8, which declares the variablecelsius
.Click any of the “Run” options in IntelliJ. Alternatively, use the terminal to navigate to the parent directory of your
TempConverter.java
class and runjava TempConverter.java
.
Your terminal will return some errors that resemble these:
Error:(16, 9) java: cannot find symbol
symbol: variable celsius
location: class TempConverter
Error:(17, 64) java: cannot find symbol
symbol: variable celsius
location: class TempConverter
These two compiler errors occur before the program runs. The values in the parentheses ()
give the line number and text column where the error was found. In the first description (line 16, column 9), the celsius
variable before the = is flagged. When this type of error happens, it usually means that the variable was not declared before we tried to initialize it with a value.
The second error message (line 17, column 64) occurs because we use celsius
before it has been assigned a value.
When using an IDE such as IntelliJ, your work is typically checked by the IDEs built-in compiler as you write your code. Errors are often visually indicated by the IDE as you type. This avoids having to explicitly compile your code before finding errors. Nice, huh?
The general rule in Java is that you must decide on the data type for your variable first, and then declare that variable before you use it. There is much more to say about the static typing of Java, but for now this is enough.
As in other languages, Java allows you to declare and initialize your variables in the same line:
double celsius = (fahrenheit - 32) * 5/9;
Add Comments to Your Code
As programs get bigger and more complicated, they get more difficult to read. Good programmers try to make their code understandable to others, but it is still tricky to look at a large program and figure out what it is doing and why.
Also, there are times when programmers need to isolate or ignore certain portions of their code as they are testing it. In the “Try It” box above, you were instructed to remove a line of code in order to create compiler errors. However, programmers are usually reluctant to delete lines that they might need to bring back.
Best practice encourages us to add comments to our programs. These are notes that clearly explain what the code is doing.
A comment is text within a program intended only for a human reader—–it is completely ignored by the compiler or interpreter. In Java, the //
token indicates the start of a comment, and the rest of the line gets ignored. For comments that stretch over multiple lines, the text falls between the symbols /* */
.
Comments can also be used to temporarily skip a portion of the code when a program runs. Instead of removing double celsius;
in TempConverter
, we could comment out the line. This would create the same compiler errors we wanted to witness, but it would preserve the original code and allow us to easily reactivate it by removing the //
token from the line.
|
|
Collect Input with the Scanner
Class
In Java, Scanner
objects make getting input from the user, a file, or even over the network relatively easy. For our temperature conversion program, we declared the variable input
to be of type Scanner
.
|
|
We want our program to prompt the user to enter in a number in the command line. We accomplish this by creating a Scanner
instance using the word new and then calling the constructor and passing it the System.in
object:
|
|
Notice that this Scanner
object is assigned to the name input
, which we declared to be a Scanner
object earlier.
And you know those System
statements we’ve been using? Like System.in
above here, and System.out.println()
for print statements. Well, System itself is a java class. System.in
is similar to System.out
except, as the name implies, it is used for input.
If you are wondering why we must create a Scanner
object to read data from System.in
when we can write data directly to System.out
using println
, you are not alone. We will talk about the reasons why this is so when we dive into Java streams.
Next, line 12 asks the user to enter a number, and in line 13 we use input to read the value from the command line:
|
|
Here again we see the implications of Java being a strongly typed language. Notice that we must call the method nextDouble
, because the variable fahrenheit
was declared as a double
.
Because Java is a statically typed language, we must call the appropriate method on the Scanner
object to ensure the entered data is of the correct type. In this case, the compiler compares the types for fahrenheit
and input.nextDouble()
and throws an error if the two do not match.
The table below shows some commonly used methods of the Scanner
class. There are many others supported by this class, and the Oracle website
provides a complete listing of the Scanner
methods.
Scanner
methods
Method Name | Return Type | Description |
---|---|---|
hasNext() | boolean | Returns true if more data is present |
hasNextInt() | boolean | Returns true if the next item to read is an int data type |
hasNextFloat() | boolean | Returns true if the next item to read is a float data type |
hasNextDouble() | boolean | Returns true if the next item to read is a double data type |
nextInt() | int | Returns the next item to read as an int data type |
nextFloat() | float | Returns the next item to read as a float data type |
nextDouble() | double | Returns the next item to read as a double data type |
next() | String | Returns the next item to read as a String data type |
nextLine() | String | Returns the next line to read as a String data type |
Closing Scanner
To collect data from the command line or other source, create a Scanner
object. This opens up resources in your machine to manage the input, and these resources remain open even after the required data is loaded into your program.
Leaving a Scanner
open is like keeping a window open in your house 24/7. Anyone can climb into your home, and you lose $$$ by trying to heat and cool your space while it is open to the outside air. Similarly, an open Scanner
can allow unintended access to your program, and it ties up resources that might be needed elsewhere.
Best practice states that if you open a Scanner
object, close it after it finishes its job. Line 14 does this in our TempConverter
program:
|
|
The general syntax is scannerObjectName.close()
.
Moving Beyond the Command Line
The Scanner
class serves as a kind of adapter that gathers primitive data types as input and converts them into object types (e.g. it converts an int
into Integer
). We will discuss the purpose of this later, but for now, know that this adaptation makes low-level data types easier to use.
For the temperature conversion program, we collected user input from the command line, but there are other options for collecting data for our programs. In future examples, we will create a Scanner
object by passing a File
object as a parameter instead of System.in
.
Check Your Understanding
True/False: An import statement is required to use a Java class defined in another package.
Which of the following Scanner
methods should you use to return an expected String
input? Check ALL that apply.
.hasNext()
.nextLine()
.next()
.nextFloat()