Documentation - james-bern/CS136 GitHub Wiki

☕️ Java

Java is an object-oriented, garbage-collected programming language.

⚠️ How to read a Java compiler error

  • 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.)

🚨 How to read a Java runtime error

  • 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's main() function, which on Line 47...
        • called class HW02's simulate1DAutomaton() function, which on Line 10...
        • accessed some array out of bounds (with invalid index 8).
  • 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. <=
    • 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) returns null if map doesn't contain key

🅰️ array

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, }

🧵 String

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 for String concatenation and converstion

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()) {
    ...
}

🧮 java.lang.*

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

🔨 java.util.*

The official generic data structures that ship with Java. Nothing special; feel free to use them.

💪 ArrayList

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 call list.set(index, ...); if list's size is at least index + 1. Otherwise you will get an out of bounds error just like if you have called array[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]

🥞 Stack

A basic stack. Push to the top. Pop from the top. (Peek at the top.) This extends ArrayList (ish).

  • ⚠️ I find the output of System.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

🎢 Queue

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

🗺️ HashMap

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

🐮 Cow.java

A teeny tiny game engine.

🏹 Vector2, Vector3

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);

}

🎨 App

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();
    }
}

✂️ Snippets

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) {
    }
}

❤️‍🔥 Vim

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

DrJava is the best IDE ever.

Open...

  1. File -> Open...
  2. 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
  3. press Open

Compile and Run

  1. press Compile
  2. 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 the Interactions pane, type run ClassName, and press Enter
      • This also lets you supply command line arguments, e.g., run Main 42 Jim
  3. if you get caught in an infinite loop, press Reset

Close (a file)

  1. click on file in left pane
  2. press Close

Find / Replace

  1. Edit -> Find / Replace (Control + F on Windows, ⌘ + F on Mac)
  2. Fill in Find Next and Replace Next
  3. Replace one at a time to be careful; Replace All to yolo it.

Debug

  1. press Compile
  2. Debugger -> Debug Mode
  3. Click and drag the vertical separator to the right so you can see your Watches
  4. Right-click on a line (Control-click on Mac) -> Toggle Breakpoint
  5. press Run
  6. Debug
    • Resume, Step Into, Step Over, Step Out
    • In Watches, double-click white box under Name, type variable name, press Enter

What if I don't like Dr Java?

  • 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.)
    1. 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
    2. java -ea ClassName to run the main in class ClassName
      • The -ea switch enables assertions (we always want them turned on this course; DrJava has them on by default)
    3. Note: The (apparently harmless) warning about the code cache being full can be suppressed by adding the additional switch -Djava.compiler=NONE
⚠️ **GitHub.com Fallback** ⚠️