Lab #1: Intro to Java

Part 0: Setup & Background

In your CS department Unix home directory, create a directory named ic211. Inside that directory, create a directory lab01 (you can nest it inside a lab directory if you like!). Inside the lab01 directory is where all the files you create for this lab will reside.

The structure of a simple Java program

It's worth taking a second to compare the simplest programs in C++ and Java. Note that they do nothing!

Ex0.cpp —The Simplest C++ Program

int main() {
  return 0;
}

Ex0.java — The Simplest Java Program

public class Ex0 {
  public static void main(String [] args) {
    return;
  }
}

The source code for the simplest C++ programs consist of

  1. a file named something .cpp
  2. that defines a function int main().

Interestingly, since there can be only one definition for a given function prototype in a program, two such files can never be used together in the creation of a new program. Already we see how reuse of code can be problematic!

The source code for the simplest Java program consists of:

  1. a file named is something.java
  2. that consists solely of the definition of a public class named something   ← i.e. it matches the file name!
  3. that defines a member function public static void main(String[] args).   ← Note: member functions are called methods in Java parlance.

Two such files can be used together as parts of a new program because the full name of the function main(String[] args) defined in the class Something is actually Something.main(String[] args), so that main functions defined in different classes technically have different names ... no conflict! Already we see how the format of a Java program makes reusing and combining code easier!

Note: It is not the case that public static void main(String[] args) has to be the only member function (or, as Java programmers prefer, method) in the class definition. You can add more function/method definitions in your class just as you would add multiple function definitions in your .cpp file while writing a C++ program.

Creating, Compiling and Running HelloWorld in Java

Is Java a compiled language or an interpreted language? Yes! Java is compiled because you run the Java compiler (javac) to translate source code (.java files) into lower-level code (.class files). It's also interpreted, because .class files do not contain machine instructions to be executed by the physical computer, but instead contain instructions for the Java Virtual Machine (JVM), which is itself just a program — i.e. the JVM is an interpreter for the low-level language (called Java bytecode) contained in the .class files.

Let's look at how to compile and run the Java version of everybody's friend: Hello World.

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello World!");
  }
}

Use an editor to create the file HelloWorld.java containing the source code for the program. Java source code files are plain ol' text files, just like C++ source code. No magic there! Note that the print statement

System.out.println("foo");

is really not that different from cout << foo;, because, although you've likely been blissfully unaware of this, the long version of the C++ statement is:

std::cout.operator<<("foo");

... which maps pretty nicely to the Java version.

Use a compiler (javac) to translate the human-readable Java source code into the class file HelloWorld.class, which contains Java bytecode, the language the JVM interprets.

Run the JVM (java) and have it execute the code in the .class file. In particular, it calls the function:

public static void main(String[] args) 
... from the class whose name matches the name of the file. In this case, because the file is named HelloWorld.class, the JVM will execute the main function defined in the class HelloWorld. If no such class exists, or no such function appears in the class, you get an error.

Step 1. Writing/Compiling/Running Java code (Lab1a.java)

  1. Using your favorite text editor put the following Java code into a file named Lab1a.java:
    public class Lab1a {
      public static void main(String[] args) {
    
      }
    }
    Note: The name of the file must be exactly Lab1a.java. Yes, upper-case vs. lower-case matters!
  2. Add the following to the main method:
    int[] x = new int[10];
    int k = 0;
    while( K < 10 ) {
       x[k] = k*k;
       k++;
    }
    for( int j = 0; j < 10; j++ ) {
       System.out.println(j + " squared is " + x[j]);
    }

    What do you think it will do when run?

  3. Now it is time to compile this program. You do this by typing the command:
    javac Lab1a.java

    (javac = "java compiler"). If you typed it in exactly as above, you should have gotten an error. Take a look at it, and notice how helpful javac is being. Fix the error.

  4. Recompile the program (so you got no errors). If you type
    ls

    You'll notice a new file, Lab1a.class, which is the bytecode to be run by the java interpreter. Run the interpreter on your program with the command

    java Lab1a
  5. Modify the program by replacing the while loop with a for loop. Compile it and run it again.

Step 2. Your first Program (Lab1b.java)

  1. Make a new file called Lab1b.java. Write the lines you need to write to make it a Java program.
  2. Add the line
    import java.util.*;
    at the very top of the file. This is like #include <iostream> in C++. It allows us to use the Scanner class, which is what we'll use to read input.
  3. Add the following code to main. Run to see what it does:
    Scanner in = new Scanner(System.in);
    System.out.print("Please input an integer: ");
    int n = in.nextInt();
    System.out.print("Please input a second integer: ");
    int k = in.nextInt();
    System.out.println("The two ints were " + n + " and " + k);
  4. What happens if you type your name instead of an integer? Try it! What you should see is that the JVM prints out the call stack, i.e. the stack of function call records as it appeared when the error occurred. One nice feature of an interpreted language is that when a run-time error occurs, the interpreter can tell you all sorts of things about the state of the program when the error occurred. This is really nice. For programs running on the CPU, the only information you get when a run-time error occurs is a message like "seg-fault".
  5. Scanner is a class that is part of Java's utility package (java.util). A package is "roughly" analogous to a C++ library. Scanner is used to facilitate reading information from an input stream. In this case, we are reading from System.in which is that standard input stream. In order to use the Scanner class, you have to import the java.util package. That's the purpose of the 'import' line of the file.
  6. Did you know that if you want to play a simple lottery where there are n possible numbers (the number of balls), and you have to pick k of them, then your odds of winning are 1 in (n * (n-1) * (n-2) * ... * (n-(k-1)))/k!, where ! means "factorial".
  7. Anyway, modify your program so that it reads in the n and k, and computes that value. You should be able to do this with code that (not counting I/O) looks just like C++. Note: to cast an int x to a double in Java you do this (double)x ... just sayin'.

    ~/$ java Lab1b
    Please input an integer: 8
    Please input a second integer: 5
    The two ints were 8 and 5
    numerator = 6720
    denominator = 120
    odds = 1 in 56 = 0.017857142857142856 

    ~/$ java Lab1b
    Please input an integer: 9
    Please input a second integer: 1
    The two ints were 9 and 1
    numerator = 9
    denominator = 1
    odds = 1 in 9 = 0.1111111111111111 

    ~/$ java Lab1b
    Please input an integer: 13
    Please input a second integer: 7
    The two ints were 13 and 7
    numerator = 8648640
    denominator = 5040
    odds = 1 in 1716 = 5.827505827505828E-4 

  8. You may wonder what else the Scanner class can do. The Scanner class, and much of the rest of what is built into Java, is described in your book. Documentation for the complete "Java API", i.e. descriptions of all packages/classes that are part of the language standard, is available online: Java 11 API Documentation. To find Scanner, look under java.base for java.util, and it is alphabetical from there (alternatively, google for "java scanner"). You'll notice a long list of functions included in the Scanner class. Which one do you think will read in a whole line? What type does it return? Change your code so that before the integers are entered, the user enters their name, and it is printed in the final println() command.

    ~/$ java Lab1b
    Enter your name: Alfred E. Newman
    Please input an integer: 11
    Please input a second integer: 4
    The two ints were 11 and 4
    numerator = 7920
    denominator = 24
    odds = 1 in 330 = 0.0030303030303030303
    Goodbye Alfred E. Newman. 

    ~/$ java Lab1b
    Enter your name: Roger Federer
    Please input an integer: 14
    Please input a second integer: 5
    The two ints were 14 and 5
    numerator = 240240
    denominator = 120
    odds = 1 in 2002 = 4.995004995004995E-4
    Goodbye Roger Federer.

Step 3. Your second program (Lab1c.java)

The following line creates a pseudo-random number generator, seeded on the current time in milliseconds.

Random rand = new Random(System.currentTimeMillis());

After that point, every time we call rand.nextInt(k), where k must be an int, it will return a random number between 0 (inclusive) and k (exclusive). Random, by the way, is in java.util, and has a lot more interesting functions you can see in your book ... or in the Java 11 API Documentation.

Write a program that generates a random number between 0 and 10 (inclusive!), and then asks the user for a guess until they get it correct. The more violent the berating on each wrong guess, the better. Code this in a file called Lab1c.java.

~/$ java Lab1c
Guess a number between 0 and 10: 0
<Insert Snarky Message> Guess again: 5
<Insert Snarky Message> Guess again: 3
<Insert Snarky Message> Guess again: 10
<Insert Snarky Message> Guess again: 6
<Insert Snarky Message> Guess again: 8
Right after 6 guesses!

Final update!

Before submitting your solution to Lab1c, change

Random rand = new Random(System.currentTimeMillis());
to
Random rand = new Random(42);

This will allow the submission system to test Lab1c. We want to seed your random number generator with the same seed every time, otherwise there is no way to test it since the current time is always changing!

Submit

Electronic Submit

Ensure that you have your submit script in your bin dir. If not, download a new submit script:

1. Go to the submit page and login. Click on your name to open the menu:

2. Click the "Retrieve Personalized Scripts" and follow the quick installation guide.

3. After you have made the above change, submit your solution using the following:

~/bin/submit -c=IC211 -p=lab01 Lab1a.java Lab1b.java Lab1c.java