Lessons from a Month Learning Java
Alex Ortiz
Posted on August 23, 2020
I started learning Java a month ago. Here are five simple programs I've written. I'll use these as hooks to share what I've learned in that time.
Program Table Of Contents
Program 1: Two Languages
Program 2: Even Odd While Loop
Program 3: The Nth Letter of the Alphabet
Program 4: Combine Two Arrays
Program 5: Prime Checker
Program 1: Two Languages
This program prints one of two sentences, depending on which programming language I specify: "python" or "java".
/*
A program that prints a different sentence depending on which of two predefined programming languages the user inputs.
*/
import java.util.Scanner; // import the Scanner class
class TwoLanguages {
public static void main(String[] args) { // program execution begins
String python = new String(); // declare the python variable
python = "Python"; // define the python variable
String java = new String(); // declare the java variable
java = "Java"; // define the java variable
Scanner keyboardInput1 = new Scanner(System.in); // declare a Scanner object to accept user input
System.out.println("Which language are you asking about?"); // prompt the user for input
String i = keyboardInput1.nextLine(); // declare a variable for storing the user's input
// An if-else-if ladder to determine the program's response.
if (i.equalsIgnoreCase("Python")) {
System.out.println("Python is a great language for newcomers to programming! It's easy to pick up and has a huge developer community surrounding it.");
}
else if (i.equalsIgnoreCase("Java")) {
System.out.println("Java is a language after my own heart; my brain `gets` it! I think it will serve me well in the 2020s for the scientific work I want to do.");
}
else {
System.out.println("The program doesn't understand. Please try again.");
}
}
}
The code above is in a .java
file named TwoLanguages.java
. That code is uncompiled, so I can't run it on my computer. The computer doesn't understand words written in English, it understands machine code. So I need to compile my program into something the computer can work with.
To do that, I run the command javac TwoLanguages.java
from my Terminal. This compiles the Java code into bytecode, which is one step removed from the machine code my computer can understand. Then I can run my program with the command java TwoLanguages
.
There are really three things going on here:
(1) The Java compiler (
javac
) takes.java
files as input and converts them to.class
files as output. The.java
file is the uncompiled code. The.class
file is the compiled (byte)code.(2)(3) When I run
java TwoLanguages
, what I'm doing is telling my machine (via thejava
interpreter) to convert the bytecode into machine code and then execute that machine code on the Java Virtual Machine installed on my computer. So there are two conversion steps and one execution step. Only then does my computer do what I expect it to do based on my program.
My Expected Output
When I run java TwoLanguages
from my terminal, I expect it to ask me a question:
"Which language are you asking about?"
I'll then be able to type in one of two words, which I already know are "python" and "java". Depending on which word I enter, the program will print a different statement. If I enter something other than "python" or "java", my program will tell me that it doesn't understand and ask me to try again.
Example Outputs
Example 1:
java TwoLanguages
Which language are you asking about?
python
Python is a great language for newcomers to programming! It's easy to pick up and has a huge developer community surrounding it.
Example 2:
java TwoLanguages
Which language are you asking about?
java
Java is a language after my own heart; my brain `gets` it! I think it will serve me well in the 2020s for the scientific work I want to do.
Example 3:
java TwoLanguages
Which language are you asking about?
blah
The program doesn't understand. Please try again.
Awesome!
Notes
Workflow
- I write my programs in
Atom
. I've tried IDEs, like IntelliJ. But for where I am in my learning process, Atom is perfect - I'm using my command line for compilation and execution commands. So
javac TwoLanguages.java
,java TwoLanguages
, and my user input all go through my Terminal - When I need to rapidly prototype a line of code, I use the ever-handy
jshell
Code
- The line
Scanner keyboardInput1 = new Scanner(System.in);
is critical to how this program works. It declares an object (keyboardInput1
) of theScanner
class. The Scanner class lets the program read text input by the user or stored in a file. In this case, I useSystem.in
to inform the program that my Scanner object is going to read from standard input - The line
String i = keyboardInput1.nextLine();
tells the program to read the string the user enters (when pressingEnter
) and "store" that string in an object namedi
-
nextLine()
isn't strictly necessary here; I could also have usednext()
for this particular scenario - When I enter my word, the case doesn't matter. I can type with lowercase, uppercase, sentence case, camelCase, or any other case. So "java", "JAVA", "Java", and "jAva" all work. That's because my code uses the
equalsIgnoreCase()
method:i.equalsIgnoreCase("Java")
. Whatever I type into the terminal is stored ini
, and theequalsIgnoreCase()
method tells the program to evaluate the word regardless of its case. Had I usedequals()
instead ofequalsIgnoreCase()
, the program would have only worked as intended if I typed "Java" exactly
Program 2: Even Odd While Loop
This program prints all integers from zero to ten (inclusive) and tells me if each number is even or odd.
/*
A program that prints even and odd numbers from zero to ten using a while loop with a nested if statement.
*/
class EvenOddWhileLoop {
public static void main(String[] args) {
int x = 0; // a variable to store the starting point, the integer 0
while (x < 11) { // set a max of x = 10
if (x % 2 == 0) { // if dividing by two leaves no remainder
System.out.println(x + " is an even number.");
x++; // increment the current value of x by 1
}
else {
System.out.println(x + " is an odd number.");
x++; // increment the current value of x by 1
}
}
}
}
My Expected Output
When I run my EvenOddWhileLoop
program, I expect it to print the numbers "0" to "10" and tell me if each number is an even number or an odd number.
Example Output
java EvenOddWhileLoop
0 is an even number.
1 is an odd number.
2 is an even number.
3 is an odd number.
4 is an even number.
5 is an odd number.
6 is an even number.
7 is an odd number.
8 is an even number.
9 is an odd number.
10 is an even number.
It worked!
Notes
Workflow
- I found it useful to think about what I want the program to do, before I sat down to code the program. Visualizing the code that I'd type, before I wrote it in Atom, was a fun way to engage my brain on what problem I was actually trying to solve. The coding itself was then faster. This is a habit I'll keep as I learn more Java
Code
- I could have also set the max value with
while (x <= 10)
. Butwhile (x < 11)
is more economical - This combo of an
if
statement nested within awhile loop
is versatile. The innerif
portion tells the program what action to take on every number. The outerwhile
portion tells the program when to stop attempting further action (whenx = 10
, in this case) - I use the modulus operator
%
along with the relational operatorequal to
(==
) as a proxy for the condition "is even". Sox % 2 == 0
is how I tell the program that ifx
has no remainder when divided by2
, thenx
is an even number. (Read aloud, the fullif
statementif (x % 2 == 0)...{System.out.println(x + " is an even number.");
is "If x modulo 2 is equal to zero, print the statement. x " is an even number.") - Each value falls into one of only two possible categories: even or odd. So the
else
clause is simpler than theif
clause and doesn't require a condition within parentheses. The reason is that if the current value ofx
fails to qualify as even, then it must be odd. With this insight, there's probably a way to use theboolean
data type, but I didn't think of that when writing the program - With the lines
int x = 0; ...while (x < 11)...
, my program predefines the half-open interval[0,11)
. A more flexible, hands-on approach is to use theScanner
class to read values from standard input viaSystem.in
like with Program #1 (TwoLanguages
). Below is a modified version ofEvenOddWhileLoop
that allows the user to enter minimum and maximum values to define a custom closed interval,[a,b]
:
/*
A program that accepts user input for the minimum and maximum values in an arbitrary integer interval, then prints the numbers and specifies if they are even or odd.
*/
import java.util.Scanner;
class CustomEvenOddWhileLoop {
public static void main(String[] args) {
Scanner lowerBound = new Scanner(System.in);
System.out.println("Enter a minimum:");
int a = lowerBound.nextInt(); // a variable to store the lower bound of the interval
Scanner upperBound = new Scanner(System.in);
System.out.println("Enter a maximum:");
int b = upperBound.nextInt(); // a variable to store the upper bound of the interval
while (a <= b) { // i.e., set a max of a = b
if (a % 2 == 0) { // if dividing by 2 leaves no remainder
System.out.println(a + " is an even number.");
a++;
}
else {
System.out.println(a + " is an odd number.");
a++;
}
}
}
}
This modified program will prompt me to enter a minimum value and enter a maximum value, then print the results:
java CustomEvenOddWhileLoop
Enter a minimum:
2
Enter a maximum:
6
2 is an even number.
3 is an odd number.
4 is an even number.
5 is an odd number.
6 is an even number.
As expected, this program prompted me to enter a minimum value. I entered 2
. Then it prompted me to enter a maximum value. I supplied 6
. The program then ran as intended.
I noticed that I didn't need to specify a starting point in my code this time, in contrast to int x = 0;
in the original, EvenOddWhileLoop
. Instead, my lowerBound
variable serves as the de facto starting point here: e.g., 2
.
There are two gotchas with these programs, EvenOddWhileLoop
and CustomEvenOddWhileLoop
:
If I input a decimal value, such as
2.0
or6.0
, there will be an error. The program will halt with anInputMismatchException
exception. I don't yet know enough to add atry/catch
block to my program, but I can picture that being useful here to redirect the user with a custom error statement such as, "You entered a decimal value; try again with an integer."With the
CustomEvenOddWhileLoop
program, it would seem that the user can enter arbitrary integer values, but that's not quite the case. The program uses the data typeint
(for integer). Integer data takes up a certain amount of space in memory (32 bits, or 4 bytes, to be specific). In Java, integers can range from -2,147,483,648 to 2,147,483,647. So any integer value smaller than -2,147,483,648 or larger than 2,147,483,647 is disallowed for theint
type. That's because such values take up more than 32 bits of space in memory. So if I input the value3,333,333,333
, I will get anInputMismatchException
exception too. A value of that size requires the data typelong
, which can handle 64-bit integer values. If I wanted to do that, the fix would be simple enough: replace typeint
with typelong
and the.nextInt()
method with the.nextLong()
method in my code. The altered program would then accept any value sized 64 bits or smaller, and3,333,333,333
would work just fine
Program 3: The Nth Letter of the Alphabet
This program prints the letters a
through z
. The program also specifies the numerical order of the letters.
/*
A program that prints the letters of the English alphabet along with their ordinals, using a while loop with a nested if-else-if ladder.
*/
class TheNthLetterOfTheAlphabet {
public static void main(String[] args) {
// An array to store the letters of the alphabet.
String alphabet[] = {"a","b","c","d","e","f","g","h","i","h","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
int n = 1; // to track which letter the program will print
while (n < 28) { // i.e., until the 27th letter is reached
//
if (n == 1 || n == 21) {
System.out.println("The " + n + "st letter of the alphabet is " + alphabet[n-1] + ".");
}
else if (n == 2 || n == 22) {
System.out.println("The " + n + "nd letter of the alphabet is " + alphabet[n-1] + ".");
}
else if (n == 3 || n == 23) {
System.out.println("The " + n + "rd letter of the alphabet is " + alphabet[n-1] + ".");
}
else {
System.out.println("The " + n + "th letter of the alphabet is " + alphabet[n-1] + ".");
}
n++;
}
}
}
My Expected Output
When I run java TheNthLetterOfTheAlphabet
, I expect to see a printout of twenty-seven sentences, one for each letter, a
to z
, in order. Each sentences will specify the ordinal number and ordinal indicator corresponding with that letter (i.e., "The 1st letter of the alphabet is...", etc).
Example Output
java TheNthLetterOfTheAlphabet
The 1st letter of the alphabet is a.
The 2nd letter of the alphabet is b.
The 3rd letter of the alphabet is c.
The 4th letter of the alphabet is d.
The 5th letter of the alphabet is e.
The 6th letter of the alphabet is f.
The 7th letter of the alphabet is g.
The 8th letter of the alphabet is h.
The 9th letter of the alphabet is i.
The 10th letter of the alphabet is h.
The 11th letter of the alphabet is j.
The 12th letter of the alphabet is k.
The 13th letter of the alphabet is l.
The 14th letter of the alphabet is m.
The 15th letter of the alphabet is n.
The 16th letter of the alphabet is o.
The 17th letter of the alphabet is p.
The 18th letter of the alphabet is q.
The 19th letter of the alphabet is r.
The 20th letter of the alphabet is s.
The 21st letter of the alphabet is t.
The 22nd letter of the alphabet is u.
The 23rd letter of the alphabet is v.
The 24th letter of the alphabet is w.
The 25th letter of the alphabet is x.
The 26th letter of the alphabet is y.
The 27th letter of the alphabet is z.
I was amazed by TheNthLetterOfTheAlphabet
the first time I ran the program. It's simple yet delightful. But this delight required some prep work.
Notes
Workflow
- The key ingredient in this program is the combo of two things:
- the
if-else-if ladder
, and - the
logical or
operator (||
)
- the
- This combo makes it possible for the program to select the correct ordinal statement corresponding with each letter. For example,
- the first and twenty-first letters have the "-st" ordinal indicator as a suffix
- the second and twenty-second letters have "-nd"
- the third and twenty-third letters have "-rd"
- The remaining 21 letters have "-th" (i.e., 4th, 5th, 6th...26th)
- It would have been tedious to specify 27 individualized print statements in my program. By combining the nested
if-else-if ladder
, the||
s, and a few simple conditions, the program can handle that mapping for me. This required a little bit of upfront thinking to get the code just right
Code
- I create an array,
alphabet[]
, in which to store the letters of the alphabet asString
variables - Arrays are zero-indexed, meaning that the position of the first object in the array is position [0], not position [1]. For example, the first letter,
a
, is in positionalphabet[0]
. This becomes important in the next few lines of code - The variable
n
lets my program keep track of which letter to make a decision on when the program reaches theif-else-if ladder
. Then
represents the ordinal of each letter, not the index of the letter in the array: i.e.,n = 1
refers to lettera
;n = 2
represents letterb
; and so on - The array itself is 0-indexed, but my code is more human-readable if I initialize
n
asn = 1
rather thann = 0
. The trade-off is that in my print statements, I have to subtract 1 fromn
to access the correct variable: soalphabet[n-1]
isalphabet[0]
, which returns lettera
. This trade-off is worthwhile, though: the conditions in theif
andelse if
statements are easier to understand this way - The print statements concatenate three things: sentence fragments, letter ordinals, and array indices, like so:
"The " + n + "st letter of the alphabet is " + alphabet[n-1] + "."
Program 4: Combine Two Arrays
This program will combine two arrays into one and print its contents as a list.
/*
A program that combines two arrays into a third array and prints its elements.
*/
class CombineTwoArrays {
public static void main(String[] args) {
String array1[] = {"a","b","c"}; // declare and define the first array
String array2[] = {"d","e","f"}; // declare and define the second array
// A third array created by the program using the first two arrays as input.
String array3[] = {array1[0], array1[1], array1[2], array2[0], array2[1], array2[2]};
int x = array1.length + array2.length; // for use in the while loop condition below
int y = 0; // a starting point for the while loop condition below
while (y < x) {
System.out.println(array3[y]); // print the members of array3
y++;
}
}
}
My Expected Output
When I run java CombineTwoArrays
, I expect the program to create an array containing the combined elements of the first two arrays. I also expect the program to print the elements a
through e
, i.e., print the six elements now stored inside the third array.
Example Output
java CombineTwoArrays
a
b
c
d
e
f
Nice.
Notes
Workflow
- Writing this program took some trial-and-error
- Initially, I thought that
.length
was a method, but it's not. It's just a variable. Soarray1.length()
would be incorrect. All I have to do is add.length
to the name of the array, and that will retrieve the array's length (in the case ofarray1
, that would be3
) - Another learning for me was that to access an element of an array, I'm supposed to use the format
array[n]
, where n is the index of the element I want to retrieve. At first, I tried the formatarray.index[n]
, and this threw the errorcannot find symbol
. After a while, I learned why. Jshell was indispensible as I tried out different statements before correcting the code in myCombineTwoArrays.java
file
- Initially, I thought that
Code
- I don't yet know if there's a way or how to print all the members of an array without specifying the indices I want printed. So I rigged the program to print all members indirectly. For this to work, I had to set up the following:
- the variable
x
, to store the combined length of arrays 1 and 2 - the variable
y
, to use as a counter for mywhile loop
- the
while loop
itself with the conditiony < x
, to coordinate the control flow forprintln
-
array3[y]
as the parameter forprintln
- the variable
- The statement
int x = array1.length + array2.length
wasn't strictly necessary. I could have usedint x = array3.length
also. Or done away withx
altogether, replacing the condition withwhile (y < array3.length)
. That would have been simpler and would have produced the same output. But I took this learning opportunity to verify these three things:-
array1.length
andarray2.length
are indeed of typeint
, -
array1.length
andarray2.length
can indeed be summed without an intermediary variable -
array1.length
andarray2.length
do indeed lead to the same result as3 + 3 = 6
-
I find it amazing that I can piggyback off of existing objects to create new ones. I'm getting strong "g(x) = f(f(x))" vibes here. :)
Program 5: Prime Checker
My final program checks if a whole number input by the user is a prime number or not.
/*
A program to check if an integer number supplied by the user is or is not a prime number.
The maximum input value is 2_147_483_647.
*/
import java.util.Scanner;
class PrimeDetector {
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
System.out.println("Enter an integer to check if it is a prime number:"); // ask the user for an integer to check
int i = userInput.nextInt(); // store the user's integer in the i variable
if (i <= 0) { // prime numbers can't be negative or zero
System.out.println("The number "+ i + " is not a prime number.");
}
else if (i == 2 || i == 3 || i == 5 || i == 7){ // single-digit prime numbers
System.out.println("The number "+ i + " is a prime number.");
}
// The number "1" or any number divisible by "2", "3", "5", "7", or "9" cannot be prime.
else if (i != 1 // the number "1" is by definition not a prime
&& i % 2 != 0
&& i % 3 != 0
&& i % 5 != 0
&& i % 7 != 0
&& i % 9 != 0) { // a redundant condition that does not harm the program
System.out.println("The number "+ i + " is a prime number.");
}
else {
System.out.println("The number "+ i + " is not a prime number.");
}
}
}
My Expected Output
When I run java PrimeDetector
on my terminal, I expect this prompt:
"Enter an integer to check if it is a prime number:"
So long as I type an integer value allowable for type int
, the program will tell me if the number is a prime number or if the number is not a prime number.
Example Outputs
Example 1:
java PrimeDetector
Enter an integer to check if it is a prime number:
11
The number 11 is a prime number.
Example 2:
java PrimeDetector
Enter an integer to check if it is a prime number:
55
The number 55 is not a prime number.
Example 3:
java PrimeDetector
Enter an integer to check if it is a prime number:
2147483647
The number 2147483647 is a prime number.
Notes
Workflow
- I tried but couldn't find a way to exclude the condition
else if (i == 2 || i == 3 || i == 5 || i == 7)
from my code. It's a verbose condition. But without it, the program evaluates that "2", "3", "5", and "7" are not prime numbers, because of the way I structure the follow-up modulus conditions. This would be correct program execution but be incorrect factually. What I need is a condition that translates to "ifi
modulo 2 is zero, theni
is not a prime number, except ifi
itself is 2." So I have more to learn
Code
- As with Program #1 (
TwoLanguages
) and Program #3 (TheNthLetterOfTheAlphabet
), theif-else-if ladder
proves to be, yet again, so useful! With just a handful of rules, this program can check the prime number status for every single integer from "0" to "2,147,483,647", which is outright bedazzling
With some modifications, the program could in fact check the prime status of numbers "0" through "2,147,483,647":
- remove the Scanner package, Scanner object, and prompt;
- replace
int i = userInput.nextInt();
withint i = 0;
; - add a
while loop
with the conditionwhile (i <= 2_147_483_647)
, and move theif-else-if ladder
inside thewhile loop
; and - add the counter
i++;
to the bottom of that while loop
With those changes, running PrimeDetector
checks the prime status of every integer from 0 to 2,147,483,647, inclusive. It would take the program over an hour to evaluate all 2.1 billion values, but it could do it. Thank goodness for Control + C
to terminate long-lived programs!
Code (continued)
- IDEs like IntelliJ have something called "chained method calls". It's a simple indentation technique to neatly display code when a line of code has a lot of method calls for the same object. Analogously, I chained my
logical ands
(&&
) above, indenting them so that my code appeared neater. I could have left all my&&
operators on one line for the secondif else
statement, but I preferred the visual cleanliness of indenting them - In retrospect, the condition
&& i % 9 != 0
is redundant and can be removed, because any number divisible by "9" is also divisible by "3" and would already satisfy the conditioni % 3 != 0
. I realized that while writing this, so I left the "9" conditional in as a harmless quirk - I suspect that there's a way to write this program with fewer lines of code, so I'll have to practice working with logical operators with Java to see if that illuminates the way
- As with Program #2 (
EvenOddWhileLoop
), there's an opportunity to add atry/catch
block to this program with a custom statement to handleInputMismatchException
errors. For example, if I type a decimal value into the command line, e.g.,11.0
, instead of11
, Java will rightfully complain, and the program won't complete. Without thetry/catch
block, the user might not realize what mistake they've made.
Wrap-up
And that's that for my five programs:
TwoLanguages
-
EvenOddWhileLoop
(andCustomEvenOddWhileLoop
) TheNthLetterOfTheAlphabet
CombineTwoArrays
PrimeDetector
I wrote the programs towards the end of my first month learning Java. It was a signal that my brain had begun to make sense of what I've learned in the last four weeks about Java syntax, packages, classes, variables, data types, arrays, relational and logical operators, conditional statements, control flow, print statements, Scanner objects, compilation, execution, bugs, and writing code. Writing about them has been a great way to review all this.
Next Up: Entering Month Two of My Learnings
I'm entering my second month of learning. It's exciting to know that I've only learned 0.001% of what there is to learn about Java. For example, I know enough to have written the five programs above in the last week. I knew enough to troubleshoot the many errors that came up as I was coding these. I knew enough to research solutions in my books and online when I got stuck.
But I don't even yet have a foundation in Java fundamentals! Herbert Schildt's 700-page Java: A Beginner's Guide is staring me in the face waiting for me to really read it, as I've only read about 20 pages' worth of it. And that book doesn't even cover all there is to know (there's nothing in it about ArrayLists
, as just one example).
Zooming out further, the Java ecosystem is immense: there's Spring for app development, Maven for dependency management, Hibernate for dealing with data, Spring Boot for making microservices, J2EE and its many APIs for enterprise app development...and that is still not all there is to learn about Java!
But I'm on my way.
Posted on August 23, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.