Kestrel Exams kestrel logo KESTREL EXAMSPRACTICE TO PASS
Java18 min readCode verified

Identifiers, keywords and literals: taking a Java statement apart

A Java declaration such as int bikesAvailable = 12; is built from five kinds of pieces, and the compiler checks the rules for each one before your program runs. This guide takes one line of a bike rental program apart, then grows the program and shows the real error for every rule you can break. Every listing was compiled and run on OpenJDK 21.

Practice this topic in the free app →All Java guides

One statement, five parts#

Picture the slip on the front desk of a bike rental shop. Each line has a printed label, such as “Bikes available”, and a space for a number. The label stays all season; the number changes every time a bike goes out.

A Java variable is one of those lines: a named place that holds one value. Here is the first line of the shop’s program:

int bikesAvailable = 12;

You know one kind of statement from your first program: System.out.println("Hello"); asks Java to do something. This is the other everyday kind, a declaration, which makes a variable. The new part: every word has a job, and each job has a name. The compiler chops the line into pieces called tokens, five here:

TokenIts nameIts job
intdata typesays what kind of value the variable holds: a whole number
bikesAvailableidentifierthe name the programmer chose
=assignment operatorstores the value on its right into the variable on its left
12literala value written straight into the code
;semicolonends the statement
Try it first

Name the five tokens in this line: double hourlyRate = 8.50;

Show the answer

double is the data type (a number that can have a decimal point), hourlyRate the identifier, = the assignment operator, 8.50 the literal, and ; ends the statement.

This guide grows one program, BikeRental, one idea per section:

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        int bikesAvailable = 12;
        double hourlyRate = 8.50;
        System.out.println(bikesAvailable);
        System.out.println(hourlyRate);
    }
}
12
8.5

The rate prints as 8.5: a double stores a number, not the way you typed it. Printing money with two decimals is in the console output guide, and one-line definitions of every term are in the core vocabulary glossary.

Identifiers: the rules for names#

An identifier is any name the programmer chooses, for a variable, a class or a method. BikeRental and hourlyRate are identifiers. There are four rules:

  1. Use letters, digits, the underscore _ and the dollar sign $. Letters from any alphabet count, so café is legal, but stick to English letters so everyone can type your names.
  2. Do not start with a digit.
  3. No spaces and no other symbols, including the hyphen -.
  4. Do not use a keyword, or one of the reserved literals true, false and null (the next section explains both groups).

Capitals count: bike2 and Bike2 are different names. A lone underscore _ cannot be a name: since Java 9 it is a keyword. (From Java 22 you may write _ for a variable you never use, but you can never read a value through it.)

NameLegal?Why
bike2yesdigits are fine after the first character
_spareyesmay start with an underscore
$depositsyesmay start with a dollar sign (legal, but rarely written by people)
2ndBikenostarts with a digit
bikes-outnothe hyphen is the minus sign
classnoa keyword

The compiler never says “bad name”, so learn to read its messages. Each has the same shape. First come the file and the line number. Then come error: and what the compiler expected. Last comes the line itself, with a caret (the upward arrow ^) under the spot where the compiler gave up.

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        int bikes-out = 2;
    }
}
BikeRental.java:3: error: ';' expected
        int bikes-out = 2;
                 ^
1 error

Java reads bikes-out as bikes minus out. After int bikes the declaration could end, so the compiler wanted a semicolon where the hyphen is. A space gives the identical message.

Trap check: a hyphen in a name

A name with - in it is not one name. Java sees a subtraction. Join words with camelCase (bikesOut) or an underscore (bikes_out).

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        int 2ndBike = 3;
    }
}
BikeRental.java:3: error: not a statement
        int 2ndBike = 3;
        ^
BikeRental.java:3: error: ';' expected
        int 2ndBike = 3;
           ^
2 errors

Two errors for one mistake. A token that starts with a digit is read as a number, and int followed by a number cannot start any statement, so the compiler complains at int itself. When one mistake causes several errors, fix the first and compile again.

Keywords, and the words that only look like keywords#

A keyword, or reserved word, is a word the language keeps for itself, with one fixed meaning. Java has about fifty, all lowercase, such as int, double, boolean, public, class, static, void, new, final, if and for. Even goto and const are reserved, though unused. A keyword cannot be a name:

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        int class = 2;
    }
}
BikeRental.java:3: error: not a statement
        int class = 2;
        ^
BikeRental.java:3: error: ';' expected
        int class = 2;
           ^
BikeRental.java:3: error: <identifier> expected
        int class = 2;
                 ^
3 errors

The third error is the hint: <identifier> expected means the compiler wanted a name.

true, false and null are strictly not keywords but reserved literals, values built into the language. The rule is the same: they cannot be names.

Try it first

String is in almost every program you write. Is it a keyword? Would int String = 2; compile?

Show the answer

It is not a keyword, and yes, it compiles. String is the name of a class in Java’s library, so it is an identifier. No keyword has a capital letter.

That pays off a line you have typed on faith since your first program: public static void main(String[] args). Here public, static and void are keywords, while main, String and args are identifiers. (The anatomy guide explains each word.) Because they are only names, int main = 1; compiles too. Legal, and terrible for the next reader.

Literals: values written straight into the code#

A literal is a value typed directly into the code, like 12. bikesAvailable is not one: it is a name that holds a value.

Kind of valueLiteralHow you write it
whole number (int)12, 125_000digits; underscores may sit between digits
decimal (double)8.50digits with a decimal point
one character (char)'M'one character in single quotes
text (String)"Trail Cruiser"any text in double quotes
yes or no (boolean)true, falseonly these two
no objectnullmeans “points at nothing yet”

Suffixes such as L and f are in the primitive types guide.

The + between a String and another value joins them into one String, which is called concatenation.

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        char frameSize = 'M';
        String model = "Trail Cruiser";
        boolean helmetIncluded = true;
        String reservedBy = null;
        int fleetMiles = 125_000;
        System.out.println(model + ", size " + frameSize + ", helmet " + helmetIncluded);
        System.out.println("Reserved by " + reservedBy + ", miles " + fleetMiles);
        System.out.println("Note: // and /* in quotes are just text");
    }
}
Trail Cruiser, size M, helmet true
Reserved by null, miles 125000
Note: // and /* in quotes are just text

125_000 printed as 125000: underscores are only for human eyes. null prints as the word null. And in the last line, // and /* are ordinary characters, because nothing between a String literal’s quotes can be a comment.

bikesOut is not BikesOut#

Java is case sensitive: capital and small letters are different characters. bikesOut, BikesOut and BIKESOUT are three unrelated names.

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        int bikesOut = 3;
        System.out.println(BikesOut);
    }
}
BikeRental.java:4: error: cannot find symbol
        System.out.println(BikesOut);
                           ^
  symbol:   variable BikesOut
  location: class BikeRental
1 error

Read the last two lines: symbol is the name the compiler could not find, and location is where it looked. The cause is almost always a typo, a wrong capital, or a name used above or outside its declaration.

If you know Python, this is a real difference: Python quietly creates a new variable when you assign to a misspelled name. Java never creates a variable you did not declare, so the typo stops at compile time, where it is cheap to fix.

Trap check: one capital letter

Before you trust “compiles and prints”, check every name against its declaration, capital by capital. One wrong capital means cannot find symbol.

Declare, initialize, assign: three separate jobs#

So far each variable got its name and value in one line. That line does two jobs, and they can be split:

JobExampleWhat it does
Declareint bikesOut;creates the variable: a type and a name, no value yet
InitializebikesOut = 3;gives it its first value
AssignbikesOut = 5;replaces the value. Initializing is just the first assignment.
Both at onceint bikesOut = 3;declares and initializes in one statement

A statement that stores a value with = is an assignment statement. It works right to left: Java works out the right side first, then stores the result in the variable on the left.

Try it first

Three bikes go out, and the program runs bikesAvailable = bikesAvailable - bikesOut; with 12 and 3. As algebra, x = x - 3 is nonsense. What does Java store?

Show the answer

9. It works out 12 - 3 first, then stores 9, replacing the 12. The = means “store”, not “is equal to”.

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        int bikesAvailable = 12;     // declare and initialize
        int bikesOut;                // declare only
        bikesOut = 3;                // first assignment: initializes it
        bikesAvailable = bikesAvailable - bikesOut;
        int helmets = 6, locks = 4, baskets;
        baskets = 2;
        System.out.println(bikesAvailable);
        System.out.println(baskets);
    }
}
9
2

int helmets = 6, locks = 4, baskets; declares three variables of one type, separated by commas. baskets gets its value on the next line, before anything reads it, so printing it is fine.

An if statement runs its block (the statements inside its curly braces) only when the condition in its parentheses is true.

Trap check: = is not ==

= stores a value. == compares two values and gives true or false. With an int, mixing them up in a condition is a compile error, as below. With a boolean, if (done = true) compiles, stores true and always runs the block, so the bug hides.

Here is the int version of that mistake:

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        int bikesOut = 3;
        if (bikesOut = 0) {
            System.out.println("All bikes are in");
        }
    }
}
BikeRental.java:4: error: incompatible types: int cannot be converted to boolean
        if (bikesOut = 0) {
                     ^
1 error

bikesOut = 0 produces the value it stored, the int 0, but a condition must be a boolean. bikesOut == 0 compiles.

Reading a variable before it has a value#

Every variable so far is a local variable, declared inside a method. Local variables get no automatic starting value. Before Java lets you read one, it checks that a value was stored on every path the program could take: the definite assignment rule. (Fields, variables declared in a class outside any method, and array elements do start at defaults such as 0; see the arrays guide.)

Try it first

Below, weekend is true, so the if block always runs and hours always gets 4. Does it compile?

Show the answer

No. The compiler does not run your program, and it does not track what an ordinary variable such as weekend holds. It sees a path that skips the if block, where hours never gets a value.

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        boolean weekend = true;
        int hours;
        if (weekend) {
            hours = 4;
        }
        System.out.println(hours);
    }
}
BikeRental.java:8: error: variable hours might not have been initialized
        System.out.println(hours);
                           ^
1 error

Notice might: the compiler cannot prove hours has a value. The caret points at line 8, which reads it. Two fixes: initialize it on declaration (int hours = 0;), or assign it on every path, for example with else { hours = 2; }.

final: the deposit that never changes#

Every rental takes a 25.00 deposit. The hourly rate may change for the weekend; the deposit never does. Put the keyword final in front of a declaration and the variable can be assigned only once. A final variable holding a fixed value is a constant, such as final double DEPOSIT = 25.00; at the shop.

Try it first

What if a later line says DEPOSIT = 30.00; as well? Does the program print 30.0, print 25.0, or refuse to compile?

Show the answer

It refuses to compile. The compiler enforces final.

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        final double DEPOSIT = 25.00;
        DEPOSIT = 30.00;
        System.out.println(DEPOSIT);
    }
}
BikeRental.java:4: error: cannot assign a value to final variable DEPOSIT
        DEPOSIT = 30.00;
        ^
1 error

final means “assigned once”, not “assigned on the declaration line”: final int LATE_FEE; followed later by LATE_FEE = 5; compiles. A second assignment would not.

DEPOSIT is in capitals on purpose. Java programmers follow three naming conventions:

Kind of nameConventionExamples
variables, methodscamelCase: first word lowercase, later words capitalizedbikesAvailable
classesUpperCamelCase: every word capitalizedBikeRental
constants (static final; often local finals too)UPPER_SNAKE_CASE: all capitals, words joined by underscoresDEPOSIT, FLEET_SIZE

Strictly, UPPER_SNAKE_CASE is for constants declared static final in a class (see the naming conventions guide). Many programmers also write a local final such as DEPOSIT this way, as this guide does.

These are conventions, not rules: the compiler accepts final double deposit = 25.00;. Follow them anyway: a reader who sees DEPOSIT knows at a glance it never changes, and exams ask. The naming conventions and Javadoc guide goes further.

Counting operators and operands#

An operator is a symbol that does work on values: + adds, * multiplies, = stores, > compares. The values it works on are its operands. In hourlyRate * hours, the operator is * and the operands are hourlyRate and hours. Here is the line that prices a rental:

double total = hourlyRate * hours + DEPOSIT;
Try it first

How many operators are in that line? Count before you look.

Show the answer

Three: =, * and +. double is a keyword; the four names are identifiers, and all four are operands (total is the left operand of =); the semicolon is a separator, not an operator.

Java’s grammar calls ; , . and parentheses, square brackets and curly braces separators, so in counting questions they do not count as operators. (One exception comes later: a cast such as (int) is called the cast operator.) Variables and literals are operands.

Predict before you run: three hours at 8.50 is 25.50, plus the 25.00 deposit makes 50.50. It must land above the deposit and below deposit plus four hours (59.00). The program also tries parentheses in the wrong place:

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        final double DEPOSIT = 25.00;
        double hourlyRate = 8.50;
        int hours = 3;
        double total = hourlyRate * hours + DEPOSIT;
        double wrong = (DEPOSIT + hourlyRate) * hours;
        boolean longRide = hours >= 3 && total <= 60.0;
        System.out.println(total);
        System.out.println(wrong);
        System.out.println(longRide);
    }
}
50.5
100.5
true

The first line matches. The second added the deposit before multiplying, charging it three times, and 100.5 fails the sanity check at once. Predict first, even when a tool or an AI wrote the code: a wrong number only looks wrong if you had a number in mind.

Trap check: which operator goes first?

*, / and % (remainder) go before + and -, as in math, and parentheses go first of all. So 10 + 2 * 5 is 20, not 60. When in doubt, add parentheses.

The last line of output comes from comparisons. >= (greater than or equal to) and <= (less than or equal to) each give true or false, and && (“and”) is true only when both sides are. A 3-hour ride at 50.5 passes both tests. That longRide line holds four operators: =, >=, &&, <=. Shorthands count as one operator each. total += 5 adds 5 to total and stores the result. -=, *=, /= and %= work the same way. x++ gives the old value, then adds one. ++x adds one first, then gives the new value. Their own guide has more.

What the semicolon ends, and what it does not#

A semicolon ends a statement, one complete instruction. It does not end a line: Java treats a line break like a space. It never ends a block, the statements inside curly braces; the closing curly brace does that, and class and method headers take no semicolon.

Try it first

Below, hours is 2, so hours > 5 is false. Will “Long-ride discount applied” print?

Show the answer

Yes. The semicolon after if (hours > 5) ends the if with an empty statement. The block below is then an ordinary block that always runs.

BikeRental.java
public class BikeRental {
    public static void main(String[] args) {
        int hours = 2; int bikesOut = 1;          // two statements, one line
        double total = 8.50 * hours
                       + 25.00;                    // one statement, two lines
        System.out.println(total);
        if (hours > 5); {
            System.out.println("Long-ride discount applied");
        }
    }
}
42.0
Long-ride discount applied

The total is one statement on two lines. The discount line is the strange output, shown so you meet it here first.

Trap check: a semicolon after if (...)

Check the end of every if, while and for header. By default, javac compiles a semicolon there without a word of warning.

Comments, and the finished program#

A comment is a note for people. The compiler discards it, so it never changes what a program does. // runs to the end of the line; /* runs to the next */, across any number of lines. /** ... */ is a Javadoc comment, which tools turn into documentation (see naming conventions and Javadoc). Commenting out a line switches it off. Here is everything together:

BikeRental.java
/* BikeRental: prices one rental.
   The deposit is refunded on return. */
public class BikeRental {
    public static void main(String[] args) {
        final double DEPOSIT = 25.00;
        final int FLEET_SIZE = 12;
        double hourlyRate = 8.50;
        int bikesOut = 3;
        int hours = 4;

        int bikesAvailable = FLEET_SIZE - bikesOut;
        double total = hourlyRate * hours + DEPOSIT;
        boolean longRide = hours > 3;
        // bikesOut = bikesOut + 1;

        System.out.println("Bikes available: " + bikesAvailable);
        System.out.println("Total due: " + total);
        System.out.println("Long ride: " + longRide);
    }
}
Bikes available: 9
Total due: 59.0
Long ride: true

As predicted: 12 minus 3 is 9 bikes, and 4 hours at 8.50 plus 25.00 is 59.00.

Type this one yourself

Type it, do not paste it. Then break it three ways, one at a time, and predict each message before you compile. (1) Rename hourlyRate to hourly-rate in its declaration. (2) Add DEPOSIT = 0; as the last line of main. (3) Move the total line below the println that prints it.

Show the answer

(1) ';' expected at the hyphen. (2) cannot assign a value to final variable DEPOSIT. (3) cannot find symbol: a variable does not exist above its declaration.

What was new in this guide#

  1. The five tokens of int bikesAvailable = 12;: data type, identifier, assignment operator, literal, semicolon.
  2. The identifier rules, and reading a compiler error by its line number and caret.
  3. Keywords and reserved literals; String and main are identifiers.
  4. Literals of each type, and joining Strings with + (concatenation).
  5. Case sensitivity and cannot find symbol.
  6. Declare, initialize, assign; = stores, == compares.
  7. Definite assignment and might not have been initialized.
  8. final constants and the three naming conventions.
  9. Counting operators and operands, and operator precedence: *, / and % before + and -.
  10. What the semicolon ends, and the empty statement in if (...);.
  11. The three kinds of comments.
One sentence to carry into the exam

A declaration names a data type and an identifier; adding = and a value initializes it, and a semicolon ends it. The compiler checks the rules for every piece before your program runs.

Where these go wrong#

  • A hyphen, a space or a leading digit in a name. bikes-out is a subtraction and 2ndBike starts as a number. Write bikesOut, bike2.
  • Thinking String or main is a keyword. Both are identifiers. Keywords are lowercase; true, false and null are reserved literals.
  • One wrong capital. BikesOut is not bikesOut: cannot find symbol.
  • Reading a local variable that only some paths assign. Initialize it when you declare it, or assign it in every branch, including an else.
  • Assigning a final variable twice. A compile error. If the value must change, it should not be final.
  • Writing = where you meant ==. = stores; == compares.

On the exam: For “what happens?” questions, first decide whether the code compiles: names, capitals, definite assignment, final. Only then trace the output. Read the question twice, answer, then check you answered every part.

Practice#

Answer each one on paper before you look at the solutions. Every answer that involves running code was checked by compiling and running it.

  1. Which of these compile as variable names? For each one that does not, name the rule it breaks. rate2Hour, 2hourRate, hour_rate, hour-rate, $rate, final, Final.
  2. What does this print?
    int locks = 5;
    int Locks = 2;            // a second, separate variable
    /* locks = 0; */
    locks = Locks + locks * 2;
    System.out.println("locks // " + locks);
    System.out.println(1_500 + locks);
  3. Here is a line: boolean canRent = bikesOut < bikesAvailable && age >= 16; How many operators does it hold? Name each one, and name the literal.
  4. These two conditions cover every possible value of hours, yet the code does not compile. What does the compiler report, and what is the smallest fix?
    int hours = 5;
    double rate;
    if (hours < 3) {
        rate = 9.00;
    } else if (hours >= 3) {
        rate = 7.50;
    }
    System.out.println(rate);
  5. Write a short program for lock sales. Store the price of one lock, 12.00, as a constant named by convention, and the number sold today, 7, in a variable. Compute the revenue and print it with a label.
  6. In one sentence each: what is the difference between int count = 0; and count = 0;, and between count = 0 and count == 0?

Solutions#

  1. rate2Hour, hour_rate, $rate and Final compile. 2hourRate starts with a digit, hour-rate contains a hyphen (minus), and final is a keyword. Final is legal because Java is case sensitive, though it is a poor name.
  2. The block comment switches off locks = 0;. Multiplication goes first, so 2 + 5 * 2 is 12. The // is text inside quotes, and 1_500 is 1500:LockShelf.java
    public class LockShelf {
        public static void main(String[] args) {
            int locks = 5;
            int Locks = 2;            // a second, separate variable
            /* locks = 0; */
            locks = Locks + locks * 2;
            System.out.println("locks // " + locks);
            System.out.println(1_500 + locks);
        }
    }
    locks // 12
    1512
  3. Four operators: =, <, && and >=. The only literal is 16. boolean is a keyword, the four names are identifiers, and the semicolon is a separator.
  4. The compiler does not work out that the conditions cover every number. It sees two tests that could both be false, so rate might never be assigned:Shop.java
    public class Shop {
        public static void main(String[] args) {
            int hours = 5;
            double rate;
            if (hours < 3) {
                rate = 9.00;
            } else if (hours >= 3) {
                rate = 7.50;
            }
            System.out.println(rate);
        }
    }
    Shop.java:10: error: variable rate might not have been initialized
            System.out.println(rate);
                               ^
    1 error
    Fix: change else if (hours >= 3) to a plain else. Every path then assigns rate, and it prints 7.5.
  5. The price never changes, so it is final and in UPPER_SNAKE_CASE. The count is an ordinary camelCase variable:LockSales.java
    public class LockSales {
        public static void main(String[] args) {
            final double LOCK_PRICE = 12.00;
            int locksSold = 7;
            double revenue = LOCK_PRICE * locksSold;
            System.out.println("Lock revenue: " + revenue);
        }
    }
    Lock revenue: 84.0
  6. int count = 0; declares a new variable and initializes it, while count = 0; assigns to a variable that must already be declared. count = 0 stores 0, while count == 0 compares count with 0 and gives true or false.

Test-readiness checklist#

These are the items from the course’s Exam 1 topic list that this guide covers. Tick each one only when you can do it without looking.

  • ☐  I can name the data type, identifier, assignment operator, literal and semicolon in a declaration such as int bikesAvailable = 12;.
  • ☐  I can tell a legal identifier from an illegal one and say which rule it breaks.
  • ☐  I can tell keywords, identifiers and literals apart.
  • ☐  I can explain declaration, initialization and assignment, and fix variable might not have been initialized.
  • ☐  I can declare a final constant and follow the naming conventions.
  • ☐  I can count the operators and operands in a statement.

Test yourself in the free Kestrel Exams app

39 practice questions on identifiers, keywords and literals, with every code answer checked by compiling and running it. Free, offline, no account.

Practice language elements →

Frequently asked questions#

What are the rules for naming a variable in Java?

An identifier may contain letters, digits, the underscore and the dollar sign. It cannot start with a digit, contain a space or a hyphen, or be a keyword or one of true, false and null. Names are case sensitive.

What is the difference between a keyword and an identifier in Java?

A keyword is reserved by the language with a fixed meaning, such as int, class or final. An identifier is a name the programmer chooses, such as bikesAvailable, and may not be a keyword.

Is String a keyword in Java?

No. String is the name of a class in the Java library, so it is an identifier. Java keywords are all lowercase. System and main are identifiers too.

What does "variable might not have been initialized" mean?

A local variable is read where the compiler cannot prove it got a value on every path. Local variables have no default. Initialize it when you declare it, or assign it in every branch, including an else.

What does "cannot assign a value to final variable" mean?

The code assigns a second value to a variable declared final. A final variable can be assigned only once. Remove the second assignment, or drop final if the value really must change.

Suggest a change

Something here not clear? A topic you wish we covered? Tell us. We read every message, and a request is the fastest way to get a guide written: several of these exist because somebody asked.