Documentation - james-bern/CS136 GitHub Wiki
Java is an object-oriented, garbage-collected programming language.
- Illegal Start of Expression
- You might be missing the closing curly brace of a function. (Which means your next function starts inside of a function; this is not allowed.)
- The Stack Trace is the state of the call stack at the time your program crashed.
- We read a Stack Trace from bottom-to-top, starting from
main()
.- Example
java.lang.ArrayIndexOutOfBoundsException: 8 at HW02.simulate1DAutomaton(HW02.java:10) at HW02.main(HW02.java:47) ...
- The program started with class
HW02
'smain()
function, which on Line 47... - called class
HW02
'ssimulate1DAutomaton()
function, which on Line 10... - accessed some array out of bounds (with invalid index 8).
- The program started with class
- Example
- We read a Stack Trace from bottom-to-top, starting from
- Common Errors (Exceptions)
-
java.lang.ArrayIndexOutOfBoundsException: INVALID_INDEX
- Translation: You called
array[index]
with an invalid index.-
index
must be>= 0
and< array.length
.
-
- TODO: Figure out why the index was invalid.
-
<
vs.<=
-
- Translation: You called
-
java.lang.NullPointerException
- Translation: You used the dot operator on a
null
object. - TODO: Figure out which object was
null
. - TODO: Figure out why that object was
null
.-
map.get(key)
returnsnull
if map doesn't containkey
-
- Translation: You used the dot operator on a
-
A fixed-size sequence of elements of the same type.
class ElementType[] {
final int length;
}
-
int[] array = new int[16];
creates and zero-initializes a new array (in this case, of 16 ints) -
double[] array = { 42.0, 0.0, -1.0 };
creates and initializes an array (in this case, of 3 doubles) -
array[i] = foo;
sets the i-th element of an array (in this case, to foo) -
foo = array[i];
gets the i-th element of an array (and, in this case, assigns it to foo) - 🚨
System.out.println(Arrays.toString(array));
prints an array
int[] array = { 3, 9, 81 };
int[] array = new int[8];
for (int i = 0; i < array.length; ++i) {
array[i] = i;
}
System.out.println(Arrays.toString(array)); // { 0, 1, 2, 3, 4, 5, 6, 7, }
int[] array = { 1, 2, 3, 4, 5 };
// reverse array in place
for (int i = 0; i < array.length / 2; ++i) {
int j = (array.length - 1) - i;
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
System.out.println(Arrays.toString(array)); // { 5, 4, 3, 2, 1, }
Internally, this is an array of characters.
class String {
int length(); // number of characters in the string
char charAt(int index); // character at index
String substring(int beginIndexInclusive, int endIndexExclusive);
int indexOf(String sub); // get the index of the first occurrence of the substring (returns -1 if not found)
char[] toCharArray(); // NOTE: use sparingly, is O(n)
}
String string = "Hello"; // makes a new String
System.out.println(string.length()); // 5
System.out.println(string.charAt(1)); // 'e'
System.out.println(string.substring(0, 3)); // "Hel" (characters 0, 1, 2, but NOT 3)
System.out.println(string.substring(1, 3)); // "el" (characters 1, 2, but NOT 3)
System.out.println(string.indexOf("ell")); // 1 (substring "ell" starts at index 1)
System.out.println(string.indexOf("Kahoot")); // -1 (substring "Kahoot" NOT found)
The +
operator is oddly convenient.
String string = "Hello" + 3; // "Hello3"
String string = "" + 3; // "3"
System.out.println("You have been asleep for " + numberOfDaysInRoom + " days.");
for (char c : string.toCharArray()) {
...
}
Some useful math-y stuff.
class Integer {
static final int MAX_VALUE;
static final int MIN_VALUE;
}
class Double {
static final double POSITIVE_INFINITY;
static final double NEGATIVE_INFINITY;
}
class Math {
static double sqrt(double x); // returns the square root of x
static double abs(double x); // returns the absolute value of x
static int abs(int x);
static int min(int x, int y); // returns the smaller of x and y
static double min(double x, double y);
static int max(int x, int y); // returns the larger of x and y
static double max(double x, double y);
// NOTE: if you just want to square a number, use `x * x`
static double pow(double x, double y); // returns x to the power of y
// // returns (x % y) but does what you want for negative x
//
// internally, this does something similar to (((x % y) + y) % y)
//
// floorMod(-3, 3) -> 0
// floorMod(-2, 3) -> 1
// floorMod(-1, 3) -> 2
// floorMod( 0, 3) -> 0
// floorMod( 1, 3) -> 1
// floorMod( 2, 3) -> 2
static int floorMod(int x, int y);
}
double foo = Math.sqrt(9.0); // 3.0
The official generic data structures that ship with Java. Nothing special; feel free to use them.
An automatically-expanding array, aka a stretchy buffer, dynamic array, vector, ... Internally, this is an array.
⚠️ Be very careful removing elements from an array list while you are iterating over it! (If you find yourself wanting to do this, there is probably a different (better) approach!⚠️ You can only calllist.set(index, ...);
iflist
's size is at leastindex + 1
. Otherwise you will get an out of bounds error just like if you have calledarray[index] = ...;
class ArrayList<ElementType> {
void add(ElementType element); // Adds a new element to the back of the list.
void add(int index, ElementType element); // Add (insert) a new element into the list at a specific index.
ElementType get(int index); // Get the element at a specific index. Similar to `array[index]`.
void set(int index, ElementType element); // Set the element at a specific index. Similar to `array[index] = element;`
void remove(int index); // Remove the element at a specific index. NOTE: Careful doing this while iterating over the list!
int size(); // Get the number of elements currently in the list.
boolean isEmpty(); // Get whether the list is empty (size() == 0).
}
ArrayList<String> list = new ArrayList<>();
System.out.println(list); // []
list.add("Hello");
list.add("World");
System.out.println(list); // [Hello, World]
list.add(1, "Cruel");
System.out.println(list); // [Hello, Cruel, World]
System.out.println(list.size()); // 3
System.out.println(list.get(1)); // Cruel
list.remove(0);
System.out.println(list); // [Cruel, World]
list.set(1, "Summer");
System.out.println(list); // [Cruel, Summer]
A basic stack. Push to the top. Pop from the top. (Peek at the top.) This extends ArrayList (ish).
⚠️ I find the output ofSystem.out.println(stack);
very confusing (feels "upside-down"). Careful printing stacks; see example code below to understand what happens.
class Stack<ElementType> extends ArrayList<ElementType> {
void push(ElementType element); // Push (add) a new element to the top of the stack.
ElementType pop(); // Pop (remove) the top element of the stack and returns it.
ElementType peek(); // Peek (look) at the top element of the stack (without removing it) and return it.
int size(); // Get the number of elements currently in the stack.
boolean isEmpty(); // Get whether the stack is empty (size() == 0).
}
Stack<String> stack = new Stack<>();
stack.push("Hello");
stack.push("Cruel");
stack.push("World");
System.out.println("BOTTOM " + stack + " <-> TOP"); // BOTTOM [Hello, Cruel, World] <-> TOP
System.out.println(stack.peek()); // World
System.out.println(stack.size()); // 3
System.out.println(stack.pop()); // World
System.out.println(stack.pop()); // Cruel
System.out.println(stack.pop()); // Hello
A basic First In First Out queue. Add to the back. Remove from the front. (Also peek at the front.)
- (Java doesn't actually have this data structure, so I'm using something more complicated and leaving out a bunch of functions so we can pretend.)
class ArrayDeque<ElementType> {
void add(ElementType element); // Add (enqueue) a new element to the back of the queue.
ElementType remove(); // Remove (dequeue) the front element of the queue and return it.
ElementType peek(); // Peek (look) at the front element of the queue (without removing it) and return it.
int size(); // Get the number of elements currently in the queue.
boolean isEmpty(); // Get whether the queue is empty (size() == 0).
}
ArrayDeque<String> queue = new ArrayDeque<>();
queue.add("Hello");
queue.add("Cruel");
queue.add("World");
System.out.println("FRONT <- " + queue + " <- BACK"); // FRONT <- [Hello, Cruel, World] <- BACK
System.out.println(queue.peek()); // Hello
System.out.println(queue.size()); // 3
System.out.println(queue.remove()); // Hello
System.out.println(queue.remove()); // Cruel
System.out.println(queue.remove()); // World
A map/dictionary (similar to Python or Lua's dictionary). Internally, this is an array.
class HashMap<KeyType, ValueType> {
// Put (add, insert) a new key-value pair into the map.
// NOTE: Can also be used to update a key's value.
void put(KeyType key, ValueType value);
// Get (lookup) a key's value in the map.
// NOTE: Returns null if map doesn't contain key.
Value get(KeyType key);
// Get the (unordered) set of all keys.
// NOTE: Use this to iterate through all keys.
// for (KeyType key : map.keySet()) { ... }
Set<KeyType> keySet();
// Get the number of key-value pairs currently in the hash map.
int size();
// Return whether the map contains a key-value pair with the specified key.
boolean containsKey(KeyType key);
// Return whether the map contains a key-value pair with the specified value.
boolean containsValue(ValueType value);
}
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Ekans", 23);
map.put("Arbok", 24);
map.put("Jigglypuff", -1);
map.put("Jigglypuff", 39);
System.out.println(map.get("Jigglypuff")); // 39
System.out.println(map.get("Ash Ketchum")); // null
System.out.println(map.size()); // 3
for (String key : map.keySet()) {
System.out.println(key);
}
// Jigglypuff
// Arbok
// Ekans
A teeny tiny game engine.
Simple 2D and 3D mathematical vectors. Usually, Vector2
is used for position/velocity and Vector3
is used for color.
class Vector2 {
double x;
double y;
// constructors
Vector2(); // (0.0, 0.0)
Vector2(double x, double y); // (x, y)
Vector2(Vector2 other); // (other.x, other.y)
Vector2(double s); // (s, s)
// arithmetic operators
Vector2 plus(Vector2 other); // this + other
Vector2 minus(Vector2 other); // this - other
Vector2 times(double scalar); // scalar * this
Vector2 dividedBy(double scalar); // (1.0 / scalar) * this
// other non-static methods
double length(); // distance formula: Math.sqrt(x * x + y * y)
double squaredLength(); // length * length
Vector2 directionVector(); // unit (length = 1) vector pointing in same direction as this
// static methods
static double distanceBetween(Vector2 a, Vector2 b); // distance between points a and b
static Vector2 directionVectorFrom(Vector2 a, Vector2 b); // unit (length = 1) vector pointing from a to b
static Vector2 lerp(double t, Vector2 a, Vector2 b); // linearly interpolate between a and b; returns (1.0 - t) * a + t * b;
// constants
static final Vector2 right; // ( 1.0, 0.0)
static final Vector2 left; // (-1.0, 0.0)
static final Vector2 up; // ( 0.0, 1.0)
static final Vector2 down; // ( 0.0, -1.0)
}
class Vector3 {
double x;
double y;
double z;
// constructors
Vector3(); // (0.0, 0.0, 0.0)
Vector3(double x, double y, double z); // (x, y, z)
Vector3(Vector3 other); // (other.x, other.y, other.z)
Vector3(double s); // (s, s, s)
// constants
static final Vector3 white;
static final Vector3 lightGray;
static final Vector3 gray;
static final Vector3 darkGray;
static final Vector3 black;
static final Vector3 red;
static final Vector3 orange;
static final Vector3 yellow;
static final Vector3 green;
static final Vector3 cyan;
static final Vector3 blue;
static final Vector3 magenta;
// returns a color from a silly cyclic rainbow colormap
// NOTE: t is wrapped to the internal [0.0, 1.0)
static Vector3 rainbowSwirl(double t);
// same math methods as Vector2
Vector3 plus(Vector3 other);
Vector3 minus(Vector3 other);
Vector3 times(double scalar);
Vector3 dividedBy(double scalar);
double length();
double squaredLength();
Vector3 directionVector();
static double distanceBetween(Vector3 a, Vector3 b);
static Vector3 directionVectorFrom(Vector3 a, Vector3 b);
static Vector3 lerp(double t, Vector3 a, Vector3 b);
}
An "app" featuring setup/reset, loop, keyboard input, mouse input, and some simple graphics. Internally, this is just a wrapper around Swing.
class App {
// To run an App, create a new instance of it and call this method.
// This method calls setup() once and then calls loop() over and over.
void run();
// This method is called once before the app starts looping, and whenever the user presses 'R'.
// It sets up (or resets) the app state.
// You may implement this method in the child class.
void setup();
// This method is called once per frame until the user presses 'Q'.
// It updates the app state and draws everything.
// You may implement this method in the child class.
void loop();
// input
Vector2 mousePosition;
boolean mousePressed;
boolean mouseHeld;
boolean mouseReleased;
boolean keyHeld(int key);
boolean keyPressed(int key);
boolean keyReleased(int key);
boolean keyToggled(int key);
// draw
void drawLine(Vector2 pointA, Vector2 pointB, Vector3 color);
void drawCircle(Vector2 center, double radius, Vector3 color);
void drawCenterRectangle(Vector2 center, Vector2 size, Vector3 color);
// NOTE: cornerA and cornerB are any 2 opposite corners of the rectangle
void drawCornerRectangle(Vector2 cornerA, Vector2 cornerB, Vector3 color);
void drawString(String string, Vector2 position, Vector3 color, int fontSize, boolean center);
// window
void setWindowBackgroundColor(double red, double green, double blue);
void setWindowBackgroundColor(Vector3 color);
void setWindowSizeInWorldUnits(double width, double height);
void setWindowCenterInWorldUnits(double x, double y);
void setWindowHeightInPixels(int height);
void setWindowTopLeftCornerInPixels(int x, int y);
}
class AppExample extends App {
Vector2 chaserPosition;
double time;
void setup() {
chaserPosition = new Vector2();
time = 0.0;
}
void loop() {
if (!keyToggled('P')) { time += 0.0167; }
if (mouseHeld) {
chaserPosition = chaserPosition.plus(Vector2.directionVectorFrom(chaserPosition, mousePosition));
}
drawLine(chaserPosition, mousePosition, Vector3.white);
drawCircle(chaserPosition, 2.0, Vector3.rainbowSwirl(time));
drawCenterRectangle(mousePosition, new Vector2(4.0), Vector3.cyan);
}
public static void main(String[] arguments) {
App app = new AppExample();
app.setWindowBackgroundColor(Vector3.black);
app.setWindowSizeInWorldUnits(64.0, 64.0);
app.setWindowCenterInWorldUnits(0.0, 0.0);
app.setWindowHeightInPixels(512);
app.setWindowTopLeftCornerInPixels(64, 64);
app.run();
}
}
Some useful little things for you to copy and paste into your code.
// returns a random double in range [a, b)
static double randomDouble(double a, double b) {
assert a < b;
return a + Math.random() * (b - a);
}
// returns a random integer in range [a, b)
// NOTE: can return a; cannot return b
static int randomInt(int a, int b) {
assert a < b;
return (int) randomDouble(a, b);
}
static int getIntFromUser() {
Scanner scanner = new Scanner(System.in);
while (!scanner.hasNextInt()) { scanner.nextLine(); }
return scanner.nextInt();
}
static String getStringFromUser() {
Scanner scanner = new Scanner(System.in);
return scanner.nextLine();
}
// linearly interpolate between a and b
static double lerp(double t, double a, double b) {
return (1.0 - t) * a + t * b;
}
static boolean areApproximatelyEqual(double a, double b) {
return Math.abs(a - b) < 1e-5;
}
final static String[] pokemonNames = { "Bulbasaur", "Ivysaur", "Venusaur", "Charmander", "Charmeleon", "Charizard", "Squirtle", "Wartortle", "Blastoise", "Caterpie", "Metapod", "Butterfree", "Weedle", "Kakuna", "Beedrill", "Pidgey", "Pidgeotto", "Pidgeot", "Rattata", "Raticate", "Spearow", "Fearow", "Ekans", "Arbok", "Pikachu", "Raichu", "Sandshrew", "Sandslash", "Nidoran♀", "Nidorina", "Nidoqueen", "Nidoran♂", "Nidorino", "Nidoking", "Clefairy", "Clefable", "Vulpix", "Ninetales", "Jigglypuff", "Wigglytuff", "Zubat", "Golbat", "Oddish", "Gloom", "Vileplume", "Paras", "Parasect", "Venonat", "Venomoth", "Diglett", "Dugtrio", "Meowth", "Persian", "Psyduck", "Golduck", "Mankey", "Primeape", "Growlithe", "Arcanine", "Poliwag", "Poliwhirl", "Poliwrath", "Abra", "Kadabra", "Alakazam", "Machop", "Machoke", "Machamp", "Bellsprout", "Weepinbell", "Victreebel", "Tentacool", "Tentacruel", "Geodude", "Graveler", "Golem", "Ponyta", "Rapidash", "Slowpoke", "Slowbro", "Magnemite", "Magneton", "Farfetch'd", "Doduo", "Dodrio", "Seel", "Dewgong", "Grimer", "Muk", "Shellder", "Cloyster", "Gastly", "Haunter", "Gengar", "Onix", "Drowzee", "Hypno", "Krabby", "Kingler", "Voltorb", "Electrode", "Exeggcute", "Exeggutor", "Cubone", "Marowak", "Hitmonlee", "Hitmonchan", "Lickitung", "Koffing", "Weezing", "Rhyhorn", "Rhydon", "Chansey", "Tangela", "Kangaskhan", "Horsea", "Seadra", "Goldeen", "Seaking", "Staryu", "Starmie", "Mr. Mime", "Scyther", "Jynx", "Electabuzz", "Magmar", "Pinsir", "Tauros", "Magikarp", "Gyarados", "Lapras", "Ditto", "Eevee", "Vaporeon", "Jolteon", "Flareon", "Porygon", "Omanyte", "Omastar", "Kabuto", "Kabutops", "Aerodactyl", "Snorlax", "Articuno", "Zapdos", "Moltres", "Dratini", "Dragonair", "Dragonite", "Mewtwo", "Mew" };
// Sleep for a bit then clear the terminal.
// This is useful for when you want to do "graphics" with the Terminal as your display.
// Just stick sleepThenClearTerminal(17) at the very end of your while loop and presto!
// NOTE: This function does NOT work inside DrJava.
// You must run your program in a regular Terminal if you want this function to work.
// Instructions for doing so are in Documentation under "What if I don't like DrJava?"
static void sleepThenClearTerminal(int millisecondsToSleep) {
try {
Thread.sleep(millisecondsToSleep);
if (System.getProperty("os.name").contains("Windows")) {
new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
} else {
System.out.print("\033\143");
}
} catch (Exception exception) {
}
}
To use Vim as a Java IDE (you'll still have to use DrJava or other for your Debugger), put this code in your .vimrc
⚠️ This makes several (big) assumptions; see comments in code below.
" set up windows for terminal on top and quickfix on right
autocmd VimEnter *.* silent!
\ | vertical copen
\ | wincmd L
\ | wincmd h
\ | wincmd n
\ | wincmd j
" " map Control + Enter to compile and run
" FileName.java must have class FileName, which must have the main method you want to run
" Cow.java must be in the same directory
"https://stackoverflow.com/questions/6411979/compiling-java-code-in-vim-more-efficiently
map <C-Enter> :call CompileAndRun()<CR>
imap <C-Enter> <Esc><C-Enter>
func! CompileAndRun()
exec "w"
if &filetype == 'java'
silent exec "! rm *.class"
silent exec "set makeprg=javac"
silent exec "make! % Cow.java"
exec "let className = expand('%:r')"
wincmd k
exec "terminal! ++curwin java -Djava.compiler=NONE -ea " . className
wincmd j
endif
endfunc
DrJava is the best IDE ever.
-
File
->Open...
- Select files
- You can multi-select a range of files by clicking on the first file in the range and then clicking on the last file in the range while holding
Shift
- You can multi-select individual files by clicking on each file while holding
Control
- You can multi-select a range of files by clicking on the first file in the range and then clicking on the last file in the range while holding
- press
Open
- press
Compile
- press
Run
- This will run the
main
of the first class in the file you currently have open. - If you would like to run the
main
of a different class, you can go into theInteractions
pane, typerun ClassName
, and pressEnter
- This also lets you supply command line arguments, e.g.,
run Main 42 Jim
- This also lets you supply command line arguments, e.g.,
- This will run the
- if you get caught in an infinite loop, press
Reset
- click on file in left pane
- press
Close
-
Edit
->Find / Replace
(Control + F
on Windows,⌘ + F
on Mac) - Fill in
Find Next
andReplace Next
-
Replace
one at a time to be careful;Replace All
to yolo it.
- press
Compile
-
Debugger
->Debug Mode
- Click and drag the vertical separator to the right so you can see your
Watches
- Right-click on a line (Control-click on Mac) ->
Toggle Breakpoint
- press
Run
- Debug
-
Resume
,Step Into
,Step Over
,Step Out
- In
Watches
, double-click white box underName
, type variable name, pressEnter
-
- First, how dare you.
- Second, you can use whatever IDE you want and then compile and run in a Terminal 🙂👍 (DrJava is great, but its printing is horrifyingly slow and it's good to know how to compile in a Terminal anywhoozle.)
-
javac FileName.java
to compile a file-
javac FileName0.java FileName1.java ...
to compile multiple files -
javac *.java
to compile all Java files in the current directory
-
-
java -ea ClassName
to run themain
in classClassName
- The
-ea
switch enables assertions (we always want them turned on this course; DrJava has them on by default)
- The
-
Note: The (apparently harmless) warning about the code cache being full can be suppressed by adding the additional switch
-Djava.compiler=NONE
-