How code reads
Statements, blocks, names and the compile-then-run cycle, explained from zero.
Before you can write plugins, you need to read code the way Java reads it. On this page you will run your first Java program, learn what every symbol on a line means, read and fix real error messages, and see how the same ideas show up inside a Paper plugin.
What a program is
A program is a list of instructions for the computer. The computer does exactly what the instructions say, one after another, from the top of the list to the bottom. It never guesses what you meant. If an instruction is missing, it does not happen. If two instructions are in the wrong order, they run in the wrong order.
You write those instructions as text in files that end with .java. That text is called source code. People can read source code, but the computer cannot run it directly. Two steps turn your text into something that runs:
- Compile. A tool called the compiler (its name is
javac) reads your.javafiles, checks that they follow Java's grammar rules, and translates them into bytecode: compact instructions stored in.classfiles. If something is wrong, the compiler stops and tells you where. - Run. The Java Virtual Machine (the JVM, started with the
javacommand) reads the bytecode and carries out the instructions.
Why two steps? Because compiling catches many mistakes before anything runs. A typo in a plugin is much better found on your PC than on a live server with 50 players. It also means the same compiled plugin jar runs on Windows, Linux and macOS servers, because each of them has a JVM that understands bytecode.
For plugins, you will rarely type javac yourself. Gradle (see Your toolbox) runs the compiler for you, packs the .class files into a jar, and the Paper server, which is itself a Java program running on a JVM, loads that jar. Same two steps, just automated.
Your first program
Here is a complete Java program. Press Run (or the green arrow next to void main) and look at the output below the code.
1void main() {2 IO.println("Hello, Minecraft!");3 IO.println("This is my first Java program.");4}- The starting point. When you run the program, Java looks for
mainand runs the lines inside its braces.voidmeans "this gives nothing back when it finishes"; you will meet it again in every plugin. - One instruction: print a line of text.
IOis a helper built into Java 25 for input and output, andprintlnmeans "print line": show the text, then move to a new line. - A second instruction. It runs after the first one finishes, so its text appears underneath.
- The closing brace ends
main. When Java reaches it, the program is done.
The output is exactly the two pieces of text inside the quotes, in the same order as the lines. The quotes themselves are not printed: they only mark where the text starts and stops.
Running it on your own PC
You can run the same file outside this guide in two ways:
- In IntelliJ: create a plain Java project (, choose Java and JDK 25), add a file called
Hello.java, paste the code, and click the green arrow that appears next tovoid main. The output shows in the Run window at the bottom. - In a terminal: go to the folder with the file and run
java Hello.java. For a single file, thejavacommand compiles it in memory and runs it right away.
java Hello.javaHello, Minecraft!This is my first Java program.Reading a line of code
Look at the line IO.println("Hello, Minecraft!"); again. It has five parts, and almost every line you will write in a plugin has the same parts:
| Part | In the example | What it means |
|---|---|---|
| The thing | IO | Who should do the work. In plugins this is often a player, the event or the server. |
| The dot | . | "Use something that belongs to this thing." Read it as "'s": player.getName() is "the player's name". |
| The action | println | A method: a named action the thing knows how to do. |
| The input | ("Hello, Minecraft!") | The arguments the action needs, inside parentheses. Text inside double quotes is a String. |
| The end | ; | The semicolon ends the instruction, like a period ends a sentence. |
Now read this line from a real plugin. You already know how to read it, even though you have never seen it before:
1player.sendRichMessage("<green>Welcome!");- The thing is
player, the action issendRichMessage, and the input is the text"<green>Welcome!". Result: that player sees a green "Welcome!" in chat.
Some actions need no input, but the parentheses are still there: player.getName() asks the player for their name and needs nothing extra. Some actions need several inputs, separated by commas. You will see both all the time.
The classic way to write main
Java 25 lets you start a program with a short void main(). Older Java needed more ceremony, and you will see this longer form in almost every tutorial and Stack Overflow answer online. It does exactly the same thing:
1public class ClassicHello {2 public static void main(String[] args) {3 System.out.println("Hello, Minecraft!");4 System.out.println("This is my first Java program.");5 }6}- A
class is a named container for code. In Java, all code lives inside a class. The shortvoid main()form simply hides this line from you. A file's public class must have the same name as the file:ClassicHellolives inClassicHello.java. - The classic starting point.
publicmeans anyone may call it,staticmeans it can run without creating anything first, andString[] argsreceives extra words typed after the program name. You will learn each word on later pages. - The classic way to print a line.
System.outis the terminal's output, andprintlnprints a line on it. - Closes
main.
| Short form (Java 25) | Classic form (all Java versions) |
|---|---|
void main() { ... } | public class Name { public static void main(String[] args) { ... } } |
IO.println("text"); | System.out.println("text"); |
IO.print("text"); (no new line) | System.out.print("text"); |
The Java pages in this guide use the short form, because it lets you focus on the idea being taught. Plugins always use full classes, and you will read plenty of them below.
Statements, semicolons and blocks
Statements run from top to bottom
Each complete instruction is called a statement. Statements run in order, one at a time. This little program pretends to start a server:
1void main() {2 IO.println("Loading world...");3 IO.println("Spawning villagers...");4 IO.println("Opening the doors...");5 IO.println("Server is ready!");6}- Runs first.
- Runs second, only after the first line is completely finished.
- Runs last. If you moved this line to the top, "Server is ready!" would print before the world loaded, which would be a lie.
Order matters in plugins too. If your plugin sends a player a message and then teleports them, they read the message at the old spot. Swap the two lines and they read it after arriving. Same instructions, different result.
Semicolons end statements; indentation is for humans
Java does not care about line breaks or spaces between statements. It looks for the semicolon to know where one statement ends. This program is badly laid out, but it runs perfectly:
1void main() {2IO.println("Line one");3 IO.println("Line two"); IO.println("Line three");4 IO.println(5 "Line four"6 );7}- No indentation at all. Java does not mind.
- Two statements on one line. The semicolon after the first one tells Java where it ends.
- One statement spread over three lines. Java keeps reading until it finds the semicolon.
So why do the other examples look so tidy? Because people read code far more often than they write it. Consistent indentation (four spaces per level) shows at a glance which lines belong together. In IntelliJ, press Ctrl+Alt+L to reformat a file neatly. Do it often.
Braces make blocks
A pair of curly braces { } groups statements into a block. Blocks can sit inside other blocks, like boxes inside boxes. A plugin's main class is a big block, and each method inside it is a smaller block with its own statements:
Every { needs a matching }. When you forget one, the compiler gets confused and often reports the problem far below where it really is, with a message such as "reached end of file while parsing". IntelliJ highlights the matching brace when you click next to one, which makes it easy to check.
Text and numbers
The quotes matter a lot. Text inside double quotes is printed exactly as written. Without quotes, Java treats what you wrote as code and works it out first. Run this and compare each line of code with its output:
1void main() {2 IO.println("2 + 3");3 IO.println(2 + 3);4 IO.println(64 * 3);5 IO.println("One stack holds " + 64 + " items.");6 IO.println("Three stacks hold " + (64 * 3) + " items.");7}- Inside quotes,
2 + 3is just five characters of text, so it prints as-is. - No quotes: Java calculates
2 + 3and prints the answer, 5. - The
*symbol means multiply. 64 is a full stack of most items. - A
+between text and a number glues them together into one piece of text. - The parentheses make Java calculate
64 * 3first, then glue the answer into the sentence.
You will use this all the time in plugins, for example "You have " + coins + " coins". The next pages explain numbers and text properly: Variables and types, Operators and math and Working with text.
Names and capital letters
Java is case sensitive: capital and small letters are different letters. IO, Io and io are three different names, and only IO exists. This is the single most common reason a beginner's code does not compile.
The names you choose yourself, for classes, methods and stored values, are called identifiers. They follow a few rules:
- Use letters, digits,
_and$only. No spaces, no dashes, no dots. - Do not start with a digit:
player2is fine,2playeris not. - Do not use a Java keyword such as
classorvoidas a name.
On top of the rules, every Java developer follows the same naming habits, called naming conventions. Java does not force them, but every Paper class follows them, so following them too makes your code look like everyone else's and helps you guess names:
| Style | Used for | Examples you will meet in plugins |
|---|---|---|
| camelCase (starts small, each new word capitalized) | Methods and variables | onEnable, getPlayer, sendRichMessage, coins, maxHomes |
| PascalCase (starts capital) | Classes and other types | JavaPlugin, PlayerJoinEvent, ItemStack, MyPlugin |
| UPPER_SNAKE_CASE (capitals with underscores) | Constants and fixed lists of values | Material.DIAMOND_SWORD, Attribute.MAX_HEALTH, MAX_HOMES |
| all lowercase with dots | Packages (folders of classes) | com.example.myplugin, org.bukkit.entity |
The conventions are a superpower when reading code. In Material.DIAMOND_SWORD you can tell from the capitals alone that Material is a type and DIAMOND_SWORD is a fixed value. In player.getName(), the small letters and parentheses tell you player is a stored value and getName is an action.
Keywords
Keywords are words that Java reserves for its own grammar. IntelliJ shows them in a different color. There are about 50 of them, and you do not need to learn them now: each one gets explained on the page where you first need it. These are the ones you will see in almost every plugin:
| Keywords | What they are for | Learn them in |
|---|---|---|
int, double, boolean, var, final | Storing values | Variables and types |
if, else, switch, return | Making decisions | Making decisions |
for, while, break, continue | Repeating things | Loops |
void, static | Defining methods | Methods |
class, new, this, public, private | Classes and objects | Classes and objects |
extends, implements | Building on other classes, like JavaPlugin and Listener | Inheritance and interfaces |
package, import | Organizing classes into folders | Packages and imports |
true, false, null | Special values: yes, no, and "nothing here" | Variables and types |
One more thing you will meet in code online: notes for humans called comments. A line starting with //, or text between /* and */, is ignored by the compiler. This guide keeps its code free of comments and explains everything in the numbered notes instead, so the code you copy stays clean.
When code goes wrong
Mistakes are normal, even for experts. What matters is reading the error message, because it nearly always tells you exactly where to look. There are two kinds of errors, and they happen at different times.
Compile errors: Java cannot understand you
A compile error means the code breaks Java's grammar rules, so the compiler refuses to translate it. Nothing runs at all. This program forgot one semicolon:
1void main() {2 IO.println("Welcome to the server!")3 IO.println("Have fun!");4}- The semicolon at the end of this line is missing.
Read the error from left to right:
MissingSemicolon.java: the file with the problem.:2:the line number. Go to line 2.error: ';' expected: what Java wanted but did not find.- The line underneath shows your code, and the
^points at the exact spot.
Here is the case-sensitivity mistake from earlier, written io instead of IO:
1void main() {2 io.println("Welcome to the server!");3}- Small
iodoes not exist. OnlyIOdoes.
"cannot find symbol" means "you used a name I do not know". The symbol: variable io line tells you which name. When you see this, check the spelling and the capital letters first, and then check whether you forgot an import (see Packages and imports).
In IntelliJ you rarely need to compile to see these errors: the editor underlines the problem in red as you type, and hovering the red line shows the same message.
Runtime errors: Java understood, but something failed
A runtime error happens while the program runs. The grammar was fine, so it compiled, but one instruction asked for something impossible. Java stops and throws an exception: an error report with a name. This program tries to share 12 diamonds among 0 players:
1void main() {2 int diamonds = 12;3 int players = 0;4 IO.println("Splitting " + diamonds + " diamonds...");5 IO.println("Each player gets " + diamonds / players);6 IO.println("Done!");7}- Stores the number 12 under the name
diamonds. You will learn about stored values on the next page. - Stores 0 under the name
players. - This line runs fine, so its text appears in the output.
- Dividing by zero is impossible in whole-number math. Java throws an exception here and stops.
- Never runs, because the program crashed on the line above.
The first line of output proves that line 4 ran. Then comes the error report, called a stack trace:
java.lang.ArithmeticException: the name of the problem (a math problem)./ by zero: the details.at SplitDiamonds.main(SplitDiamonds.java:5): where it happened: inmain, in the fileSplitDiamonds.java, on line 5.
Plugins crash the same way, and the stack trace appears in the server console. If a join listener divided by zero, a player joining would print something like this. Notice that the "at" line names your class, your method and the exact line:
[14:06:03 INFO]: Steve joined the game[14:06:03 ERROR]: Could not pass event PlayerJoinEvent to HowCodeReads v1.0.0java.lang.ArithmeticException: / by zero at com.example.javahowcodereadsplugin.GreetingListener.onJoin(GreetingListener.java:14) ~[HowCodeReads-1.0.0.jar:?]The good news: one crashing event handler does not crash the server. Paper catches the exception, prints it, and carries on. The bad news: your feature silently stops working for that event, so always keep an eye on the console while testing. Null, exceptions and stack traces teaches stack traces in depth, and the Error Doctor explains any error you paste into it.
How plugin code is different
Everything so far started at main and ran to the end. A plugin has no main at all. Instead, the Paper server is the program that is running, and it calls your code at the right moments:
- When the server starts, Paper calls your plugin's
onEnablemethod. - When something happens in the game, such as a player joining, Paper calls the matching event handler in your plugin.
- When the server stops, Paper calls your
onDisablemethod.
Inside each of those methods, your statements still run top to bottom, exactly like in the programs above. You just do not decide when the method starts. That is the server's job.
This small plugin makes the order visible. Read it with what you now know: things, dots, actions, inputs, semicolons and blocks.
Where this file livesjava-how-code-reads-pluginsrcmainjavacomexamplejavahowcodereadspluginHowCodeReadsPlugin.java
The package com.example.javahowcodereadsplugin is the folder path com/example/javahowcodereadsplugin inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.
- java-how-code-reads-plugin/
- src/main/
- java/com/example/javahowcodereadsplugin/Package com.example.javahowcodereadsplugin
- GreetingListener.javaListener: reacts to events
- HowCodeReadsPlugin.javayou are hereMain class: Paper starts here (named as main in plugin.yml)
- resources/Files copied into the jar as they are
- plugin.ymlTells Paper the plugin's name, version and main class
- java/com/example/javahowcodereadsplugin/Package com.example.javahowcodereadsplugin
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1package com.example.javahowcodereadsplugin;2 3import org.bukkit.plugin.java.JavaPlugin;4 5public final class HowCodeReadsPlugin extends JavaPlugin {6 7 @Override8 public void onEnable() {9 getLogger().info("Step 1: the server called onEnable.");10 getLogger().info("Step 2: registering the join listener.");11 getServer().getPluginManager().registerEvents(new GreetingListener(), this);12 getLogger().info("Step 3: setup is done. Waiting for players...");13 }14 15 @Override16 public void onDisable() {17 getLogger().info("The server is stopping. Goodbye!");18 }19}- The
package : which folder this file lives in. Every plugin file starts with this line. - Says which
JavaPluginwe mean: the one in Paper'sorg.bukkit.plugin.javapackage. IntelliJ writes import lines for you. - The class block for the whole plugin.
extends JavaPluginmakes it a Paper plugin, which is how the server knows it may callonEnableandonDisable. - A label that says "this method is one that
JavaPluginexpects". If you misspell the method name, this label makes the compiler stop with an error instead of silently ignoring your method. - There is no
main. This method is your starting point, and the server calls it once when your plugin starts. - Thing:
getLogger(), the plugin's logger. Action:info, which writes a line to the server console. Input: the text. - Tells the server about the listener class below, so the server knows to call it when players join. This runs second, after Step 1's log line.
- Runs last. After this line,
onEnableis finished and the server carries on starting. - Called once when the server stops. A good place to save data.
Where this file livesjava-how-code-reads-pluginsrcmainjavacomexamplejavahowcodereadspluginGreetingListener.java
The package com.example.javahowcodereadsplugin is the folder path com/example/javahowcodereadsplugin inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.
- java-how-code-reads-plugin/
- src/main/
- java/com/example/javahowcodereadsplugin/Package com.example.javahowcodereadsplugin
- GreetingListener.javayou are hereListener: reacts to events
- HowCodeReadsPlugin.javaMain class: Paper starts here (named as main in plugin.yml)
- resources/Files copied into the jar as they are
- plugin.ymlTells Paper the plugin's name, version and main class
- java/com/example/javahowcodereadsplugin/Package com.example.javahowcodereadsplugin
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1package com.example.javahowcodereadsplugin;2 3import org.bukkit.entity.Player;4import org.bukkit.event.EventHandler;5import org.bukkit.event.Listener;6import org.bukkit.event.player.PlayerJoinEvent;7 8public final class GreetingListener implements Listener {9 10 @EventHandler11 public void onJoin(PlayerJoinEvent event) {12 Player player = event.getPlayer();13 player.sendRichMessage("<gold>Hello, " + player.getName() + "!");14 player.sendRichMessage("<gray>This message came from your plugin.");15 player.sendRichMessage("<gray>Your plugin ran these lines in order, top to bottom.");16 }17}- Marks this class as a listener: a class whose methods react to things that happen in the game.
- Tells Paper "call the next method when its event happens".
- The server calls this method every time a player joins. You never call it yourself.
- Asks the event which player joined and stores the answer under the name
player, so the next lines can use it. - Thing:
player. Action:sendRichMessage. Input: text glued together with the player's name using+, just likeTextAndNumbersdid. - The second chat line. It always arrives after the first.
- The third line, last of all.
And plugin.yml tells the server which class is the main class:
Where this file livesjava-how-code-reads-pluginsrcmainresourcesplugin.yml
Files in src/main/resources are copied into the jar exactly as they are. Paper looks for plugin.yml at the top of the jar.
- java-how-code-reads-plugin/
- src/main/
- java/com/example/javahowcodereadsplugin/Package com.example.javahowcodereadsplugin
- GreetingListener.javaListener: reacts to events
- HowCodeReadsPlugin.javaMain class: Paper starts here (named as main in plugin.yml)
- resources/Files copied into the jar as they are
- plugin.ymlyou are hereTells Paper the plugin's name, version and main class
- java/com/example/javahowcodereadsplugin/Package com.example.javahowcodereadsplugin
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1name: HowCodeReads2version: '1.0.0'3main: com.example.javahowcodereadsplugin.HowCodeReadsPlugin4api-version: '26.3'5description: Logs its startup steps and greets players, to show the order code runs in.- The full name of the class the server creates and calls
onEnableon: package plus class name. - The Paper version this plugin was written for.
When you start the server, join, and stop the server again, the console shows each step in order:
[14:05:10 INFO]: [HowCodeReads] Enabling HowCodeReads v1.0.0[14:05:10 INFO]: [HowCodeReads] Step 1: the server called onEnable.[14:05:10 INFO]: [HowCodeReads] Step 2: registering the join listener.[14:05:10 INFO]: [HowCodeReads] Step 3: setup is done. Waiting for players...[14:05:42 INFO]: Steve joined the game[14:09:00 INFO]: [HowCodeReads] Disabling HowCodeReads v1.0.0[14:09:00 INFO]: [HowCodeReads] The server is stopping. Goodbye!And Steve sees this in chat when he joins:
Hello, Steve!
This message came from your plugin.
Your plugin ran these lines in order, top to bottom.
| Plain Java program | Paper plugin | |
|---|---|---|
| Where it starts | main | onEnable, called by the server |
| Who starts it | You, with Run or java | The Paper server, when it starts |
| When it ends | At the end of main | When the server stops (onDisable) |
| Printing text | IO.println to the terminal | getLogger().info to the console, sendRichMessage to players |
| How it is built | java Hello.java | Gradle compiles it into a jar for the plugins folder |
You can download this plugin as a Gradle project, open it in IntelliJ and run it with Run Paper Server, as shown in Your first plugin.
Practice
Your server's welcome board
Start from this program and make it print a welcome board for a server: a title line, two rules, and a line about the starter kit. The number of ender pearls in the kit must be calculated by Java as 5 stacks of 16, not typed in as 80.
1void main() {2 IO.println("Welcome to my server!");3}Your output should look like this:
=== Welcome to Skyblock Island ===Rule 1: Be kind in chat.Rule 2: No griefing.Starter kit: 80 ender pearlsHint 1
Each line of output needs its own IO.println(...); statement.
Hint 2
To put a calculated number in the middle of text, glue three pieces together: "Starter kit: " + (5 * 16) + " ender pearls".
Show the solution
Four statements, run top to bottom. The parentheses around 5 * 16 make Java calculate before gluing.
1void main() {2 IO.println("=== Welcome to Skyblock Island ===");3 IO.println("Rule 1: Be kind in chat.");4 IO.println("Rule 2: No griefing.");5 IO.println("Starter kit: " + (5 * 16) + " ender pearls");6}Fix the shop program
This program has two mistakes. Find and fix both, using the error messages to guide you.
1void main() {2 IO.println("The shop is open!")3 Io.println("Diamonds cost 5 coins.");4 IO.println("Have fun shopping!");5}Hint 1
The compiler only reports one error. Fix line 2 first, then run again.
Hint 2
After the first fix, the compiler finds the second mistake:
1void main() {2 IO.println("The shop is open!");3 Io.println("Diamonds cost 5 coins.");4 IO.println("Have fun shopping!");5}Show the solution
Line 2 was missing its semicolon, and line 3 said Io instead of IO. The compiler only showed the second mistake after the first was fixed, which is why you always fix the top error and try again.
1void main() {2 IO.println("The shop is open!");3 IO.println("Diamonds cost 5 coins.");4 IO.println("Have fun shopping!");5}Add a line to the plugin
In HowCodeReadsPlugin, add a fourth log line at the end of onEnable that prints how many items a double chest holds. A double chest has 54 slots, and each slot holds 64 items. Let Java do the multiplication.
Hint
Copy one of the existing getLogger().info(...) lines and change the text. Glue the number in with +, just like the welcome board.
Show the solution
Add this as the last statement inside onEnable, after the "Step 3" line:
1getLogger().info("A double chest holds " + (54 * 64) + " items.");Restart the server and the console shows [HowCodeReads] A double chest holds 3456 items. right after Step 3, because it is the last statement in the block.
Want more? The Practice Arena has short challenges for this chapter that check your answer with real tests.
Recap
- A program is a list of instructions that run from top to bottom, in order.
- Java is compiled first (
javacturns.javainto.classbytecode) and then run by the JVM. Gradle does both steps for plugins. - Most lines read as "thing, dot, action, input in parentheses, semicolon":
player.sendRichMessage("Hi");. - Statements end with
;. Braces{ }group statements into blocks. Indentation is only for humans. - Java is case sensitive. Classes use PascalCase, methods and variables use camelCase, constants use UPPER_SNAKE_CASE.
- Compile errors stop the code from building; runtime errors (exceptions) stop it while it runs. Both tell you the file and line.
- Plugins have no
main. The server callsonEnable, your event handlers andonDisable, and each of them runs top to bottom.
Quick quiz
What does the compiler (
javac) do?The compiler only checks and translates. Running the bytecode is the JVM's job, started with thejavacommand or, for plugins, by the Paper server itself.In
player.sendRichMessage("<green>Hi");, which part is the action (the method)?playeris the thing that does the work,sendRichMessageis the action, and the text in parentheses is the input for that action.Your code says
Player player = event.getplayer();and IntelliJ shows "cannot find symbol". What is wrong?"cannot find symbol" means Java does not know a name.getplayerandgetPlayerare different names to Java, and onlygetPlayerexists. The semicolon is there, so that is not the problem.A program prints "Loading...", then crashes with
ArithmeticException: / by zero. What kind of error is this?The first line printed, so the program compiled and started running. A compile error would have stopped it before anything printed at all.A plugin has no
mainmethod. How does its code ever start running?The server is the running program, and your plugin is code the server calls at the right moments.plugin.ymltells the server which class to create, and the server callsonEnableon it.
Next steps
- Variables and types: store numbers, text and true/false values, such as a player's health and coins.
- IntelliJ survival guide: the shortcuts that catch mistakes before you even compile.
- Java cheat sheet: everything on one page once you have learned it.