Lessons from a Second Month Learning Java
Tags: java
Published: 2020-10-03 23:58:23

With two months under my belt learning Java, I've refactored the toy programs I wrote in [last month's post](https://dev.to/alexlearnsjava/lessons-from-a-month-learning-java-2djm). My goal here is to optimize my programs based on what I've learned in the last four weeks.

**Program Table Of Contents**
       [Refactored Program 1: Two Languages](#refactored-program-1-two-languages)
       [Refactored Program 2: Even Odd While Loop](#refactored-program-2-even-odd-while-loop)
       [Bonus Refactored Program 2: Custom Even Odd While Loop](#bonus-refactored-program-2-even-odd-while-loop)
       [Refactored Program 3: The Nth Letter of the Alphabet](#refactored-program-3-the-nth-letter-of-the-alphabet)
       [Refactored Program 4: Combine Two Arrays](#refactored-program-4-combine-two-arrays)
       [Refactored Program 5: Prime Detector](#refactored-program-5-prime-detector)
       [Wrap-up](#wrapup)


## Refactored Program 1: Two Languages<a name="refactored-program-1-two-languages"></a>

My [previous **TwoLanguages** program](https://dev.to/alexlearnsjava/lessons-from-a-month-learning-java-2djm#program-1-two-languages) was this:

```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.");
      }
    }
}
```

Here's the new one, **RefactoredTwoLanguages**:

```java
import java.util.Scanner;

/*
A program that prints a different sentence depending on which of two predefined programming languages the user inputs.
*/

class RefactoredTwoLanguages {
  public static void main(String[] args) {
    Scanner userInput = new Scanner(System.in);
    System.out.println("Would you like to know about Java or Python? (Type 'Java' or 'Python')");

    var i = userInput.nextLine().toLowerCase();

    switch(i) {
      case "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.");
      break;

      case "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.");
      break;

      default:
      System.out.println("Please re-run the program and enter a different language. The only valid values are `Java` or `Python` (not case-sensitive)");
      break;
    }
  }
}
```
---

### Refactored Code Summary
Here's what the compiler does in this program:

- Import the package `java.util.Scanner`
- Begin program execution
- Create a `Scanner` class object to accept user input via the keyboard
- Print a prompt displaying a question for the user and wait for the user to type an input
- Create a variable, `i`, to store whatever the user types, automatically converting it into all lowercase; moreover, the compiler will infer the data type based on the user's entry
- Evaluate the entry stored in `i`:
  - If it's "java", print the corresponding statement
  - If it's "python", print the corresponding statement
  - If it's anything else, print the corresponding default statement
- Exit the program

### Old vs New: What's Changed
First, here's a summary of the changes:

CHANGE LOG

* Moved the _import statement_ to the top of the file
* Removed two unnecessary `String` variable declarations and instantiations
* Made a minor tweak to the `Scanner` variable name
* Reworded the print statement which prompts the user for a language
* Made variable `i` a variable of type `var`
* Added a chained method, `.toLowerCase()`, to improve functionality
* Implemented a `switch statement` in place of an `if-else-if` ladder

### Details
Here's more about each change.

> **Moved the _import statement_ to the top of the file**

I read the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html), which is a lot to absorb but is a great reference for two reasons:

1. it functions as a digest important Java conventions for structuring, naming, formatting, and other aspects of writing and organizing Java code, and
2. it conveys what Google considers to be the best practices for Java styling to maximize readability

If it's good enough for Google, it's good enough for me, a newcomer.

After reading the document, I moved `import` statements to the top of my source files, removed unnecessary or unhelpful whitespace, and made other cosmetic or readability improvements to my code. This is true in this refactored program as well as the rest.

> **Removed two unnecessary `String` variable declarations and instantiations**

Re-reading my old code, I realized that the `python` and `java` variables didn't serve any purpose. The user is going to input "Python" or "Java" via the keyboard, so storing those strings in variables beforehand is redundant. My original reasoning for including them might have been to compare the input strings with the ones stored in the `python` and `java` variables. But I never did do that, since the `i.equalsIgnoreCase()` method addressed that need in the old program.

In any case, I deleted the variables.

> **Made a minor tweak to the `Scanner` variable name**

Previously, I named the Scanner object `keyboardInput1`. This had been lazy naming: there was no `keyboardInput2` in my program, so no need to specify a number in the name. This time, I chose the name `userInput`.

> **Reworded the print statement which prompts the user for a language**

The previous print statement was `"Which language are you asking about?"`. The new one is more specific: `"Would you like to know about Java or Python? (Type 'Java' or 'Python')"`.

> **Made variable `i` a variable of type `var`**

I recently learned about **local variables**, which are variables declared and used within the scope of a method or code block. I also learned about **local variable type inference**, a feature that allows the Java compiler to infer the data type based on the value stored in a local variable. To avail yourself of this functionality, you use the keyword `var` instead of specifying a particular primitive type or reference type in your declaration. So I did that here with `i`. The only wrinkle is—and I might be misunderstanding this point—is that `i` appears to be an _instance variable_ of my class, not a _local variable_ of a specific method, constructor, etc. Nonetheless, I replaced `int` with `var` to practice my new learning, and it worked.

> **Added a chained method, `.toLowerCase()`, to improve functionality**

This line of code was one of my favorite lines of code from the last month:

```java
var i = userInput.nextLine().toLowerCase();
```

Why? This line of code solved a problem I'd been banging my head against the wall with for a few days. The problem was related to my use of a `switch statement` in place of the previous `if-else-if` ladder (also referred to simply as an `if-then-else statement`). I'll explain more in this next section below.

> **Implemented a `switch statement` in place of an `if-else-if` ladder**

In my original program, the user is asked a question with the expectation of entering either "Python" or "Java" in response. But there was a chance that the user would enter either word in lowercase rather than in capitalized form. So I wrote the program to ignore casing:

```java
if (i.equalsIgnoreCase("Python")) {...} // accepts any combination of lowercase and uppercase
```

This worked well. But in my refactored program, I wanted to replace the if-then-else statement with a switch statement. For one, a switch statement is more readable, and for two, the goal of my exercise was to refactor my code while retaining an identical user experience and program output.

That's when I ran into a problem: I tried `switch (i.equalsIgnoreCase())` to achieve a similar result, but I discovered that this is illegal in Java. This is because the input to a switch statement can't be a boolean value; unfortunately for me, this is exactly what the result of `i.equalsIgnoreCase("blah")` returns: a boolean value. So I was stuck. I would need to manually program different case values for the different combinations of lowercase and uppercase letters.

That is, until I realized that there was another solution: store the value of `i` in the same output format regardless of how the user chooses to input the letters in the words "Python" or "Java". To do that, I used a chained method, `.toLowerCase()`, as in

```
userInput.nextLine().toLowerCase()
```

So whether the user enters a word in ALL CAPS, all lowercase, or mixedCase, it won't matter: "java", jAva", "jaVa", "javA", "Java", "JAva", "JAVa", "JAVA", "jaVA", etc. will be stored in `i` as the same representation: "java".

With this solution in place, I only needed two case labels and one default label in my switch statement to account for all possible scenarios.

### Output(s)

Example 1:

```
$ java RefactoredTwoLanguages
Would you like to know about Java or Python? (Type 'Java' or 'Python')
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.
```

```
$ java RefactoredTwoLanguages
Would you like to know about Java or Python? (Type 'Java' or 'Python')
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 2:

```
$ java RefactoredTwoLanguages
Would you like to know about Java or Python? (Type 'Java' or 'Python')
PYTHOn
Python is a great language for newcomers to programming! It's easy to pick up and has a huge developer community surrounding it.
```

```
$ java RefactoredTwoLanguages
Would you like to know about Java or Python? (Type 'Java' or 'Python')
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 3:

```
$ java RefactoredTwoLanguages
Would you like to know about Java or Python? (Type 'Java' or 'Python')
C++
Please re-run the program and enter a different language. The only valid values are `Java` or `Python` (not case-sensitive)
```

### Key Takeaway(s)
Cosmetic changes can aid readability. A well-selected chained method can save you precious time and obviate the need for long control structures. Your choices in one part of your code (such as in a method) can affect your options in another part of your code (such as in a switch statement), so you must plan ahead. Switch statements offer a cleaner, more readable alternative to if-then-else statements.

## Refactored Program 2: Even Odd While Loop<a name="refactored-program-2-even-odd-while-loop"></a>

Here's [my old **EvenOddWhileLoop** program](https://dev.to/alexlearnsjava/lessons-from-a-month-learning-java-2djm#program-2-even-odd-while-loop):

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

And here's my new **RefactoredEvenOddWhileLoop** program:

```java
/*
A program that prints even and odd numbers from zero through ten.
*/

class RefactoredEvenOddWhileLoop {
  public static void main(String[] args) {
    var i = 0;
    while (i < 11) {
      System.out.println((i % 2 == 0) ? i + " is an even number." : i + " is an odd number.");
      i++;
    }
  }
}
```

### Refactored Code Summary
Heres what the compiler will do:

- Begin program execution
- Create a variable named `i`; this will serve as an increment variable with an initial value of `0`. The compiler will infer its type, and that will be `int`
- Consider the current value of `i` and take the following actions while `i` is less than `11`:
  - If the value is divisible by 2 with no remainder, print the first statement
  - Otherwise, print the second statement
  - Increment the current value of `i` by 1
- Exit the program

That's all there is to it!

### Old vs New: What's Changed
Here's a summary of the changes:

CHANGE LOG
* Replaced the `int` data type with the `var` keyword
* Cosmetic change: renamed the variable `x` to `i`
* Removed unnecessary vertical whitespace
* Implemented a `ternary operator` to replace the true/false branches of the former `if-then-else` statement

### Details
Here's each change in greater detail.

> **Replaced the `int` data type with the `var` keyword**

This wasn't a strictly necessary change, but I wanted to continue testing type inference. So instead of explicitly declaring the variable as being of primitive type `int`, I used the `var` keyword to let the compiler infer `int` from the stored value of `0`.

> **Cosmetic change: renamed the variable `x` to `i`**

One of the books I'm reading is Jeanne Boyarski and Scott Selikoff's _OCP Java SE 11 Programmer I Study Guide_. In it, Boyarski & Selikoff explain that `i` is short for "increment" variable and is conventionally used as a counter in loops in many programming languages. (This apparently was done pre-Java, so presumably in C and C++.) Conventions, even very small ones like this one, can reduce mental overhead over time, so I made the change and will keep using `i` in future programs when a variable's purpose is incrementation.

> **Removed unnecessary vertical whitespace**

Ironically, more whitespace doesn't automatically make code cleaner or more readable. _Selective_ use of vertical whitespace does. In this program, I determined that less is more.

> **Implemented a `ternary operator` to replace the true/false branches of the former `if-then-else` statement**

With respect to decision-making programs, Java has a bit of "paper-rock-scissors" that I'm still learning about. Joshua Bloch would say you should prefer for loops to while loops if you can help it and you should "prefer for-each loops to traditional for loops" also (Item 58, _Effective Java, 3rd Edition_).

Translated:

```
 while loop < for loop < for-each loop // it depends!
```

In my original program, I used a while loop with an embedded if-then-else statement. In my refactored version, the next best approach would seem to be a for loop. But as the name of this program suggests, the point is to implement a while loop, so a for loop is off the table. Besides, I found my for loop attempts lacking:

```java
// Worked but was ugly
for (var i = 0; i < 11; i++) {
  System.out.println((i % 2) == 0 ? i + " is an even number." : i + " is an odd number.");
}
...
```

In this snippet, I save a line of code by having the compiler create a local variable, `i`, inside the for loop. Then the compiler runs a `ternary operation` for as long as the `i < 11` condition is met. A ternary operation is a shortcut that evaluates a boolean expression and returns one of two statements—one if it's true, the other if it's false.

Said differently, the ternary has three operands:

1. a boolean condition to test,
2. a statement to process if the condition evaluates to `true`, and
3. a statement to process if the condition evaluates to `false`

For example, the compiler here will perform a modulus division; if the evaluation results in `true`, the compiler will print "_...is an even number_". If the evaluation results in `false`, the compiler will print "_...is an odd number_". This process repeats for every value until the compiler can exit the for loop.

In any case, this worked and wasn't terrible, but that's a lot to cram into three lines of code.

My next attempt at a for loop was slightly better but definitely longer:

```java
// Also worked and was less ugly yet longer
for (var i = 0; i < 11; i++) {
  if ((i % 2) == 0) {
    System.out.println(i + " is an even number.");
  } else {
    System.out.println(i + " is an odd number.");
  }
}
...
```

What went well here is that the code is easier to read. But now I've added an `if-then-else` statement with separate `if` and `else` branches, making my code longer. Note that the if block also has a ternary operator inside. So this attempt compiles fine and prints the desired output, but it nests a ternary within an if-then-else statement within a for loop. (The original program, **EvenOddWhileLoop**, had an `if-then-else` statement nested within a _while_ loop. So technically, this version is slightly better.)

In the end, I opted to keep the while loop, as seen in my **RefactoredEvenOddWhileLoop** program. There is a downside, though. As Bloch explains in _Effective Java_, a while loop doesn't let me declare `i` as a local variable within the loop itself. For example, I can't write `while (var i = 0 && i < 11)`. I don't know if it's because you can't include two boolean expressions there, or if it's something to do with the `var` keyword. But I have to declare `i` as an instance variable of the class, before the compiler reaches the while loop. On the other hand, in a for loop, I _can_ declare `i` as a local initialization variable, within the scope of the for loop itself. This is a better practice (Bloch, "Item 57: Minimize the scope of local variables", _Effective Java_, 3rd Edition). So I may end up creating an "**EvenOddForLoop**" program to replace this one in a future refactoring.

In any case, I wanted to practice succinctness and practice ternary operations, so I added the `ternary operator` to my refactored while loop. To recap what the ternary does, here's the full ternary operator:

```java
(i % 2 == 0) ? i + " is an even number." : i + " is an odd number."
```

It first evaluates the expression involving integer `i`. If the expression evaluates to true, the compiler returns the print statement left of the colon (`:`). If the outcome is false, the compiler returns the print statement to the right of the colon. So the ternary operator functions like a shortcut for an `if-then-else` statement, which is great.

---

As a related aside, here's something I was stuck on for a while. I might still have something wrong here, but here's my present understanding:

In **RefactoredEvenOddWhileLoop**, the first operand is of type `boolean` and is evaluating an `int`, whereas the other two operands are of type `String`. This would be problematic for the compiler but for the fact that the `System.out.println()` method automatically converts the output of all three into Objects of type `String`. Per Boyarski & Selikoff, the compiler calls the `toString()` method under-the-hood; therefore the ternary works fine even though there's one numerical operand and two String operands in play. So upon compilation, there's no error. I think that's right, but don't quote me on it.

---

In summary, I tried a few different refactored programs, all of which worked. I selected the one that offered the best trade-off between simplicity and readability, even though using a while loop is not a best practice.

### Output(s)

```
$ java RefactoredEvenOddWhileLoop
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.
```

### Key Takeaway(s)

Don't cram too much code into a single line just to be succinct. Simplicity and readability involve trade-offs. You can write the program in various ways, but select the one that achieves the mission while navigating multiple concerns. Listen to Joshua Bloch; he gives well-reasoned advice.

---

### BONUS Refactored Program 2: Custom Even Odd While Loop<a name="bonus-refactored-program-2-even-odd-while-loop"></a>

Last time, I also created a **CustomEvenOddWhileLoop** program:

```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++;
      }
    }
  }
}
```
It was a satisfying, if wordy, program. Instead of printing the pre-selected values 0 through 10, the program let the user provide a custom range.

Here's the first of two valid implementations for **RefactoredCustomEvenOddWhileLoop**:

```java
import java.util.Scanner;

/*
A program that prints whether numbers are even or odd, based on a range supplied by the user. The valid input value range is from -2,147,483,648 to +2,147,483,647.
*/

class RefactoredCustomEvenOddWhileLoop {
  public static void main(String[] args) {
    Scanner userInputMin = new Scanner(System.in);
    System.out.println("Enter a minimum value:");
    int min = userInputMin.nextInt();

    Scanner userInputMax = new Scanner(System.in);
    System.out.println("Enter a maximum value:");
    int max = userInputMax.nextInt();

    // Implemtation #1: An if-then-else statement within a while loop
    while (min <= max) {
      if (min % 2 == 0) { // if dividing by 2 leaves no remainder
        System.out.println(min + " is an even number.");
        min++;
      } else {
        System.out.println(min + " is an odd number.");
        min++;
      }
    }
  }
}
```

### Refactored Code Summary for Implementation 1
In this first version, the compiler will do these sequentially:

- Import the `java.util.Scanner` package
- Begin program execution
- Create an object named `userInputMin` of the `Scanner` class; the new object will be capable of accepting user input via the keyboard
- Print a statement to the console asking the user to input a minimum value
- Create a variable named `min` to store the user-supplied minimum value
- Repeat the last three steps, but with a `userInputMax` object, a print statement about a maximum value, and a new variable named `max`
- Execute a while loop that runs until `min` and `max` have the same value:
  - Run a modulus operation to check if `min` is an even number, and
    - if yes, print the corresponding statement in the `if` block, then increment `min` by 1
    - if no, print the alternative statement in the `else` block, then increment `min` by 1
- Exit the program

And here's the second valid implementation:

```java
import java.util.Scanner;

/*
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.
*/

class RefactoredCustomEvenOddWhileLoop {
  public static void main(String[] args) {
    Scanner userInputMin = new Scanner(System.in);
    System.out.println("Enter a minimum value:");
    int min = userInputMin.nextInt();

    Scanner userInputMax = new Scanner(System.in);
    System.out.println("Enter a maximum value:");
    int max = userInputMax.nextInt();

    // Implementation #2: A ternary operator within a while loop
    while (min <= max) {
      System.out.println((min % 2 == 0) ? min + " is an even number." : min + " is an odd number.");
      min++;
    }
  }
}
```

Note how much shorter this one is, since it uses the ternary operator in place of an if-then-else statement.

### Refactored Code Summary for Implementation 2
In this second version, the compiler will perform these steps:

- Do everything as in Implementation 1 prior to the while loop
- As before, execute a while loop that runs until `min` and `max` have the same value, but this time, follow control flow based on a ternary operation
- Exit the program

So the logic is practically identical to Implementation 1's logic while requiring fewer lines of code. You'll notice that this while loop is identical to the while loop in **RefactoredEvenOddWhileLoop**. My opinion seems to be that ternary operators are visually palatable when used within a while loop, but not when used in a for loop 🤷🏾‍♂️.

### Old vs New: What's Changed
Finally, here's a summary of the changes:

CHANGE LOG
* Moved the import statement to the top of the file
* Removed arbitrary vertical whitespace
* Renamed the Scanner object variables from `lowerBound` and `upperBound` to `userInputMin` and `userInputMax`, respectively
* Renamed the storage variables from `a` and `b` to `min` and `max`, respectively
* Cosmetic change: removed the line break before the `else` in the if-then-else statement (Implementation 1 only)

### Details
For the first three of these changes, I have the same reasons as the ones given for **RefactoredTwoLanguages** and **RefactoredEvenOddWhileLoop**: simplicity, readability, and convention.

However, the last change is worth detailing:

> **Cosmetic change: removed the line break before the `else` in the if-then-else statement (Implementation 1 only)**

Here's what the Google Java Style Guide has to say about formatting with braces:

"_Braces follow the Kernighan and Ritchie style ("Egyptian brackets") for nonempty blocks and block-like constructs: [...] Line break after the closing brace, only if that brace terminates a statement or terminates the body of a method, constructor, or named class. For example, there is no line break after the brace if it is followed by else or a comma._" [See Braces > Nonempthy blocks: K & R style]

That translates into the following:

```java
// Do this
if (condition) {
  ...
} else {
  ...
} else if {
  ...
}

// Not this
if (condition) {
  ...
}
else {
  ...
}
else if {
  ...
}
```

Both are syntactically correct. They make no difference to the compiler. But the K&R style is conventionally correct per Google Java Style Guide, so I tweaked my refactored code accordingly and removed the line break and vertical whitespace.

### Output(s) for Refactored Custom Program

Example 1

```
$ java RefactoredCustomEvenOddWhileLoop
Enter a minimum value:
13
Enter a maximum value:
22
13 is an odd number.
14 is an even number.
15 is an odd number.
16 is an even number.
17 is an odd number.
18 is an even number.
19 is an odd number.
20 is an even number.
21 is an odd number.
22 is an even number.
```

Example 2
```
java RefactoredCustomEvenOddWhileLoop
Enter a minimum value:
-5
Enter a maximum value:
122
-5 is an odd number.
-4 is an even number.
-3 is an odd number.
-2 is an even number.
-1 is an odd number.
0 is an even number.
1 is an odd number.
2 is an even number.
3 is an odd number.
... // purposely truncated
116 is an even number.
117 is an odd number.
118 is an even number.
119 is an odd number.
120 is an even number.
121 is an odd number.
122 is an even number.
```

### Key Takeaway(s)
Name all variables as descriptively as possible. This reduces mental overhead on future reads or for external readers of your code. Choose a Style Guide that has well-researched and well-argued choices, then apply your choices consistently when you write code. This includes where and how you use brackets and vertical whitespace.

## Refactored Program 3: The Nth Letter of The Alphabet<a name="refactored-program-3-the-nth-letter-of-the-alphabet"></a>

Here's [my original program, **TheNthLetterOfTheAlphabet**](https://dev.to/alexlearnsjava/lessons-from-a-month-learning-java-2djm#program-3-the-nth-letter-of-the-alphabet):

```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 <-- TYPO: "27th" should read "26th"; the loop begins at n = 1 and ends when n = 27
      // <-- TYPO: empty comment
      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++;
    }
  }
}
```

Below is the refactored version, **RefactoredTheNthLetterOfTheAlphabet**:

```java
/*
A program that prints each letter of the English alphabet along with its position (1st, 2nd, 3rd...26th) in the sequence.
*/

class RefactoredTheNthLetterOfTheAlphabet {
  public static void main(String[] args) {
     // Implementation with a for-each loop and switch statement
     String st = "st letter of the alphabet is ";
     String nd = "nd letter of the alphabet is ";
     String rd = "rd letter of the alphabet is ";
     String th = "th letter of the alphabet is ";

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

     var i = 1;

     for (String e : alphabet) {
       switch (i) {
         case 1: case 21:
         System.out.println("The " + i + st + e + ".");
         i++;
         break;

         case 2: case 22:
         System.out.println("The " + i + nd + e + ".");
         i++;
         break;

         case 3: case 23:
         System.out.println("The " + i + rd + e + ".");
         i++;
         break;

         default:
         System.out.println("The " + i + "th letter of the alphabet is " + e + ".");
         i++;
         break;
       }
     }
  }
}
```

### Refactored Code Summary
The compiler will do this:

- Begin program execution
- Create a variable named `st` to store a phrase for later use
- Create a variable named `nd` to store a phrase for later use
- Create a variable named `rd` to store a phrase for later use
- Create a variable named `th` to store a phrase for later use
- Create an array named `alphabet` of type `String` to store the 26 letters of the English alphabet
- Instantiate a variable named `i` with a value of `1`
- Create and execute a for-each loop
  - Evaluate the value stored in `i`
    - In the case of "1" or "21", print the corresponding combination strings (e.g., "The 1st letter...")
    - In the case of "2" or "22", print the corresponding combination of strings (e.g., "The 2nd letter...")
    - In the case of "3" or "23", print the corresponding combination of strings (e.g., "The 3rd letter...")
    - In all other cases, print the default combination of strings (e.g., "The 4th letter...")
- Exit the program

### Old vs New: What's Changed
Here's a summary of the changes:

CHANGE LOG
* Cosmetic change: changed the position of the array bracket, from `String alphabet[]` to `String[] alphabet`
* Created placeholder variables `st`, `nd`, `rd`, and `th` as shortcuts for substrings of the print statements
* Adjusted `int n = 1` to `var i = 1`
* Replaced the while loop with a for-each loop
* Implemented a switch statement within the new for-each loop, as a replacement for the original program's if-then-else statement

### Details
Here's more information about each change.

> **Cosmetic change: changed the position of the array bracket, from `String alphabet[]` to `String[] alphabet`**

This is purely cosmetic and doesn't change what the compiler does. Via Boyarski & Selikoff, I've learned that any of these would be valid positions for the array bracket `[]`:

- `String[] alphabet`
- `String [] alphabet`
- `String alphabet[]`

The first style is the most common, so I went with that. But they all instruct the compiler to do the same thing: create an array to store Strings, and name that array "alphabet".

> **Created placeholder variables `st`, `nd`, `rd`, and `th` as shortcuts for substrings of the print statements**

This was a workaround to improve readability. I wanted my switch statement to be tidier than the if-then-else statement it was meant to replace had been. So instead of specifying the full text as a phrase in the case statements, I pre-made these snippets. But the enhancement wasn't free: the penalty was having to add four new instance variables to my class.

> **Adjusted `int n = 1` to `var i = 1`**

There are two cosmetic changes here:

1. `i` is still an integer value, so I don't really need to delegate type inference to the compiler. I could have simply retained `int i = 1`
2. I also renamed the variable from `n` to `i`, for consistency's sake: `i` functions as an increment variable in the subsequent switch statement

---

**An Aside about Consistency in Naming**

While writing this program, I determined to settle on the following variable naming conventions in future code:

- as explained before, use `i` for local variables or instance variables that are used primarily to increment a value (as in `i++`)
- use `n` or `x` for index variables whose primary function is to be indices in a collection (as in `alphabet[n]` or `alphabet[x]`)

Consistency in nomenclature helps to free up mental bandwidth for the programmer (one fewer decision to have to make). It also makes it easier for the reader to identify the purpose of code, once they understand your conventions. By analogy, it's common in mathematics for the variables _a_, _b_, and _c_ to be used in equations with variables of _known or fixed_ values, and to use the variables _x_, _y_, and _z_ when the variables have _unknown or varying_ values.

---

> **Replaced the while loop with a for-each loop**

I didn't set out to follow Joshua Bloch's advice regarding the benefits of a for-each loop over a for loop (and by extension a while loop) for this program. But that's what happened here. Now I see why it's useful to prefer a for-each loop to a for loop or a while loop. First, the variable `e` here is local; it's used only within the scope of the for-each loop. Because of that, `e` will be eligible for garbage collection as soon as this portion of my refactored program completes, as far as I understand. The variable `i`, on the other hand, does not enjoy this same benefit because it's declared as a regular (instance) variable before the compiler reaches the for-each loop. So even though `i` is only used within the switch statement, its scope is actually part of the `main()` method. So even when the switch statement is no longer in play and the for-each loop is no longer in play, `i` remains in play until the entire program terminates. Apparently, this is an anti-pattern to avoid, as it can lead to memory leaks in some cases.

> **Implemented a switch statement within the new for-each loop, as a replacement for the original program's if-then-else statement**

There are four case branches here compared to four if/else if/else branches. But the switch statement is tidier and easier to read.

I also learned something new and important here. The original if-then-else statement is followed by an incrementation statement (`n++;`). I tried to do the same here by adding `i++;` after the switch statement, as a way around specifying `i++;` in each case branch. That didn't work. The `i++;` statement will be unreachable by the compiler if you do that, creating infinite loop. You have to add an `i++;` instruction to each case branch for the program to work properly.

### Output(s)

```
$ java RefactoredTheNthLetterOfTheAlphabet
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.
```

### Key Takeaway(s)
Storing predefined sentence strings in variables can make your code more readable. For-each loops combine nicely with switch statements. Watch out for infinite loops.

### BONUS PROGRAMS :)

While creating the refactored version of this program, I found multiple ways to print the individual elements or all the elements of an array. Below are some of the toy additions that didn't make it into **RefactoredTheNthLetterOfTheAlphabet**. Note that each of the snippets assumes the class, main method, and array have been declared prior to that snippet.

#### println(Arrays.toString(alphabet))

```java
import java.util.Arrays;

// Print all array elements using the name of the array
System.out.println(Arrays.toString(alphabet));
```

This program will only work if the import statement `import java.util.Arrays;` is included in the source file. That's because this implementation uses the `.toString()` method, a method of the `Arrays` class. This method allows me to pass the `alphabet` array in as an argument in order to print its contents.

Here's the output with the above snippet included:

```
[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]
```

Initially, I tried to print the contents using just the name of the array within the `println()` method, but Java doesn't let you do that:

```java
// Both will compile but will not print the array elements

System.out.println(alphabet);
System.out.println(alphabet.toString());
```

Both of those commands compiled correctly but returned this:

```
[Ljava.lang.String;@d716361
```

Boyarski & Selikoff explain that `[L` means you have a list; `java.lang.String` is the reference type (`String` in java is not a primitive type; instead, it is a reference type); and `@...` is a hash code. This is why I need the `.toString()` method. Once I import the `Arrays` package, I can run `Arrays.toString(alphabet)` to print its elements, as shown further above.

---

#### println(alphabet[i])

What if I want to print the elements of this array, but on a different line and without the brackets? I can do so with this:

```java
// Print each member of the array, on a new line
for (var i = 0; i < alphabet.length; i++) {
  System.out.println(alphabet[i]);
}
```

For this implementation, I don't need the import statement or `Arrays.toString()`. I'm doing something different here: I'm not instructing the compiler to print "everything in this array", I'm telling it to "print each individual element" and specifying which element to print and how. So it's now an index-based program.

The only downside is longer code: this requires a for loop, a local variable, the `length` value, and the use of `i` as both an increment variable (`i++`) and an index variable (`[i]`). That's a lot. (By the way, `length` is a final field, or property, of an Array object. It corresponds in this case to the number of letters in the alphabet, which is 26. In other words, the `length` of this array is 26 because it has 26 elements inside. And since the index `i` starts at `0`, `i < alphabet.length` works perfectly as the for loop's condition statement).

But it works and the program outputs this:

```
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
```

---

#### println(e)

```java
// The most concise, and best-practice, way to print each member of the array, on a new line
for (String e : alphabet) {
  System.out.println(e);
}
```

This last one implements a for-each loop. It's by far the simplest approach to take, and it's the best-practice one to boot. It doesn't require an import statement. I don't need to declare and use an increment variable. It's easy to read ("_For every String element e in the alphabet array, print the element._"). And it's crisp, with just `e` as the argument passed into the `println()` method.

The result is the same as above:

```
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
```

---

## Refactored Program 4: Combine Two Arrays<a name="refactored-program-4-combine-two-arrays"></a>

Here's [my old program, **CombineTwoArrays**](https://dev.to/alexlearnsjava/lessons-from-a-month-learning-java-2djm#program-4-combine-two-arrays):

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

And my new one, **RefactoredCombineTwoArrays**:

```java
/*
A program that combines two arrays into a third array and prints its elements.
*/

class RefactoredCombineTwoArrays {
  public static void main(String[] args) {

    String[] abc = {"a","b","c"};
    String[] def = {"d","e","f"};
    String[] abcdef = { abc[0], abc[1], abc[2], def[0], def[1], def[2] };

    for (String e : abcdef) {
      System.out.println(e);
    }
  }
}
```

### Refactored Code Summary
The compiler does the following:

- Begin program execution
- Create an array named `abc`, with three elements
- Create an array named `def`, with three elements
- Create an array named `abcdef`, with six elements, using the 0th, 1st, and 2nd index of arrays `abc` and `def`, respectively
- Print the elements of the `abcdef` array
- Exit the program

### Old vs New: What's Changed
Here's a summary of the changes:

CHANGE LOG
* Renamed the arrays to be more descriptive
* Cosmetic change: moved the array symbol `[]` immediately after the `String` type
* Replaced the while loop with a for-each loop
* Removed the variables `x` and `y`

(I tried to implement `abcdef` in a way that didn't require me to manually specify the indices of `abc` and `def`—`{ abc[0], abc[1], ..., def[2] }`—but I couldn't figure out how.)

### Details
Here's more about each change.

> **Renamed the arrays to be more descriptive**

Names like `array1` and `array2` are missed opportunities to create clarity for the code reader. The names `abc` and `def` are more descriptive, convey more information, and are shorter to boot.

> **Cosmetic change: moved the array symbol `[]`** immediately after the `String` type

The original program places the array brackets `[]` to the right of the array names. In the new program, I've left-shifted the brackets to just after the `String` type. This makes no difference to the compiler but is the more conventional placement for the array brackets.

> **Replaced the while loop with a for-each loop**

For reasons covered previously in this article, a for-each loop has advantages over a while loop. This for-each loop also shortened my refactored code dramatically (to nearly half the program length).

> **Removed the variables `x` and `y`**

These variables were helper variables to the while loop in the old program. In retrospect, the `x` was unnecessary even then: `array3.length` would have gotten the same job done:

```java
while (y < array3.length) // replaces "while (y < x)"
```

So declaring and instantiating `x` was wasteful.

As for `y`, it played a role as both increment variable and index variable. But in my refactored program, I don't need that: the logic baked into the for-each loop automatically iterates through the specified array in a similar way without the need for a dedicated incrementor or index variable.

### Output(s)

```
$ java RefactoredCombineTwoArrays
a
b
c
d
e
f
```

### Key Takeaway(s)
Use descriptive names for arrays. Don't declare unnecessary instance variables to store a property that can be accessed directly, such as `length`. A well-designed for-each loop can shrink your code dramatically and doesn't require extraneous variable declarations.

## Refactored Program 5: Prime Detector<a name="refactored-program-5-prime-detector"></a>

Here's [my original **PrimeDetector** program](https://dev.to/alexlearnsjava/lessons-from-a-month-learning-java-2djm#program-5-prime-checker) (formerly referred to as "Prime Checker"):

```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.");
    }
  }
}
```

Here's the refactored version, **RefactoredPrimeDetector**:

```java
import java.util.Scanner;

/*
A program that evaluates an integer number supplied by the user and determines if it is a prime number or not. The input value can be any integer from -2,147,483,648 to +2,147,483,647.
*/

class RefactoredPrimeDetector {
  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:");
    var x = userInput.nextInt();

    switch (x) {
      case 0: case 1:
      System.out.println("The number "+ x + " is not a prime number.");
      break;

      case 2: case 3: case 5: case 7:
      System.out.println("The number "+ x + " is a prime number.");
      break;

      default:
        if (x >= 0 && (x % 2 != 0) && (x % 3 != 0) && (x % 5 != 0) && (x % 7 != 0)) {
          System.out.println("The number " + x + " is a prime number.");
        } else {
          System.out.println("The number " + x + " is not a prime number.");
        }
      break;
    }
  }
}
```

### Refactored Code Summary

The compiler will perform these steps, in order:

- Import the `java.util.Scanner` package
- Begin program execution
- Create a Scanner object named `userInput`, capable of accepting user input via standard input from the keyboard
- Create and initialize the variable `x` to store what the user inputs
- Evaluate the value of `x` in the switch statement for the cases listed within
- Exit the program

### Old vs New: What's Changed
Here's a summary of the changes:

CHANGE LOG
* Changed `int` to `var` in the declaration for `x`
* Replaced the if-then-else statement with a switch statement

### Details
Here's more information about each change.

> **Changed `int` to `var` in the declaration for `x`**

In place of the primitive type `int`, I went with the `var` keyword here. I also renamed `i` to `x`, since this isn't an increment variable, just a regular placeholder variable for a value.

> **Replaced the if-then-else statement with a switch statement**

For starters, I was able to share one case branch for `case 0` and `case 1`. Doing so replaced some of the logic found in the former `if (i <= 0)` and `else if (i != 1...)`.

The case branch for `case 2`, `case 3`, `case 5`, and `case 7` replaces one of the former `else if` branches. Admittedly, this part of my refactored code is about the same length as the corresponding else if statement, so the gain in this part of the code is in readability only.

But it's worth noting that the new switch statement is overall both easier to read _and_ slightly shorter than the original if-then-else statement. Admittedly, that's because of how I stacked boolean conditions in the old program, which made it longer than it had to be. Also, the new switch statement includes an if-then-else statement in the `default` case, so it's not exactly a home run in terms of simplicity.

Still, the `default` case is easier to digest than what I wrote previously to cover most of the allowable values. It's also where I had the most readability gains in my refactored code. Here's how it works:

- `x` is either a prime number or it's not
- the values 0, 1, 2, 3, 5, and 7 are already accounted for in the other switch statements. So any other legal value for `x` will be evaluated like this:
  - if it's a negative value, it will fail the `x >= 0` part of the if statement, so it will be deemed not prime (negative values cannot be prime, by definition)
  - if it's a positive value (`x >= 0`) AND it can be divided evenly neither by 2 nor 3 nor 5 nor 7, then it will pass the if statement, so it will be classified as a prime (because, by definition, it will only be divisible by "1" and itself)
  - if it's a positive value (`x >= 0`) BUT it fails any of the other conditions in the if branch, then it fails the if statement as a whole, so it will be be classified as not a prime

As before, this program will only work for the range of inputs that are legal for `int` values in Java: i.e., from -2147483648 to +2147483647.

There may be an easier way to implement this program, but I don't know one yet.

### Output(s)

```
$ java RefactoredPrimeDetector
Enter an integer to check if it is a prime number:
-1234567
The number -1234567 is not a prime number.
```

```
$ java RefactoredPrimeDetector
Enter an integer to check if it is a prime number:
11
The number 11 is a prime number.
```

```
$ java RefactoredPrimeDetector
Enter an integer to check if it is a prime number:
11232134
The number 11232134 is a prime number.
```

### Key Takeaway(s)

When there are a lot of possible values to consider, a switch statement is indeed more useful than an if-then-else statement. Some conditional logic can be programmed more easily and less confusingly inside the default case of a switch statement.

---

## Wrap-up<a name="wrapup"></a>

This concludes my refactoring exercise. The toy programs I made a month ago are now modernized:

- `RefactoredTwoLanguages`
- `RefactoredEvenOddWhileLoop` (and `RefactoredCustomEvenOddWhileLoop`)
- `RefactoredTheNthLetterOfTheAlphabet`
- `RefactoredCombineTwoArrays`
- `RefactoredPrimeDetector`

In most cases, I was able to shorten and/or simplify the programs. Even in cases where the new program was the same length or slightly longer than before, the code was generally cleaner and easier to read. I also gained a deeper understanding of some of the rules covered _Effective Java_ while applying some of the more foundational knowledge gained from the other books I've been studying and the Google Java Style Guide I've digested. I'm pleased with the result.

## Next Up: Month Three of My Learnings

The more Java basics I learn, the more I continue to appreciate how immense this language is. There's a great deal that works out of the box, and the box itself is enormous. So there's a lot more to learn, and I'm having with the journey.

---

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