Prelude

First of all, thank you for your time and for your patience.

I know that when I was in school I never wanted to read a book and, except for The Cay and Great Expectations, I got away without having to.

So while it is hypocritical for me to ask this of you, please read this book like a book and go from the start to the end, one section at a time.

At the end of each section there will also be challenges. I want you to at least attempt all of them before moving on to the next section.

This book is written specifically for those folks that feel like giving up, like they are too stupid to get it, or like they didn't understand a damn thing their professor has said for the last three months.

I see you. You are not stupid. This is not your fault, it is theirs.1

1

probably.

Asking for Help

If anything in this confuses you or feels intimidating please, please reach out to someone.

If you are in a position to, make use of your teacher. That is what they are there for.

If you are not, on every page there is a button in the top right corner which you can click to ask a question.

When you do, keep in mind these basic rules.

1. You get what you pay for

Often the people willing to help you will be volunteers.

Do not expect them to do your assignments for you, do not expect them to be available at a moments notice, and accept that they are under no obligation to help anyone or you in particular.

2. Ask early

If you are struggling with something and you have a deadline in 5 hours, that might not be enough time to do anything.

Asking questions well before a deadline is best for all those involved.

3. Don't Ask to Ask

Don't ask to ask, nor only say hello, just ask your actual question right away.

Consult https://dontasktoask.com/ for what that means exactly.

Toy Problems

As you go through this book there will be a lot of what can be considered "toy problems."

That is, you will be shown or asked to write programs that have no obvious real world use. They will be similar in spirit to math problems like "if you have 8 apples and I take 3, how many apples do you have left?"

The intent is not for these to be annoying, although I am sure they will be. I just don't know any other way to help you build an understanding of mechanics.

Lies

At various points in this book I am also going to lie to you. Specifically I will make lies of omission.

If there are five ways to do something, I might pretend that there is only one way to do it until I give you enough context so that I can talk about the other four.

This can be particuarly annoying if you are in a course that is teaching things in a different order or if you feel rushed to just get some project done.

I get that. I just ask that you trust me and go in the sequence I am laying out. I am honestly trying to make it so that you end with a stronger understanding than you would have otherwise.

If I fail, there is the question mark in the top right of every page.

Getting Started

There are a lot of ways to "get set up" to run Java code.

For the purposes of this book, I am going to reccomend that you start with replit.com.

It requires an internet connection and you will have to make an account, but of the available options it is the easiest to set up.

If you are in school and your teacher has helped you get set up in some other way it is okay to skip this section and just do it the way you were shown.

All that matters is that in the end you have the ability to run and edit the following code.

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World");
    }
}

Step 1. Make an account

Go to replit.com and find the "Sign Up" button. Websites change every now and then so these screenshots might be out of date.

Picture of the sign up button on replit's website

Click it and sign up for an account.

Picture of the sign up form on replit's website

Step 2. Create a Java REPL

Find the "Create REPL" button and click it.

Picture of the create repl button on replit's website

Then you should be presented with a menu that lets you search for the type of REPL to create. Find the Java template and click "Create".

Unfilled in create from template menu on replit

Filled in create from template menu on replit

Step 3. Run code

You should land on a screen with a big green run button, an open file called "Main.java", and a blank window labeled "console".

Picture of an unran hello world program

Click it and you should see the text Hello, world! appear under the console window.

Picture of a hello world program after running

First Steps

If you made it through the Getting Started section you've successfully run this program.

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

This "prints" - not in the sense of a physical printer, but like "displays on the screen" - the text "Hello, World!".

Its a tradition for this to be your first program in any language.

Unfortunately, for reasons that are impossible to explain with the context you have at this point, half of this probably reads as cryptic nonsense.

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

I don't want it to stay cryptic nonsense, but until we get there all you truly need to know is that Java uses all of that to know where to start the program.

public class Main {
    public static void main(String[] args) {
        < WRITE YOUR CODE HERE >
    }
}

So for all intents and purposes, this is the whole program.

System.out.println("Hello, World!");

This bit of magic here - System.out.println - is a "statement" that "prints" the text inside the ( and ) as well as a "new line" to the screen.

print with new line.

If you were to replace it with System.out.print, then the output would lack that new line. This makes the following program be functionally identical to the first.

System.out.print("Hello, ");
System.out.print("World");
System.out.println("!");

Which, when we add back the part you are squinting past, looks like this.

public class Main {
    public static void main(String[] args) {
        System.out.print("Hello, ");
        System.out.print("World");
        System.out.println("!");
    }
}

You should get in the habit of, whenever you see some bit of code, trying to physically type it out, run it, tweak it, and play with it.

So try playing around with this program. If you are not actively engaging then the whole thing is a bit of a wash.

Comments

At various points, I am going to leave "comments" in the code. Comments are parts of the code that are solely there for a human to be able to read as an explanation and can be written in regular words.

public class Main {
    public static void main(String[] args) {
        // This prints hello world!
        System.out.println("Hello, World!");
    }
}

The rules for this are that if you see a //, everything after that in the same line is ignored.

If you put // in front of something that is "code" and not an English explanation we colloquially call that "commenting out" the line.

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
        // The line that prints out goodbye is "commented out"
        // System.out.println("Goodbye!");
    }
}

You might want to do that at various points where you want to see what happens if you "turn off" parts of the code.

If you put /* in the code then everything up until the next */ will be treated as a comment. The distinction here is that this style of comment can span multiple lines.

public class Main {
    public static void main(String[] args) {
        /*
            I have eaten
            the plums
            that were in
            the icebox
            and which
            you were probably
            saving
            for breakfast
            Forgive me
            they were delicious
            so sweet
            and so cold
        */
        System.out.println("Hello, World!");
    }
}

So that's a mechanism you will see me use and you can use yourself however you see fit.

Semicolons

The ; at the end of each of those lines is a "semicolon".

System.out.print("Hello, "); // <-- this thing
                       //  ^

It indicates that the statement has finished. A "statement" is a line of code that "does something." The reason we call it a statement and not just a "line of code" is that it can technically span multiple lines and be more complicated than these examples.

System.out.print(
    "Hello, "
);

The ; at the end is needed so that Java knows that the statement is over. You need to put a ; at the end of every statement. If you do not, Java will get confused and your code will not work.

If you happen to have an extra semi-colon or two that is technically okay. It just reads it as an "empty statement." It's pointless, but it is allowed.

System.out.print(
    "Hello, "
);;

Or even

System.out.print(
    "Hello, "
);

  // Technically legal, but kinda sus

  ;;;;;;;;;;;;;
  ;;;        ;;
  ;;;        ;;
  ;;;;;;;;;;;;;
  ;;   ;;;   ;;
  ;;;;;;;;;;;;;
  ; ;       ; ;
  ; ;       ; ;
  ;;;       ;;;

Formatting

You may have noticed that after each { all the code that comes after it is "indented" in one "level."

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Then, when there is a } everything is "de-dented" one level.

I will kindly ask that you try to stick to this rule when writing your own code as well. If you try to find help online and you haven't, it will be hard for people to read your code.

This is easier to show than to explain in detail. Just try to make your code look like this.

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

And not like this.

public class Main 
    {
    public static void main(String[] args) 
            {
        System.out.println("Hello, World!");
            }
    }

And keep in mind that this rule of thumb applies to every language constrict that requires a { and } many of which I will introduce later.

Challenges

At the end of each larger section, I am going to write down some things you can do to make sure you get what was just gone over.

The rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

Write a program that prints your name twice. So if your name is "Jasmine", the output of the program should be this.

Jasmine
Jasmine

Challenge 2

What will this program output when run? Write down your guess and then try actually running it.

public class Main {
    public static void main(String[] args) {
        System.out.println("A");
        //System.out.println("B");
        System.out.println("C");//
        System.out.println("D");
        /*
        System.out.println("E");
        System.out.println("F");*/
        System.out.println("G");
    }
}

Challenge 3

There are four semicolons in this perfectly functional program. Delete one of them at random and see what the errors you get look like.

How could you use that error to figure out where you might have forgotten to put a semicolon?

public class Main {
    public static void main(String[] args) {
        System.out.println("Apple");
        System.out.println("Banana");
        System.out.println("Clementine");
        System.out.println("Durian");
    }
}

Local Variables

Mechanically, the next thing to cover is "variables".

public class Main {
    public static void main(String[] args) {
        String boss = "Jaqueline";
        System.out.println(boss);
    }
}

A variable declaration has three components - the "type", the "name", and the "initial value".

     String boss = "Jaqueline";
//   type   name   initial value

In this case, we are declaring a variable called "boss" and assigning it the initial value of "Jaqueline". Its "type" is "String", which I'll explain in more detail a bit ahead.

After you declare a variable and assign it a value, the "name" refers to the value on the right hand side and you can use that name instead of the value.

// Does the same thing as System.out.println("Jaqueline");
String boss = "Jaqueline";
System.out.println(boss);

Naming

It is a social convention1 that local variables be named likeThis.

That is if their name is one word, that word should be in lowercase.

String apple = "Red Delicious";

If it is multiple words, the first word should be lowercase and the others should start with a capital letter.

This convention is called camelCase because the capitals looks like the humps on a Camels back2.

Just like proper formatting, sticking to this style will increase your chances of someone online being able to help you with your code.

2

And because doing this will increase your body's ability to retain water by ~34%

Reassignment

After a variable is declared and assigned an initial value, that value can be later reassigned.

public class Main {
    public static void main(String[] args) {
        String boss = "Jaqueline";
        System.out.println(boss);
        boss = "Chelsea"
        System.out.println(boss);
    }
}

Reassignments just involve the name and the new value. The type should not be redeclared.

    boss = "Chelsea";
//  name   new value

After a variable is reassigned, the value associated with the name will reflect the new value from that point in the program onwards.

public class Main {
    public static void main(String[] args) {
        String boss = "Jaqueline";
        // This will output "Jaqueline"
        System.out.println(boss);
        boss = "Chelsea"
        // But this will output "Chelsea"
        System.out.println(boss);
    }
}

Delayed Assignment

The declaration of a variable and the assignment of its initial value can be done separately.

public class Main {
    public static void main(String[] args) {
        String contestWinner;
        contestWinner = "Boaty McBoatface";

        System.out.println(contestWinner);
    }
}

In which case the "variable declaration" will only have the "type" and "name" components.

   String contestWinner;
//  type  name

And the "initial assignment" will look identical to a "re-assignment".

   contestWinner = "Boaty McBoatface";
//   name            initial value

Before an initial value is assigned to a variable, it is not allowed to be used.1

public class Main {
    public static void main(String[] args) {
        String contestWinner;
        // This will not run, since Java knows that
        // you never gave contestWinner an initial value.
        System.out.println(contestWinner);
    }
}
1

There is no direct use for separating declaration and initial assignment at this point, but it's a surprise tool that will help us later.

Types

When a variable is declared, it is given a type.

String color = "green";

In this case, the variable color is declared to have the type String. After this declaration, color cannot be assigned to a value that is not a String.

// A number is not a String!
String color = 8;

This applies to all situations where a variable might be given a value, including delayed assignment and reassignment.

One mental model is that types are like shapes. If the type of something is a circle, you can only put circles into it.

◯ thing = ◯;

You cannot put square pegs in that round hole.

// If Java actually functioned in terms of shapes, this
// would not work since a Square is not the same "type" 
// of thing as a Circle.
◯ thing = ▢;

Final Variables

There is an optional extra part to a variable declaration where you can mark a variable as "final", meaning its value can never be reassigned.

public class Main {
    public static void main(String[] args) {
        final String coolestChef = "Anthony Bourdain";
        System.out.println(coolestChef);
    }
}

If you try to reassign a final variable, Java will not accept your program.

public class Main {
    public static void main(String[] args) {
        final String coolestChef = "Anthony Bourdain";
        System.out.println(coolestChef);

        // I'm sorry, but no. Cool guy, but no.
        coolestChef = "Gordan Ramsey";
        System.out.println(coolestChef);
    }
}

This is useful if you have a lot of lines of code and want the mental comfort of knowing you couldn't have reassigned that variable at any point between its declaration and its use.

final String genie = "Robin Williams";
// imagine
// 100s of lines
// of code
// and it is 
// hard to
// read all of it
// at a glance
// ......
// ......
// You can still be sure "genie" 
// has the value of "Robin Williams"
System.out.println(genie);

Variables whose assignment is delayed can also be marked final.

final String mario;
mario = "Charles Martinet";

The restriction is the same - after the initial assignment, the variable cannot be reassigned.

final String mario;
// An initial assignment is fine
mario = "Charles Martinet";
// But you cannot reassign it afterwards
mario = "Chris Pratt";

The downside to this, of course, is more visual noise. If a variable is only "alive" for a small part of the code, then adding final might make it harder to read the code, not easier.

Inferred Types

In many cases, Java is smart enough to know what the type of a variable should be based on what it is initially assigned to. In these cases, you can write var in place of the type and let java "infer" what it should be.

// Since what is to the right hand side
// of the = is in quotes, Java knows that
// it is a String.
var theDude = "Lebowski";
System.out.println(theDude);

You cannot use var with variables whose assignment is delayed.

// With just the line "var theDude;",
// Java doesn't know enough to infer the type
var theDude;
theDude = "Lebowski";
System.out.println(theDude);

You can use var with final to make a variable whose type is inferred and cannot be reassigned.

final var theDude = "Lebowski";
System.out.println(theDude);

Important to note that even if Java is smart enough to automatically know the type, you might not be yet. There is no shame in writing out the type explicitly.

String theDude = "lebowski";

Challenges

Remember the rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        String mascot = "The Noid";
        System.out.println(mascot);
        mascot = "Pizza the Hut";
        System.out.println(mascot);
        mascot = "Little Caesar";
        System.out.println(mascot);
    }
}

Challenge 2

Why won't this code run? Make it run by only changing one line.

public class Main {
    public static void main(String[] args) {
        String fruit;
        fruit = "apple"
        
        System.out.println(fruit);
        
        final String vegtable = "carrot";

        System.out.println(fruit);
        System.out.println(vegtable);

        fruit = "orange";
        vegetable = "celery";

        System.out.println(fruit);
        System.out.println(vegtable);
    }
}

Challenge 3

What is the output of this code?

public class Main {
    public static void main(String[] args) {
        String a = "A";
        String b = "B";
        
        b = a;
        a = b;
        b = a;
        a = b;

        System.out.println(a);
        System.out.println(b);
    }
}

Challenge 4

Only adding lines in the middle and without writing "A" or "B" again, make it so that the output of the program is

B
A
public class Main {
    public static void main(String[] args) {
        String a = "A";
        String b = "B";
        // Don't touch above this

        // You can add code here

        // Don't touch below this
        System.out.println(a);
        System.out.println(b);
    }
}

Challenge 5

Some of the variables in this program are named "wrong." Fix them.

public class Main {
    public static void main(String[] args) {
        String apple = "red";
        String clown_car = "polka dot";
        String SeriousCar = "black";
        String FASTRunner = "bolt";
        String slowRunner = "tortoise";
    }
}

Booleans

A boolean is either true or false.

boolean onFleek = true;
boolean badVibes = false;

This is used to represent situations where there are exactly two possible states.

And

One way multiple booleans can be combined is by using the "and" operator - &&.

boolean funToBeAround = true;
boolean believesInFundamentalHumanRights = true;
boolean willAskOnDate = funToBeAround && believesInFundamentalHumanRights;

So in this case, I will ask someone on a date if they are fun to be around and they wholeheartedly believe in the assertions made in the Universal Declaration of Human Rights.

funToBeAroundbelievesInFundamentalHumanRightswillAskOnDate
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse

Or

Another way booleans can be combined is by using the "or" operator - ||.

boolean dogLooksNice = true;
boolean personLooksNice = false;
boolean willAskToPetDog = dogLooksNice || personLooksNice;

So in this case, I will ask to pet someone's dog if either the the dog looks nice or the person walking the dog looks nice.

dogLooksNicepersonLooksNicewillAskToPetDog
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse

Exclusive vs. Inclusive

It is important too note that this is not an "exclusive" OR.

An exclusive OR would be something like a child being allowed to have ice cream or a cookie, but not both.

The || operator is an "inclusive" OR, meaning the child is allowed ice cream, a cookie, or both ice cream and the cookie.

Not

Booleans can also be "negated" using the "not" operator - !.

boolean haveOreosInHouse = true;
boolean stuckToCalorieLimit = !haveOreos;

So in this case, I have stuck to my calorie limit if there are not Oreos in the house.

haveOreosInHousestuckToCalorieLimit
falsetrue
truefalse

Operator Precedence

The operators that work on booleans have a "precedence order."

This is defines an order of operations similar to mathematics, where multiplication and division happen before addition and subtraction.

For booleans ! always happens first. This is followed by && and then by ||.

boolean a = true;
boolean b = false
boolean c = false;

// just as 2 + 5 * 3 "evaluates" 5 * 3 before adding 2
// first, !b is true
// second, a && true is true
// third true || c is true.
boolean result = a && !b || c;

Also like mathematics, parentheses can be used to control this order.

// Even though || has a lower precedence than &&, we evaluate
// !b || c first because of the parentheses.
boolean result = a && (!b || c);

Challenges

Remember the rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        boolean a = true;
        boolean b = false;
        boolean c = true;
        boolean d = false;

        boolean result = a || b && c || !d;

        System.out.println(result);
    }
}

Challenge 2

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        boolean a = true;
        boolean b = false;
        boolean c = true;
        boolean d = false;

        boolean result = !(a || b && c || !d) || (a && b || c);

        System.out.println(result);
    }
}

Challenge 3

Say you have two boolean variables, how could you use the operators we've covered to get the "exclusive or" of the two.

public class Main {
    public static void main(String[] args) {
        // Change these two variables to test your solution
        boolean hasIceCream = true;
        boolean hasCookie = false;

        boolean validChoice = < YOUR CODE HERE >;

        System.out.println(validChoice);
    }
}

Make sure to test all the possibilities.

hasIceCreamhasCookievalidChoice
truetruefalse
truefalsetrue
falsetruetrue
falsefalsefalse

Integers

An integer is any number in the set { ..., -2, -1, 0, 1, 2, ... }.

int x = 1;
int y = 8;
int z = -4;

Integer Literals

In order to write an integer in a program, you write an "integer literal."

789

We call them this because the integer is literally written down in the program.

int trueCrime = 789;

Addition

You can add any two ints using the + operator.

int x = 5;
// y will be 6
int y = x + 1;
// z will be 11
int z = x + y;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Adding a negative number does the same thing as subtraction.

int x = 5;
// y will be 1
int y = x + -4;

System.out.println(x);
System.out.println(y);

Subtraction

You can subtract any two ints using the - operator.

int x = 5;
// y will be 4
int y = x - 1;
// z will be 1
int z = x - y;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Subtracting a negative number does the same thing as addition.

int x = 5;
// y will be 9
int y = x - -4;

System.out.println(x);
System.out.println(y);

Multiplication

You can multiply any two ints using the * operator.

// x will be 15
int x = 3 * 5;
// y will be 75
int y = x * 5;
// z will be 1125
int z = x * y;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Division

You can divide any two ints using the / operator.

int x = 8;
// y will be 4
int y = x / 2;

System.out.println(x);
System.out.println(y);

Division with integers gives results in only the quotient of the result, not the remainder.

So 5 / 2 does not result in 2.5, but instead just 2.

// 5 / 2 is not 2.5, but instead 2.
int x = 5 / 2;
// 13 / 3 is not 4.3333, but instead 4.
int y = 13 / 2;

System.out.println(x);
System.out.println(y);

Remainder

To get the remainder of the division between two integers you can use the % operator. This is called the "modulo operator."

int x = 5;
// The remainder of 5 / 2 is 1
// y will be 1
int y = x % 2;
// The remainder of 5 / 3 is 2
// z will be 2
int z = x % 3;

System.out.println(x);
System.out.println(y);
System.out.println(z);

A common use for this is to make numbers "go in a circle."

For instance, say you wanted to count from 0 up to 3 and then go back to 0.

int value = 0;
System.out.println(value);

// the remainder of (0 + 1) divided by 3 is 1
// value will be 1
value = (value + 1) % 3;
System.out.println(value);


// the remainder of (1 + 1) divided by 3 is 2
// value will be 2
value = (value + 1) % 3;
System.out.println(value);


// the remainder of (2 + 1) divided by 3 is 0
// value will again be 0!
value = (value + 1) % 3;
System.out.println(value);

// the remainder of (0 + 1) divided by 3 is 1
// value will be 1
value = (value + 1) % 3;
System.out.println(value);

// and so on.

The fact that all the reassignments of value look identical is something that will be useful in tandem with loops.

Equality

Any two ints can be inspected to see if their value is equal by using the == operator.

Unlike the previous operators, which all take ints and produce ints as their result, == takes two ints and produces a boolean as its result.

// 1 is never equal to 2
// this will be false
boolean universeBroken = 1 == 2;
System.out.println(universeBroken);

boolean loneliestNumber = 1;
boolean otherLonelyNumber = 2;

// this will be true
boolean bothLonely = loneliestNumber == (otherLonelyNumber - 1);
System.out.println(bothLonely);

It is very important to remember that a single = does an assignment. Two equals signs == checks for equality.

The opposite check, whether things are not equal, can be done with !=.

// 1 is never equal to 2
// this will be true
boolean universeOkay = 1 != 2;
System.out.println(universeOkay);

Comparison

In addition to comparing for equality with == and !=, ints can be compared to see if one is bigger than another using >, <, >=, and <=.

> will evaluate to true if the number on the left is greater than the one on the right.

boolean willBeTrue = 5 > 2;
boolean willBeFalse = 2 > 5;

< will evaluate to true if the number on the right is greater than the one on the left.

boolean willBeFalse = 5 < 2;
boolean willBeTrue = 2 < 5;

If you went to public school like I did, you should be used to imagining that the > was the jaw of a shark. Whatever direction the Jaws are facing, thats the one that would need to be bigger for the statement to be true.1

// true if the shark is facing the bigger number
// false otherwise.
boolean result = 9 🦈 5;

>= behaves the same as > except >= will evaluate to true if the numbers are identical, > will not.

boolean willBeTrue = 5 >= 5;
boolean willBeFalse = 5 > 5;

<= has the same relationship to < as >= does to >.

boolean willBeTrue = 5 <= 5;
boolean willBeFalse = 5 < 5;
1

Shark attacks are far more rare than people think they are. You are not a seal.

Chained Comparisons

When writing an expression in math to say something along the lines of "x is greater than zero and less than 5," it is natural to put that x in the middle of both operators like so.

0 < x < 5

This does not work in Java. In order to "chain" comparisons like this, you should combine the results of comparisons using the && operator.

boolean xInRange = 0 < x && x < 5;

Operator Precedance

Just like boolean operators, +, -, *, /, and % have a defined precedence order.

The order of operations is the same as mathematics. Multiplication and division happen before addition and subtraction, with the modulo operator being a sort of "funky division." Parentheses can be used to control this order.

None of this should be a surprise if you learned PEMDAS in school.

// Following the order of operations:
// 2 * 3 + 3 * 9 / 2 - 2

// 2 * 3 happens first
// 6 + 3 * 9 / 2 - 2

// 3 * 9 happens next
// 6 + 27 / 2 - 2

// 27 / 2 happens next
// because of integer division, that gives 13 
// 6 + 13 - 2

// 6 + 13 comes next
// 19 - 2

// and the final result is 17;
int result = 2 * 3 + 3 * 9 / 2 - 2;
System.out.println(result);

The ==, !=, >, <, >=, and <= operators play a part here too1. They all have a lower precedence order than all the math operators, so you can put them in the middle of any two math expressions.

// The == check happens last.
boolean areThingsSame = 3 * (4 - 1 + 3) * 4 == 5 * 3 + 1 * 3 * 9;
1

Every operator in the language has a defined order of operations with respect to all of the others. I am just showing them to you as they become relevant.

Reassignment

When the value of a variable is reassigned, the value stored in the variable before the reassignment can be used to compute the new value.

This is true for all data types, but it is easiest to demonstrate with numbers.

int x = 1;
System.out.println(x);

// x starts as 1, 1 + 1 is 2.
// 2 is the new value of x. 
x = x + 1;
System.out.println(x);

// x is now 2, 2 * 2 * 3 is 12
// 12 is the new value of x.
x = x * x * 3;
System.out.println(x);

This property was used in the previous example for the % operator, but I think it worth calling attention to even if it is "intuitive".

Shorthands for Reassignment

A very common thing to do is to take the current value of a variable, perform some simple operation like addition on it, and reassign the newly computed value back into the variable.

int x = 2;
System.out.println(x);

x = x * 5 // 10
System.out.println(x);

As such, there is a dedicated way to do just that.

int x = 1;

// This is the same as
// x = x + 2;
x += 2;

// This is the same as
// x = x * 4
x *= 4;

// This is the same as
// x = x - (x * 5)
x -= (x * 5)

// This is the same as
// x = x / 6
x /= 6;

// This is the same as
// x = x % 3
x %= 3;

// Pop quiz!
System.out.println(x);

Of note is that adding or subtracting exactly 1 is common enough that it has its own special shorthand.

int x = 0;
System.out.println(x);

// Same as
// x = x + 1;
// x += 1;
x++;
System.out.println(x);

// Same as
// x = x - 1;
// x -= 1;
x--;
System.out.println(x);

Limits

Unlike in math, where numbers can be arbitrarily big or small, a Java int is "fixed width."

Say you had a piece of paper that was only big enough to write two numbers on.

The only numbers you could write in a base ten system would be those from 0 to 99. You could not write 100 or anything larger.

A Java int is similar except instead of only being able to write 0 to 99 on a piece of paper, a variable that has the type int can represent numbers from -231 to 231 - 1.

If you try to directly write out a number that is outside of that range, Java will not let you.

// This will not run
int tooBig = 999999999999;

If you do math that should produce a larger number than is representable, the value will "loop around."

// This is the value of 2^31 - 1
int atLimit = 2147483647;
// The value will "loop around" to -2^31
int beyondLimit = atLimit + 1;
// This will output -2147483648
System.out.println(beyondLimit);

There are other types which can represent a larger range of integers, as well as types which do not have any limits, but for now int is the only one you will need.

Challenges

Remember the rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        int x = 5;
        int y = 8;
        System.out.println(x + y);
    }
}

Challenge 2

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        int x = 5;
        x--;
        x--;
        x = x + x;
        System.out.println(x);
    }
}

Challenge 3

Make it so that this program correctly determines if the numbers are even or not.

Assume that the values of x, y, and z could be changed. Don't just write out literally true and false for their current values.

public class Main {
    public static void main(String[] args) {
        int x = 5;
        int y = 4;
        int z = 98;

        boolean xIsEven = < CODE HERE >;
        System.out.println(xIsEven);

        boolean yIsEven = < CODE HERE >;
        System.out.println(yIsEven);

        boolean zIsEven = < CODE HERE >;
        System.out.println(zIsEven);
    }
}

Challenge 4

Try dividing a number by zero. What happens?

Write down your guess and then try running the program below to see.

public class Main {
    public static void main(String[] args) {
        System.out.println(5 / 0);
    }
}

Challenge 5

What can you write in the spot marked that will make the program output 2?

public class Main {
    public static void main(String[] args) {
        int x = 5;
        int y = <CODE HERE>;
        System.out.println(x + y);
    }
}

Challenge 6

What is the output of this code.1

public class Main {
    public static void main(String[] args) {
        System.out.println(
            6 / 2 * (1 + 2)
        );
    }
}

Floating Point Numbers

Floating point numbers are used to represent numbers which cannot be stored as Integers like 2.5 or 3.14.

double x = 1.5;
double y = 8.0;
double z = -3.14;

The type you will use to store a floating point number is double. double stands for "double precision floating point."

Floating Point Literals

In order to write a floating point number in a program, you use a "floating-point literal."

1.5

Any number written with a decimal point is a floating point literal.

double pi = 3.14;

This includes numbers where a decimal point is written, but there is no fractional part to the number.

5.0

You cannot directly give a value to an integer variable using a floating point literal, even if there is no fractional part to the number.

// this will not work
int x = 5.0;

The reverse is possible though. You can give a value to a variable that stores a floating point number using an integer literal.

double x = 5;

Accuracy

Floating Point numbers are not an exact representation of numbers.

The reasons for this are twofold.

  1. It is much more efficient for a computer to work with data that is a "fixed size". You can't cram all the infinite possible numbers into 32, 64, or any fixed number of bits.
  2. For most systems, the inaccuracy is okay. When it is not, there are ways to do "real math" that we will cover much later.

For an explanation of the mechanics, I'll defer to this old Computerphile video.

Addition

You can add any two doubles using the + operator.

double x = 5.1;
// y will be 14.2
double y = x + 9.1;

Because of the previously mentioned inaccuracy, the results of additions might not always be what you expect.

// z will be 19.299999999999997
double z = x + y;

You can add any int to a double and the result of any such addition will also be a double.

int x = 5;
double y = 4.4;
// z will be 9.4
double z = x + y;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Even if the result of such an expression will not have any fractional parts, you cannot directly assign it to an int.

int x = 5;
double y = 4;
// even though z would be 9, which can be stored in an int
// this will not work. The result of the expression is a double.
int z = x + y;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Subtraction

You can subtract any two doubles using the - operator.

double x = 5.1;
// y will be 4.1
double y = x - 9.2;

System.out.println(x);
System.out.println(y);

Because of the previously mentioned inaccuracy, the results of subtractions might not always be what you expect.

// z will be -4.199999999999999
double z = y - 0.1;

System.out.println(z);

You can subtract any int to or from a double and the result of any such subtraction will also be a double.

int x = 5;
double y = 4.5;
// z will be 0.5
double z = x - y;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Even if the result of such an expression will not have any fractional parts, you cannot directly assign it to an int.

int x = 5;
double y = 4;
// even though z would be 1, which can be stored in an int
// this will not work. The result of the expression is a double.
int z = x - y;

Multiplication

You can multiply any two doubles using the * operator.

double x = 3;
// y will be 27
double y = x * 9;
// z will be 13.5
double z = y * 0.5;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Just like with addition and subtraction, it is fine to use both integers and integer literals when doing multiplication on doubles. So long as any number being used is a double the overall result will be a double.

// a will be 3
double a = 1.5 * 2;

Division

You can divide any two doubles using the / operator.

double x = 8;
// y will be 4.0
double y = x / 2;
// z will be 1.3333333333333333
double z = y / 3;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Unlike with integer division, floating point division will include the remainder in the result.1

1

With the caveat that the result is now potentially inaccurate.

Equality

Just like ints, doubles can be inspected to see if they are equal to one another using ==.

double numberOfToes = 10.0;
double numberOfFingers = 10.0;

boolean humanGenerated = numberOfToes == numberOfFingers;

Because of floating point inaccuracy, this might not always give you the result you expect though.

double x = 0.1;
double y = 0.2;
// z will be 0.30000000000000004
double z = x + y;

// this will be false.
boolean doesWhatYouExpect = z == 0.3;

A double can also be compared to an int and, if they represent the same value, they will be reported as equal.

int x = 5;
double y = 5.0;

// will be true
boolean fiveIsFive = x == y;

Comparison

In addition to comparing for equality with == and !=, doubless can be compared to see if one is bigger than another using >, <, >=, and <=.

This works the same as it does with ints.

double x = 1.5;
double y = 0.2;

// true
System.out.println(x > y);
// false
System.out.println(x < y);

Shorthands for Reassignment

All the same shorthands for reassignment work with doubles the same as they do with ints.

double x = 0.5;
// 0.5
System.out.println(x);

x += 3;
// 3.5
System.out.println(x);

x -= 1;
// 2.5
System.out.println(x);

x++;
// 3.5
System.out.println(x);

x--;
// 2.5
System.out.println(x);

x *= 5;
// 12.5
System.out.println(x);

x /= 2;
// 6.25
System.out.println(x);

NaN

There is a special floating point number called NaN, which stands for "Not a Number."

You generally only encounter NaN as the result of doing something silly like dividing zero by zero.

double nan = 0.0 / 0.0;

NaN is not equal to itself.

// will be false
boolean equalToItself = nan == nan;

System.out.println(equalToItself);

NaN is not greater than itself.

// will be false
boolean greaterThanItself = nan > nan;

System.out.println(greaterThanItself);

NaN is not less than itself.

// will be false
boolean lessThanItself = nan < nan;

System.out.println(lessThanItself);

NaN is not greater than, less than, or equal to any number.

// will all be false
System.out.println(nan < 5);
System.out.println(nan > 5);
System.out.println(nan == 5);

None of this is usually useful, but it is fun to know about.

Positive and Negative Infinity

In addition to the wackyness of NaN, floating point numbers can also represent both positive and negative infinity.

You can get positive infinity by dividing any positive number by zero.

double positiveInfinity = 1.0 / 0.0;

You can get negative infinity by dividing any negative number by zero.

double negativeInfinity = -1.0 / 0.0;

As you might expect, positive infinity is greater than any number and negative infinity is less than any number.

// true
System.out.println(positiveInfinity > 99999999);

// true
System.out.println(negativeInfinity < -99999999);

Except for NaN, of course.

double nan = 0.0 / 0.0;

// false
System.out.println(positiveInfinity > nan);

// false
System.out.println(negativeInfinity < nan);

Square Root

A relatively common operation to want to perform on floating point numbers is to find their square root.

You can do this with Math.sqrt.

double x = 4;
double y = Math.sqrt(x);

// This will output 2
System.out.println(y);

You need to write Math.sqrt and then inside of parentheses the expression whose value you want to take the square root of..

double x = 5;
double y = 13;
double z = Math.sqrt(9 * x + y);
 
// This will output 7.615773105863909
System.out.println(z);

If you try to take the square root of a negative number, the result will be NaN.

// will output NaN
System.out.println(Math.sqrt(-5.2));

Conversion to Integers

Normally, a double value cannot be assigned to an int.

double x = 5.0;
// will not work
int y = x;

The reason for this is that there are numbers like 2.5, the infinities, and NaN which do not have an obvious way to be represented as an integer.

There are also numbers which a double can represent like 4207483647.0 and -9999999999.0 which happen to be too big or too small to fit into the limits of an int even though they do have an obvious "integer representation."

As such, to make an int out of a double you need to accept that it is a "narrowing conversion." The number you put in won't neccesarily be the number you get out.

To perform such a narrowing conversion, you need to put (int) before a literal or expression that evaluates to a double.

double x = 5.0;
// will be 5
int y = (int) x;

System.out.println(y);

Any decimal part of the number will be dropped. So numbers like 2.1, 2.5, and 2.9 will all be converted into simply 2.

int x = (int) 2.1;
int y = (int) 2.5;
int z = (int) 2.9;

System.out.println(x);
System.out.println(y);
System.out.println(z);

Any number that is too big to store in an int will be converted to the biggest possible int, 231 - 1.

// 2147483647
System.out.println((int) 4207483647.0);

double positiveInfinity = 5.0 / 0.0;
// 2147483647
System.out.println((int) positiveInfinity);

Any number that is too small to store in an int will be converted to the smallest possible int, -231.

// -2147483648
System.out.println((int) -9999999999.0);

double negativeInfinity = -5.0 / 0.0;
// -2147483648
System.out.println((int) negativeInfinity);

And NaN will be converted to zero.

double nan = 0.0 / 0.0;
System.out.println((int) nan);

When you use (int) to convert, we call that a "cast1 expression". The (int) is a "cast operator." It even has a place in the operator precedence order just like +, -, ==, etc.

The main difference is that instead of appearing between two expressions like the + in 2 + 5, it appears to the left of a single expression.

1

https://english.stackexchange.com/questions/220001/etymology-of-type-cast

Conversion from Integers

To convert from an int to a double, you don't need to do any special work. All ints are representable as doubles so it is a "widening conversion" and will be handled automatically by Java when performing an assignment.

int x = 5;
double y = x;

System.out.println(x);
System.out.println(y);

This is not true in an expression. Even if the result of a computation between ints is being assigned to a double, the computation will still be performed using the same rules ints usually follow.

int x = 7;
int y = 2;
// integer division of 7 and 2 gives 3.
double z = x / y;

System.out.println(z);

To perform math on an int and have that int behave as if it were a double, you need to convert said int into a double using a cast expression and the (double) cast operator.

int x = 7;
int y = 2;
// This converts x into a double before performing the division
// so the result will be 3.5.
double z = (double) x / y;

System.out.println(z);

Challenges

Remember the rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        double x = 5.1;
        double y = 2.4;
        System.out.println(x + y);
    }
}

Challenge 2

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        double x = 5.1;
        double y = 2.1;
        System.out.println(x + y);
    }
}

Challenge 3

What will this program output when run? Write down your guess and then try running it.

How can you make it give the "right" answer?

public class Main {
    public static void main(String[] args) {
        double x = 5 / 2;
        System.out.println(x);
    }
}

Challenge 4

These two expressions give different results. Why is that, and what results do they give?

double resultOne = (int) 5.0 / 2 + 5.0 / 2;
double resultTwo = (int) (5.0 / 2 + 5.0 / 2);

System.out.println(resultOne);
System.out.println(resultTwo);

Challenge 5

The following is a quadratic equation.

\[ 2x^2 + 8x + 3 = 0 \]

To find the solutions of any quadratic equation you can use the following formula.

\[ x = \frac{-b \pm \sqrt{b^2 - 4ac} }{2a} \]

Where \(a\), \(b\), and \(c\) are the prefixes of each term in the following equation.

\[ ax^2 + bx + c = 0 \]

Write some code that finds both solutions to any quadratic equation defined by some variables a, b, and c. If the equation has imaginary solutions, you are allowed to just output NaN.

public class Main {
    public static void main(String[] args) {
        // For this one in particular, you should output
        // -3.5811388300842 and -0.41886116991581
        // but your code should work with these three numbers changed to
        // represent any given quadratic equation.
        double a = 2;
        double b = 8;
        double c = 3;

        double resultOne = ???;
        double resultTwo = ???;

        System.out.println(resultOne);
        System.out.println(resultTwo);
    }
}

Characters

A character, represented by the data type char, is a single letter or symbol.

char letter = 'a';

I choose to pronounce it like the "char" in "Charmander."

Character Literals

In order to write a character in a program, you write that one character surrounded by single quotes.

'a'

This is called a "character literal." It has the same relationship to char that an integer literal like 123 has to int.

// Same as this "integer literal" is used to write a number
int sesameStreet = 123;
// A "character literal" is used to write text
char thisEpisodeIsBroughtToYouBy = 'c';

Common Escape Sequences

While most characters can be written directly into a program, as is the case for a, b, or t, there are some which cannot.

For these, you need to use what is called an "escape sequence."

The most common escape sequence you will use will be the one for a "new line." Which is a backslash followed by an n.

char newline = '\n';

Because a backslash is used for this special syntax, to put a backslash into a character literal you need to escape it with a backslash of its own.

char backslash = '\\';

And because single quotes are used to mark the start and end of a character literal, they need to be escaped as well.

char singleQuote = '\'';

Conversion to Integers

All chars have a matching numeric value. 'a' is 97, 'b' is 98, '&' is 38, and so on.

Same as assigning an int to a double, you can perform a widening conversion by attempting to assign a char to an int.

int valueOfA = 'a';

System.out.println(valueOfA);

chars will be automatically converted to ints when used with mathmatical operators like +, -, >, <, etc.

char gee = 'g';

// all the letters from a to z have consecutive numeric values.
boolean isLetter = gee >= 'a' && gee <= 'z';

System.out.println(isLetter);

This can be useful if you are stranded on Mars1 or if you want to see if a character is in some range.

1

https://www.youtube.com/watch?v=k-GH3mbvUro

Conversion from Integers

An int can represent more values than a char, so conversion from int to char requires the use of the cast operator (char).

int x = 120;

char xAsChar = (char) x;

System.out.println(xAsChar);

This conversion is narrowing, so information might be lost if the int value is too big or too small to fit into a char.

The initial value of a char can also be given by an integer literal if the integer literal represents a small enough letter.

char z = 122;

System.out.println(z);

Unicode

Most letters and symbols that are common in the English speaking world fit into a single char, so pretending that a char is always "a single letter or symbol" is generally a good enough mental model.

Where this falls apart is with things like emoji (👨‍🍳) which are generally considered to be one symbol, but cannot be represented in a single char.

char chef = '👨‍🍳';

chars are actually "utf-16 code units". Many symbols require multiple "code units" to represent.

For a full explanation, refer to this old Computerphile video.

It describes "utf-8", which is 8 bits per "code unit." Java's char uses 16 bits, but that is the only difference.

Challenges

Remember the rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

A lot of math problems ask you to find \( x^2 \). What is the value of the character x squared?

Try to work it out on paper before running the program below.

public class Main {
    public static void main(String[] args) {
        char x = 'x';

        System.out.println(x * x);
    }
}

Challenge 2

Alter the program below so that it will output true if the character declared at the top is a letter.

Make use of the fact that the numeric values for a - z and A - Z are contiguous.

public class Main {
    public static void main(String[] args) {
        char c = 'a';

        boolean isLetter = ???;

        System.out.println(isLetter);
    }
}

Challenge 3

How many UTF-16 code units does it take to represent this emoji? 👨‍🍳.

Strings

The String data type is used to represent text.

String shortStory = "Everyone lived happily ever after, the end."

The word "string" comes from the fact that text is just individual characters "strung together".

As a concrete example j, o, and e can be "strung together" into the "string" joe.

String Literals

In order to write text in a program, you surround it with double quotes.

"Hello, World"

This is called a "string literal." It has the same relationship to String that an integer literal like 123 has to int.

// Same as this "integer literal" is used to write a number
int abc = 123;
// A "string literal" is used to write text
String name = "penelope";

Common Escape Sequences

Inside of a string literal, there are some characters that cannot be written normally.

An easy example is double quotes. You can't write double quotes in the middle of a string literal because Java will think the extra quote is the end of the String.

String title = "The "Honorable" Judge Judy";

In order to make it work, the "s need to be "escaped" with a backslash.

String title = "The \"Honorable\" Judge Judy";

Since the backslash is used to escape characters, it too needs to escaped in order to have it be in a String. So to encode ¯\_(ツ)_/¯ into a String you need to escape the first backslash.

// The first backslash needs to be escaped. ¯\_(ツ)_/¯
String shruggie = "¯\\_(ツ)_/¯";

And much the same as with char, you need to use \n to write in a newline.

String letter = "To Whom It May Concern,\n\nI am writing this letter to complain.";

The Empty String

There is a special String which contains no characters at all.

// There is nothing to say.
String conversationWithDog = "";

You write it just like any other string, just with nothing between the double quotes.

""

It is different from a String that just contains spaces because to Java those "space characters" are just as much real characters as a, b, or c.

// There is noteworthy silence.
String conversationWithInlaws = " ";

This is one of those things that feels totally useless, but comes in handy pretty often.

  • Say you are writing a message to send to your friend. The messenger app can represent the state of the input box before you type anything with an empty String.
  • If you want to digitally record responses to legal paperwork, you might choose to represent skipped fields as empty Strings.
  • Video Games where characters have assigned names can assign an empty String as the name of otherwise "unnamed" characters.
  • etc.

Multiline Strings

If the text you want to store in a String has multiple lines, you can use three quotation marks to represent it in code.

String poem = """
    I met a traveller from an antique land,
    Who said—“Two vast and trunkless legs of stone
    Stand in the desert. . . . Near them, on the sand,
    Half sunk a shattered visage lies, whose frown,
    And wrinkled lip, and sneer of cold command,
    Tell that its sculptor well those passions read
    Which yet survive, stamped on these lifeless things,
    The hand that mocked them, and the heart that fed;
    And on the pedestal, these words appear:
    My name is Ozymandias, King of Kings;
    Look on my Works, ye Mighty, and despair!
    Nothing beside remains. Round the decay
    Of that colossal Wreck, boundless and bare
    The lone and level sands stretch far away.
    """;

Inside of the this "Multiline String Literal" you don't need to escape quotation marks " and you gain the ability to write newlines without having to use \n.

Concatenation

Any two strings can be concatenated by using the + operator.

String he = "he";
String llo = "llo";

String hello = he + llo;

System.out.println(hello);

This will make a new String where the characters from the first one all appear followed by the characters in the second one.

If you try to concatenate a String to something that is not a String, like an int or a double, then the result will be a new String with the characters from the "string representation" of that other thing.

int numberOfApples = 5;
double dollahs = 1.52;

String message = "I have " + numberOfApples + 
    " apples and $" + dollahs + " in my pocket.";

System.out.println(message);

Equality

You can check if two Strings have the same contents by using .equals.

String lyricOne = "Green, Green, Dress";
String lyricTwo = "Green, Green, Dress";

boolean areSameLyric = lyricOne.equals(lyricTwo);
boolean isMyName = lyricOne.equals("Bop Bop");

System.out.println(areSameLyric);
System.out.println(isMyName);

You write one String on the left, .equals, and then the String you want to check it against inside of parentheses.

To see if strings have different contents, you need to use the not operator (!) on the result of .equals.

String bow = "bow";
String wow = "WOW";

boolean areNotSame = !bow.equals(wow);

System.out.println(areNotSame);

Length

The number of chars which comprise a String can be accessed by using .length().1

String fruit = "strawberry";
int numberOfChars = fruit.length();

// strawberry is 10 characters long
System.out.println(
    fruit + " is " numberOfChars + " characters long"
);
1

This is different from the number of unicode codepoints.

Access Individual Characters

Given a String, you can access the individual characters which comprise it by using .charAt.

The first character can be accessed by putting 0 in the parentheses. The second by using 1, and so on.

String spy = "loid";

char l = spi.charAt(0);
System.out.println(l);

char o = spi.charAt(1);
System.out.println(o);

char i = spi.charAt(2);
System.out.println(i);

char d = spi.charAt(3);
System.out.println(d);

We call this number the "index" of the character.1

The index of the character to access can come from a variable.

String assassin = "yor";
int indexOfR = 2;

char r = assassin.charAt(indexOfR);
System.out.println(r);

If you give a number equal to or greater than the length of the String or a number less than zero, you will get an error.

String student = "anya";
// Crash!
student.charAt(999);
String dog = "bond";
// Crash!
dog.charAt(-1);
1

There will be more things which have their individual elements accessible by indexes. They will all generally start from 0 for the first element but there are rare exceptions.

Challenges

Remember the rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        String first = "1";
        String second = "2";
        String result = first + second;
    
        System.out.println(result);
    }
}

Challenge 2

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        String first = "1";
        int second = 2;

        System.out.println(first + second);
    }
}

Challenge 3

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        char first = 'a';
        String second = "b";
        String third = "ab";
    
        System.out.println((first + second).equals(second));
    }
}

Challenge 4

Make it so this program will output abc by only changing one line and not altering the println statement.

Before your change, why does it output 294?

public class Main {
    public static void main(String[] args) {
        char a = 'a';
        char b = 'b';
        char c = 'c';
        // Change above this line
        System.out.println(a + b + c);
    }
}

Challenge 5

Without adding any new printlns, change one line in this program so that it outputs racecar.

Try to find two ways to do that.

public class Main {
    public static void main(String[] args) {
        String racecar = "racecar";

        int diff = 1;

        int index = 6;

        System.out.print(racecar.charAt(index));
        index += diff;
        System.out.print(racecar.charAt(index));
        index += diff;
        System.out.print(racecar.charAt(index));
        index += diff;
        System.out.print(racecar.charAt(index));
        index += diff;
        System.out.print(racecar.charAt(index));
        index += diff;
        System.out.print(racecar.charAt(index));
        index += diff;
        System.out.println(racecar.charAt(index));
    }
}

Branching Paths

All the code I have shown you so far has run from top to bottom. That is, it has followed a single "path."

Not all programs can follow a single path though.

Imagine trying to rent a car online. The first thing you might be asked is your age. This is because most car rental companies do not want to rent to people under the age of 25.1.

If you enter an age that is less than 25, the program should immediately tell you that you cannot rent a car. If you enter an age that is greater than or equal to 25, the program should continue to prompt you for more information.

There are multiple "branching paths" that the program might take.

1

For insurance reasons.

If

The way to represent a branching path in Java is by using an if statement.

int age = 5; // 👶
if (age < 25) {
    System.out.println("You are too young to rent a car!");
}

You write the word if followed by an expression which evaluates to a boolean inside of ( and ). This expression is the "condition". Then you write some code inside of { and }.

if (CONDITION) {
    <CODE HERE>
}

When the condition evaluates to true, the code inside of the { and } will run. If it evaluates to false that code will not run.

In this example the condition is age < 25. When age is less than 25 it will evaluate to true and you will be told that you cannot rent a car.

int age = 80; // 👵
if (age < 25) {
    System.out.println("You are too young to rent a car!");
}

If this condition evaluates to false, then the code inside of { and } will not run.

Else

When you want to do one thing when a condition evaluates to true and another when that same condition evaluates to false you can use else.

int age = 30; // 🙎‍♀️
if (age < 25) {
    System.out.println("You cannot rent a car!");
}
else {
    System.out.println("You might be able to rent a car.");
}

You write the word else immediately after the } at the end of an if statement, then some code inside of a new { and }.

if (CONDITION) {
    <CODE TO RUN>
}
else {
    <CODE TO RUN>
}

When the condition evaluates to false, the code inside of else's { and } will run.

else cannot exist without a matching if, so this code does not work.

else {
    System.out.println("No if.");
}

Nested Ifs

The code inside of the { and } can be anything, including more if statments.

int age = 5; // 👶
if (age < 25) {
    System.out.println("You are too young to rent a car!");
    if (age == 24) {
        System.out.println("(but it was close)");
    }
}

When an if is inside another if we say that it is "nested".

If you find yourself nesting more than a few ifs that might be a sign that you should reach out for help.

if (...) {
    if (...) {
        if (...) {
            if (...) {
                // Seek professional help
            }
        }
    }
}

Else If

If you have an if nested in an else branch, you can simplify that by using else if.

boolean cool = true; // 🕶️
int age = 30; // 🙎‍♀️
if (age < 25) {
    System.out.println("You cannot rent a car!");
}
else {
    if (!cool) {
        System.out.println("You failed the vibe check.");
    }
    else {
        System.out.println("You are rad enough to rent a car.");
    }
}

So the following will work the same as the code above.

boolean cool = true; // 🕶️
int age = 30; // 🙎‍♀️

if (age < 25) {
    System.out.println("You cannot rent a car!");
}
else if (!cool) {
    System.out.println("You failed the vibe check.");
}
else {
    System.out.println("You are rad enough to rent a car.");
}

You can have as many else ifs as you need. Each one will only run if all the previous conditions evaluate to false.

boolean cool = true; // 🕶️
int age = 100; // 👴

if (age < 25) {
    System.out.println("You cannot rent a car!");
}
else if (!cool) {
    System.out.println("You failed the vibe check.");
}
else if (age > 99) {
    System.out.println("You are too old to safely drive a car!");
}
else if (age > 450) {
    System.out.println("There can only be one! ⚔️🏴󠁧󠁢󠁳󠁣󠁴󠁿");
}
else {
    System.out.println("You are rad enough to rent a car.");
}

Relation to Delayed Assignment

Delayed assignment of variables becomes useful with if and else.

So long as Java can figure out that a variable will always be given an initial value inside of an if and else, you will be allowed to use that variable.

int age = 22;

String message;
if (age > 25) {
    message = "You might be able to rent a car";
}
else {
    message = "You cannot rent a car!";
}

System.out.println(message);

If it will not always be given an initial value, then you will not be allowed to use that variable.

int age = 22;

String message;
if (age > 25) {
    message = "You might be able to rent a car";
}

// message is not always given an initial value
// so you cannot use it.
System.out.println(message);

Conditional Operator

When the only operation being performed inside of an if and else pair is setting the initial value of a variable, you can use the "conditional operator"1 to perform that assignment instead.

int age = 22;

String message = age < 25 
    ? "You cannot rent a car!"
    : "You might be able to rent a car";

You write a condition followed by a ?, a value to use when that condition evaluates to true, a :, and then a value to use when that condition evaluates to false.

CONDITION ? WHEN_TRUE : WHEN_FALSE
1

Some people will call this a ternary expression. Ternary meaning "three things." Same idea as tres leches.

Boolean Expressions

A common thing I've seen students do is set the initial value of some boolean variable based on some condition.

int age = 22;

boolean canRent;
if (age > 25) {
    canRent = true;
}
else {
    canRent = false;
}

// or
// boolean canRent = age > 25 ? true : false;

System.out.println(canRent);

This is valid code, but very often can be made simpler if you remember that the condition itself already evaluates to a boolean. You can directly assign the variable to that value.

int age = 22;
boolean canRent = age > 25;

System.out.println(canRent);

Challenges

Remember the rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

Write code that will outputs The number is even if x is an even number.

public class Main {
    public static void main(String[] args) {
        // Change this variable to different numbers
        // to test your code
        int x = 5;

        // < YOUR CODE HERE >
    }
}

Challenge 2

Make it so that your code from the previous problem will also output The number is odd if the number is odd.

Challenge 3

Write code that will output allowed if the the password variable is equal to "abc123" and not allowed if it isn't.

public class Main {
    public static void main(String[] args) {
        // Change this variable to different strings
        // to test your code
        String password = "apple";

        // < YOUR CODE HERE >
    }
}

Challenge 4

Write code that will assign the string The number is {x} even to message if x is an even number and The number is {x} odd if x is an even number.

So if x is 12 the string you should assign The number 12 is even to message.

public class Main {
    public static void main(String[] args) {
        String message;

        // Change this variable to different numbers
        // to test your code
        int x = 5;

        // < YOUR CODE HERE >

        System.out.println(message);
    }
}

Loops

if and else let you write programs which can take branching paths, but they will still run from the beginning to the end.

Not all programs can just end though. Video games should draw their world at one second and do it again the next. If you enter the wrong password on your phone, it should ask you for your password again.

This is what "loops" are for. You run code starting from some point and then loop back to that same point and run that code again.

While

One way to make a loop in code is to use while.

int x = 5;
while (x != 0) {
    System.out.println(x);
    x--;
}

You write while followed by a condition inside of ( and ) and some code inside of { and }.

while (CONDITION) {
    <CODE HERE>
}

If the condition evaluates to true then the code inside of { and } will run. After that code runs, the condition will be evaluated again. If it still evaluates to true then the code { and } will run again.

This will continue until the code in the condition evaluates to false.

int glassesOfMilk = 99;
while (glassesOfMilk > 0) {
    System.out.println(
        glassesOfMilk + " glasses of milk left"
    );

    glassesOfMilk--;
}

If a loop is made with while we call it a "while loop."1

1

"We called him Tortoise because he taught us." - Lewis Carroll

Endless Loops

If a while loop will never end, we call that an endless loop.

This can happen if the condition is a constant like while (true)

while (true) {
    System.out.println("This is the song that never ends");
}

Or if the variables tested in the condition are not updated inside of the loop.

// x is never changed
int x = 0;
while (x != 1) {
    System.out.println("It goes on and on my friends");
}

Many games should never really "finish" so at the very start of that sort of program it is not uncommon to see a while (true).

Break

While loops will usually stop running when the condition at the top evaluates to false.

This can be bypassed by using the break statement.

int x = 5;
while (x > 0) {
    if (x == 2) {
        break;
    }
    x--;
}

System.out.println(
    "Final value of x is " + x
);

If a break is reached, the code in the loop stops running immediately. The condition of the loop is not checked again.

This can be useful in a variety of situations, but notably it is the only way to exit from an otherwise endless loop.

while (true) {
    System.out.println(
        "The people started singing it not knowing what it was"
    );

    // Will immediately leave the loop
    break;
}

Continue

Unless there is a break, while loops will usually run all the code in their body from top to bottom.

The only other situation this will not happen is if a continue statement is reached.

// Will output a message for every number except 4
int x = 5;
while (x > 0) {
    if (x == 4) {
        continue;
    }
    System.out.println(x + " is a good number");
    x--;
}

If a continue is reached the code in the loop stops running immediately but, unlike break, the condition of the loop is checked again. If it still evaluates to true then the code in the loop will run again.

Unreachable Code

If you write some code directly after a break or continue that code will be "unreachable."

Java knows this and so won't let any code like that run.

// This will not work
while (true) {
    continue;

    System.out.println("this is unreachable");
}

Do

One variation on a while loop is a "do-while loop."

int x = 0;
do {
    System.out.println(x);
    x++
} while(x < 5);

You write do, some code inside of { and }, and then while, a condition inside of ( and ), and finally a semicolon.

do {
    <CODE HERE>
} while (CONDITION);

In most situations it works exactly the same as a regular while loop. The only difference is that the first time the loop is reached the condition for the loop is not checked.

int x = 0;
do {
    System.out.println("this will run");
} while (x != 0)

while (x != 0) {
    System.out.println("this will not run");
}

One way to remember the difference is that in a "do-while loop" you always "do the thing" at least once.

Nested Loops

Just like with if, The code inside of the { and } can be anything, including more loops.

int x = 5;
int y = 3;

while (x != 0) {
    while (y != 0) {
        System.out.println(
            "x is " + x
        );
        System.out.println(
            "y is " + y
        );

        x--;
        y--;
    }
}

If you are inside such a "nested loop", continue and break apply to the "closest" loop.

That is, if a continue or a break were to appear here

while (x != 0) {
    while (y != 0) {
        if (y == 2) {
            break;
        }

        System.out.println(
            "x is " + x
        );
        System.out.println(
            "y is " + y
        );

        x--;
        y--;
    }
}

Then the y != 0 loop will be broken out of, not the x != 0 one. And if a continue or a break were to appear here

while (x != 0) {
    if (x == 2) {
        break;
    }
    while (y != 0) {


        System.out.println(
            "x is " + x
        );
        System.out.println(
            "y is " + y
        );

        x--;
        y--;
    }
}

Then the x != 0 loop would be the "target."

Labeled Break

If you want to break out of a nested loop from one of the inner loops, you can use a "labeled break."

outerLoop:
while (true) {
    while (true) {
        break outerLoop;
    }
}

To do this, before your outer while or do-while loop you need to add a "label" followed by a :. A label is an arbitrary name just like a variable's name.

<LABEL>:
while (<CONDITION>) {
    <CODE HERE>
}
<LABEL>:
do {
    <CODE HERE>
} while (<CONDITION>);

Then inside of an inner loop, you just need to write break followed by the label name.

int x = 5;
int y = 3;

xLoop:
while (x != 0) {
    while (y != 0) {
        if (x == 2 && y == 2) {
            break xLoop;
        }

        System.out.println(
            "x is " + x
        );
        System.out.println(
            "y is " + y
        );

        x--;
        y--;
    }
}

System.out.println("done.")

In this case the x != 0 loop will be broken out of, not the y != 0 one.

Labeled Continue

In the same way a labeled break can break out of a nested loop, a labeled continue can jump back to the start of a nested loop.

You just write continue followed by the label name.

// Will keep going back to the top of the outer loop
outerLoop:
while (true) {
    System.out.println("inside outer loop");
    while (true) {
        System.out.println("inside inner loop");
        continue outerLoop;
    }
}

Iteration

Loops potentially run code multiple times. Each time one goes from its top to its bottom we call that an "iteration" of the loop.

int x = 0;
while (x < 5) {
    // On the 1st iteration x will be 0
    // On the 2nd iteration x will be 1
    // ...
    // On the final iteration x will be 4
    System.out.println(x);
    x++
}

When the purpose of a loop is to run for every thing in some sequence of things, we say that the loop is "iterating over" those things.

Counting Up

Say your loop is intended to run some code for every number from 1 to 100.

The general pattern for code like this is to have some variable which tracks the current number, a loop whose condition is that the number is less than the number you want to stop at, and a line at the bottom of the loop which increments the current number.

int currentNumber = 1;
while (currentNumber <= 100) {
    System.out.println(currentNumber);
    currentNumber++;
}

Take note that in this example the condition is currentNumber <= 100, so the code in the loop will run when currentNumber is equal to 100. If the condition was currentNumber < 100 it would stop at 99.

int currentNumber = 1;
// Stops at 99
while (currentNumber < 100) {
    System.out.println(currentNumber);
    currentNumber++;
}

Counting Down

If you want to do the opposite, starting from a number like 100 and count down to 1, the pattern will be similar.

You still have some variable tracking the current number, but with a loop whose condition is that the number is greater than the number you want to stop at, and a line at the bottom of the loop which decrements the current number.

int currentNumber = 100;
while (currentNumber >= 1) {
    System.out.println(currentNumber);
    currentNumber--;
}

Similar to when counting up if the condition was not currentNumber >= 1 and instead was currentNumber > 1, the loop would stop at 2

int currentNumber = 100;
// Stops at 2
while (currentNumber > 1) {
    System.out.println(currentNumber);
    currentNumber--;
}

Iterate over a String

This general pattern of counting up and counting down becomes especially useful when you want to iterate over each character in a String.

String name = "Avril";

int index = 0;
while (index < name.length()) {
    System.out.println(name.charAt(index));
    index++;
}

Challenges

Early on, most students tend to have a lot of trouble with loops. Its also what is quizzed on in a lot of standardized tests.

Because of that there will be a lot of challenges in this section for you to practice. Try to at least do the first ten or so to make sure you have the concept down, but the more the better.

It might take awhile before you feel truly comfortable with this. That is normal.

Remember the rules for this are

  • Try to use only the information given up to this point in this book.
  • Try not to give up until you've given it a solid attempt

Challenge 1

Write code that outputs every number from 1 to 10.

public class Main {
    public static void main(String[] args) {
        <CODE HERE>
    }
}

Challenge 2

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        int x = 0;
        while (x < 10) {
            System.out.println(x);
            x++;
        }
    }
}

Challenge 3

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        int x = 0;
        while (x <= 10) {
            System.out.println(x);
            x++;
        }
    }
}

Challenge 4

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        int x = 0;
        while (x < 10) {
            if (x % 3 == 0) {
                break;
            }
            System.out.println(x);
            x++;
        }
    }
}

Challenge 5

What will this program output when run? Write down your guess and then try running it.

public class Main {
    
    public static void main(String[] args) {
        int x = 0;
        while (x < 10) {
            if (x % 3 == 0) {
                continue;
            }
            System.out.println(x);
            x++;
        }
    }
}

Challenge 6

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        int x = 1;
        while (x < 10) {
            int y = 2;
            while (y < 5) {
                System.out.println(x * y);
                y++;
            }
            
            x++;
        }
    }
}

Challenge 7

What will this program output when run? Write down your guess and then try running it.

public class Main {
    public static void main(String[] args) {
        int x = 0;
        String scream = "a";
        while (!scream.equals("aaaaaaaa")) {
            scream = scream + "a";
            System.out.println(x);
            System.out.println(scream);
        }
    }
}

Challenge 8

Write code that will output each character of name on its own line.

So for if name is equal to "Bridget", I would expect the following as output.

B
r
i
d
g
e
t
public class Main {
    public static void main(String[] args) {
        // Change this value to test your code.
        String name = "Bridget";

        // <CODE HERE>
    }
}

Challenge 9

Write code that will output each character of name on its own line, starting with the last character and going backwards.

So for if name is equal to "Samantha", I would expect the following as output.

a
h
t
n
a
m
a
S
public class Main {
    public static void main(String[] args) {
        // Change this value to test your code.
        String name = "Samantha";

        // <CODE HERE>
    }
}

Challenge 10

Write code that will take a number and if it is divisible by two, divides it by two. If it is not, multiplies it by three and adds one.

Keep doing this until the number equals one. Output it each time.

If the initial number is 6 you should have this as output.

6
3
10
5
16
8
4
2
1

If the initial number is 15 you should have this as output.

15
46
23
70
35
106
53
160
80
40
20
10
5
16
4
2
1
public class Main {
    public static void main(String[] args) {
        // Change this value to test your code.
        int n = 15;

        // <CODE HERE>
    }
}

Challenge 11

Write code that outputs every third number from 37 to 160.

public class Main {
    public static void main(String[] args) {
        <CODE HERE>
    }
}

Challenge 12

Write code that outputs the number of vowels in name. Treat y as a vowel.

Treat the characters a, A, e, E, i, I, o, O, u, U, y, and Y as vowels.

public class Main {
    public static void main(String[] args) {
        // Change this value to test your code.
        String name = "Damian";

        // <CODE HERE>
    }
}

Challenge 13

Write code that outputs {name} is mostly vowels if the number of vowels in name is greater than the number of consonants. and {name} is mostly consonants if the opposite is true. Output {name} has an equal number of vowels and consonants if the count of both is the same.

Make sure to not treat non-alphabetic characters like ! and ? as consonants.

public class Main {
    public static void main(String[] args) {
        // Change this value to test your code.
        String name = "Messi";

        // <CODE HERE>
    }
}

Challenge 14

Rewrite the following code to not have the shouldBreak variable and instead to use a labeled break.

public class Main {
    public static void main(String[] args) {
        // Don't think too hard about what these numbers mean.
        int x = 3;
        int y = 0;

        boolean shouldBreak = false;
        while (shouldBreak && x < 100) {
            while (y < 100) {
                System.out.println("x is " + x);
                System.out.println("y is " + y);
                x = x * y;
                if (x == 0) {
                    shouldBreak = true;
                    break;
                }
                y++;
            }
        }

        System.out.println("Done");
    }
}

Arrays

Arrays are used to represent a fixed-size collection of things.

int[] oddNumbers = { 1, 3, 5, 7, 9 };

Fixed-size means that once an array is made, it will always hold the same number of things.

We call the things stored in an array its "elements."

You can make an array of any type of element by using the name of the type followed by [].

char[] letters = { 'a', 'b', 'c' };
String[] words = { "its", "as", "easy", "as" }
int[] numbers = { 1, 2, 3 };
double[] doubles = { 97.0, 98.0, 99.0, 1.0, 2.0, 3.0 };

Array Initializers

To give an initial value to an array you can use an array initializer.

After the equals sign you write { followed by a comma separated list of elements and a final }.

int[] numbers = { 1, 2, 3 }
             // |---------|
             // this part is
             // the initializer

The elements in an initializer do not have to be literals and can also be variables or expressions.

int two = 2;
// Will hold 1, 2, 3 just like the array above 
int[] numbers = { 1, two, two + 1 }

We call them array initializers because you use them to give an initial value to an array.1

1

You may be noticing a pattern. Confusing sounding names are often kinda "obvious" with enough context.

Length

The number of elements which comprise an array can be accessed by using .length.1

String[] veggies = { "brussels", "cabbage", "carrots" };
int numberOfElements = veggies.length;

// veggies is 3 elements long
System.out.println(
    "veggies is " numberOfElements + " characters long"
);
1

Unlike with a String, you do not write () after .length.

Access Individual Elements

Given an array, you can access any of its elements by index.

You write the name of a variable containing an array, [, a number, and then a ].

The first element can be accessed by using 0, the second by using 1, and so on.

String[] lyrics = { "you", "say", "goodbye" };

String you = lyrics[0];
System.out.println(you);

String say = lyrics[1];
System.out.println(say);

String goodbye = lyrics[2];
System.out.println(goodbye);

The index of the element can also come from a variable.

int index = 2;
String[] lyrics = { "I", "say", "hello" };

System.out.println(lyrics[index]);

If you give a number equal to or greater than the length of the array or a number less than zero, you will get an error.

String[] lyrics = { "I", "say", "hi" };
// Crash!
lyrics[999];
String[] lyrics = { "you", "say", "low" };
// Crash!
lyrics[-1];

Set Individual Elements

You can also set any of the elements of an array to have a new value.

To do this, on the left hand side of an equals sign you write the name of a variable followed by [, an index, and ]. Then on the right hand side of the equals you write the new value.1

String[] sentence = { "you", "are", "found", "guilty" };
System.out.println(sentence);

sentence[1] = "aren't";
System.out.println(sentence);

The index of the element to set can also come from a variable.

int index = 2;
String[] response = { "and", "it", "isn't", "opposite", "day" };
System.out.println(response);

response[2] = "is";
System.out.println(response);

If you give a number equal to or greater than the length of the array or a number less than zero, you will get an error.

String[] response = { "objection" };
// Crash
response[1] = "!";
String[] response = { "sustained" };
// Crash
response[-1] = "not";
1

You cannot change the contents of a String like you would an array. This is one of the biggest differences between a String and a char[].

Aliasing

When you assign a variable containing an array to another variable, the array referenced by both variables will be the exact same.

This means that if the contents of the array are updated, that change will be reflected by both variables.

char[] lettersOne = { 'B', 'a', 't', 'm', 'a', 'n' };
char[] lettersTwo = lettersOne;

// Batman
System.out.println(lettersOne);
// Batman
System.out.println(lettersTwo);

lettersOne[0] = 'C';

// Catman
System.out.println(lettersOne);
// Catman
System.out.println(lettersTwo);

lettersTwo[0] = 'R';

// Ratman
System.out.println(lettersOne);
// Ratman
System.out.println(lettersTwo);

When two variables point to the same thing like this we say that both variables are "aliases" for eachother.

Reassignment

The length of an array cannot change, but a variable holding an array can be reassigned to a new array that has a different length.

int[] numbers = { 1, 2 };
// 2
System.out.println(numbers.length);

numbers = { numbers[0], numbers[1], 3 };
// 3
System.out.println(numbers.length);

This reassignment will not be affect any variables which are aliases for the variable's old value.

char[] wordOne = { 'g', 'o' };
char[] wordTwo = wordOne;
// go
System.out.println(wordOne);
// go
System.out.println(wordTwo);

wordOne = { wordOne[0], wordOne[1], 's', 'h' };

// gosh
System.out.println(wordOne);
// go
System.out.println(wordTwo);

wordTwo[0] = 'n';

// gosh
System.out.println(wordOne);
// no
System.out.println(wordTwo);

wordOne[0] = 'p';

// posh
System.out.println(wordOne);
// no
System.out.println(wordTwo);

Relation to Final Variables

Just like anything else, arrays can be stored in variables marked final.

This means that the variable cannot be reassigned, but it does not mean that the array's contents cannot be changed directly or through an alias.

final char[] catchphrase = { 'w', 'o', 'a', 'h', '!' };
// woah!
System.out.println(catchphrase);

// Cannot reassign
// catchphrase = { 'e', 'g', 'a', 'd', 's' }
// but can set elements directly
catchphrase[0] = 'e';
catchphrase[1] = 'g';

// or through an alias
char[] alias = catchphrase;
alias[2] = 'a';
alias[3] = 'd';
alias[4] = 's';

// egads
System.out.println(catchphrase);

Printing the Contents of an Array

If you try to use System.out.println to output a String[] you won't see the contents of the array. Instead you will see something like [Ljava.lang.String;@1c655221.

String[] shout = { "fus", "ro", "dah" };
// [Ljava.lang.String;@5a07e868
System.out.println(shout);

A similar thing will happen with int[], boolean[], and double[].1

int[] nums = { 11, 11, 11 };
// [I@5a07e868
System.out.println(nums);

boolean[] bools = { true, false };
// [Z@5a07e868
System.out.println(bools);

double[] doubles = { 1.1, 1.1, 1.1 };
// [D@5a07e868
System.out.println(bools);

The only kind of array which will include its contents when printed is a char[]. It will be printed as if it were a String.

char[] continent = { 'T', 'a', 'm', 'r', 'i', 'e', 'l' };
// Tamriel
System.out.println(continent);

If you want to actually see the contents of an array, you should use a loop.2

String[] factions = { "empire", "stormcloaks", "dragons" };

int index = 0;
while (index < factions.length) {
    System.out.println(factions[index])
    index++
}
1

What [I@5a07e868 and co. mean isn't really important. Try not to get too distracted by it.

2

Later on, there will be easier ways to do this sort of inspection. This is just the one I can demonstrate now.

Empty Array

If you use an array initializer that has no elements between the { and } you can create an empty array.

char[] emptyCharArray = {};

An empty array is very similar to an empty String. It has a length of 0, it has no elements, and it is generally useful only as a placeholder value for when you have no data yet but will be able to reassign the variable holding it when you get some.

char[] emptyCharArray = {};

// 0
System.out.println(emptyCharArray.length);

// Crash
System.out.println(emptyCharArray[0]);

Difference between Initializer and Literal

The reason { 1, 2, 3 } is called an "array initializer" and not an "array literal" is somewhat subtle.

When you have a literal, like a String literal, you can assign that to a variable and then use that String afterwards.

String name = "Alana";
// l
System.out.println(name.charAt(1));

But you can also perform those operations using the literal itself, without an intermediate variable.

// l
System.out.println("Alana".charAt(1));

Array initializers work in the case where you first assign them to a variable before using the array.

char[] name = { 'A', 'm', 'a', 'n', 'd', 'a' };
// m
System.out.println(name[1]);

But they do not work to perform operations on directly.

// Will not run
System.out.println({ 'A', 'm', 'a', 'n', 'd', 'a' }[1]);

Challenges

Classes

Primitive Classes

Reference Classes

null

Class Declaration

Naming

Fields

Default Values

Methods

Arguments

Return Values

void

Constructors