~/ Just enough Java for Crafting Interpreters
I've been working my way through Robert Nystrom's Crafting Interpreters and had to learn some Java in order to run
the Scanner
class implemented in Chapter 4.
The last time I wrote Java was right before I withdrew from my first CS 101 course, so I had to put some time into mastering the basics. This post documents a handful of the things I had to learn to start scanning tokens in Lox!
Here's a link to an example that will have you up and running with Java in no time! https://github.com/jshawl/just-enough-java-for-crafting-interpreters
Installing the JDK
The last time I tried installing the JDK on a mac, I was prompted to create
an account with Oracle, which I did not want to do. I decided to go with
docker compose
for all of my Java work. The compose.yml
file looks like:
services:
java:
image: eclipse-temurin:17
Starting the java
service with docker compose run java bash
will open
a shell where you can then run javac
to compile your code and java
to
run it.
Creating a first Java class
I created my first class inside of com/jshawl/example
so that the package
name com.jshawl.example
matched the directory structure. More on packages
in a minute...
Your directory structure should look like this:
./
├── com/
│ └── jshawl/
│ └── example/
│ └── FirstClass.java
└── compose.yml
and inside of FirstClass.java
:
package com.jshawl.example;
class FirstClass {
public static void main(String[] args) {
System.out.println("Hello from FirstClass!");
}
}
Compiling and Running
Let's modify the compose.yml
to specify a volume for the newly
created com/
directory:
services:
java:
image: eclipse-temurin:17
+ working_dir: /app
+ volumes:
+ - ./com:/app/com
Start the container:
docker compose run java bash
Compile the code:
javac com/jshawl/example/FirstClass.java
This will create a new file com/jshawl/example/FirstClass.class
.
You can now run this code with:
java com.jshawl.example.FirstClass
#=> Hello from FirstClass!
Packages
Packages allow us to group related classes and use a namespace to import
classes from the standard library à la import java.io.BufferedReader
.
For the examples in Crafting Interpreters, several classes reference
each other, and a shared package allows us to include code without a
specific import
statement.
Let's create a second class to demo this functionality:
// in com/jshawl/example/SecondClass.java
package com.jshawl.example;
class SecondClass {
public static void greetings() {
System.out.println("Greetings from SecondClass.");
}
}
and create an instance of this class inside of FirstClass.java
:
public static void main(String[] args) {
System.out.println("Hello from FirstClass!");
+ SecondClass secondClass = new SecondClass();
+ secondClass.greetings();
you can now recompile:
javac com/jshawl/example/FirstClass.java
and run and you'll see the output from SecondClass
:
java com.jshawl.example.FirstClass
#=> Hello from FirstClass!
#=> Greetings from SecondClass.
You might have noticed I didn't explicitly compile SecondClass
. javac
is smart enough to compile the code that is referenced in FirstClass
.
If you wanted to compile everything even if it isn't used anywhere yet, use a glob:
javac com/jshawl/example/*.java
I'll plan to come back and add to this guide if I encounter any other foundational knowledge about building and running Java programs, but so far this was enough for me to start a jlox prompt.
Happy hacking!
~/ Posted by Jesse Shawl on 2023-10-10