Lessons from a Month Learning Java
Tags: java
Published: 2020-08-23 01:47:29

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-1-two-languages)
       [Program 2: Even Odd While Loop](#program-2-even-odd-while-loop)
       [Program 3: The Nth Letter of the Alphabet](#program-3-the-nth-letter-of-the-alphabet)
       [Program 4: Combine Two Arrays](#program-4-combine-two-arrays)
       [Program 5: Prime Checker](#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".

```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 the `java` 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 the `Scanner` class. The Scanner class lets the program read text input by the user or stored in a file. In this case, I use `System.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 pressing `Enter`) and "store" that string in an object named `i`
- `nextLine()` isn't strictly necessary here; I could also have used `next()` 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 in `i`, and the `equalsIgnoreCase()` method tells the program to evaluate the word regardless of its case. Had I used `equals()` instead of `equalsIgnoreCase()`, 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.

```java
/*
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)`. But `while (x < 11)` is more economical
- This combo of an `if` statement nested within a `while loop` is versatile. The inner `if` portion tells the program what action to take on every number. The outer `while` portion tells the program when to stop attempting further action (when `x = 10`, in this case)
- I use the modulus operator `%` along with the relational operator `equal to` (`==`) as a proxy for the condition "is even". So `x % 2 == 0` is how I tell the program that if `x` has no remainder when divided by `2`, then `x` is an even number. (Read aloud, the full `if` statement `if (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 the `if` clause and doesn't require a condition within parentheses. The reason is that if the current value of `x` fails to qualify as even, then it must be odd. With this insight, there's probably a way to use the `boolean` 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 the `Scanner` class to read values from standard input via `System.in` like with Program #1 (`TwoLanguages`). Below is a modified version of `EvenOddWhileLoop` that allows the user to enter minimum and maximum values to define a custom closed interval, `[a,b]`:

```java
/*
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`:

  1. If I input a decimal value, such as `2.0` or `6.0`, there will be an error. The program will halt with an `InputMismatchException` exception. I don't yet know enough to add a `try/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."

  2. 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 type `int` (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 the `int` type. That's because such values take up more than 32 bits of space in memory. So if I input the value `3,333,333,333`, I will get an `InputMismatchException` exception too. A value of that size requires the data type `long`, which _can_ handle 64-bit integer values. If I wanted to do that, the fix would be simple enough: replace type `int` with type `long` and the `.nextInt()` method with the `.nextLong()` method in my code. The altered program would then accept any value sized 64 bits or smaller, and `3,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.

```java
/*
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 (`||`)
- 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 as `String` 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 position `alphabet[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 the `if-else-if ladder`. The `n` represents the ordinal of each letter, _not_ the index of the letter in the array: i.e., `n = 1` refers to letter `a`; `n = 2` represents letter `b`; and so on
- The array itself is 0-indexed, but my code is more human-readable if I initialize `n` as `n = 1` rather than `n = 0`. The trade-off is that in my print statements, I have to subtract 1 from `n` to access the correct variable: so `alphabet[n-1]` is `alphabet[0]`, which returns letter `a`. This trade-off is worthwhile, though: the conditions in the `if` and `else 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.

```java
/*
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. So `array1.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 of `array1`, that would be `3`)
  - 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 format `array.index[n]`, and this threw the error `cannot find symbol`. After a while, I learned why. Jshell was indispensible as I tried out different statements before correcting the code in my `CombineTwoArrays.java` file

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 my `while loop`
  - the `while loop` itself with the condition `y < x`, to coordinate the control flow for `println`
  - `array3[y]` as the parameter for `println`
- The statement `int x = array1.length + array2.length` wasn't strictly necessary. I could have used `int x = array3.length` also. Or done away with `x` altogether, replacing the condition with `while (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:
  1. `array1.length` and `array2.length` are indeed of type `int`,
  2. `array1.length` and `array2.length` can indeed be summed without an intermediary variable
  3. `array1.length` and `array2.length` do indeed lead to the same result as `3 + 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.

```java
/*
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 "if `i` modulo 2 is zero, then `i` is not a prime number, _except_ if `i` itself is 2." So I have more to learn

Code
- As with Program #1 (`TwoLanguages`) and Program #3 (`TheNthLetterOfTheAlphabet`), the `if-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":

1. remove the Scanner package, Scanner object, and prompt;
2. replace `int i = userInput.nextInt();` with `int i = 0;`;
3. add a `while loop` with the condition `while (i <= 2_147_483_647)`, and move the `if-else-if ladder` inside the `while loop`; and
4. 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 second `if 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 condition `i % 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 a `try/catch` block to this program with a custom statement to handle `InputMismatchException` errors. For example, if I type a decimal value into the command line, e.g., `11.0`, instead of `11`, Java will rightfully complain, and the program won't complete. Without the `try/catch` block, the user might not realize what mistake they've made.

---

## Wrap-up

And that's that for my five programs:

- `TwoLanguages`
- `EvenOddWhileLoop` (and `CustomEvenOddWhileLoop`)
- `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.

---

![Till next time.](https://dev-to-uploads.s3.amazonaws.com/i/s61lek6ocuhydhqfylnm.png)