Java Exploration
In the spirit of one of the meta-learning goals of the course, we’ll use these first weeks not just to learn the Java programming language but also the refine our skills at learning new programming languages. The jump from C to Java is no where near as dramatic as the jump from Racket to C, so we can use this opportunity to develop some best practices for migrating from language to language whether it’s from Java to C#, Java to Python, or to some more exotic language.
Partners, Collaboration, and Turn-ins
For our weekly labs, you will work with a randomly-assigned partner. We’ll mix the partners every week to keep things fresh. Please make sure you understand the collaboration policies for the course as presented in the syllabus. And finally, whenever you do work with your partner, keep in mind the golden rule when working with a group:
You are there to help your partner learn and vice versa!
Github Repositories
At this point, you should have your development environment set up for the course: Java, VSCode, Maven, and Git. We will use Github to manage our project work for the course. To get started, go to the template repository on Github for this week’s labs/project:
Choose the option to “Use this template” and “Create a new repository” to create a copy of the template in your account.
From here, give your groupmates access to this new repository. Navigate to the repository on Github, click “Settings” → “Collaborators” in the sidebar and add your partner’s via their Github usernames to the repository.
Finally, you will need to clone down the repository to your local machine so you can do work on it. Navigate back to your repository’s main page. (Make sure this is your copy’s page and not the template’s!) Click on “Code” → “Local” → “SSH” and copy the SSH location. From the terminal, issue the following command in the directory where you want to put your project’s folder:
$> git clone <SSH location>
If everything is set up correctly, this command should clone down your repository to your machine. From there, you can open up the folder in VSCode and begin to work!
Part 1: Building Up Your Bag of Programs
With a basic programming pipeline established, you are now in the position to begin writing real programs. I typically break down what I can do in a programming language into two buckets:
- What I can do with the language itself.
- What I can do with the language’s libraries.
For solving more interesting problems, we’ll need external libraries (either the built-in libraries or some third-party libraries), for example, to perform file I/O or create graphics. But it is worthwhile to tackle the two buckets independently. In particular, learning what primitive operations the language provides gives you insight into how you should model your problems and structure your solutions.
Again, Java is an ancestor of C, so much of these primitive operations are carried over without any changes. In particular, minus some slightly different syntax and subtly different semantics (which will be exposed as we write more Java):
- Basic types,
- Variable declarations and assignments,
- Basic expressions and statements, and
- Function declarations.
Are identical between Java and C.
With this in mind, try writing a program that solves the canonical Fizzbuzz interview problem:
In Fizzbuzz.java (found in the edu.grinnell.csc207.exploration package), write a complete program that takes a single command-line argument n, presumed to be an integer, and prints the integers from 1 to n (inclusive) to the console, one integer per line.
However:
- When
nis a multiple of 3, printfizz, - When
nis a multiple of 5, printbuzz, and - When
nis both a multiple of 3 and 5, printfizzbuzz.
> java Fizzbuzz 5
1
2
fizz
4
buzz
Your program does not need to perform any error-checking on the command-line arguments, i.e., it can assume it receives exactly one argument that is an integer.
To convert a String to an int, use the Integer.parseInt(n) function.
When executing this program via Maven (mvn exec:java), you’ll need to specify the fully-qualified name of the Fizzbuzz class explicitly: edu.grinnell.csc207.exploration.FizzBuzz with the -Dexec.mainClass flag.
Additionally, you will also need to use the -Dexec.args flag to specify Fizzbuzz’s command-line argument.
Putting the two together, the following Maven invocation compiles and runs the program with 20 as the command-line argument:
mvn compile exec:java -q "-Dexec.mainClass=edu.grinnell.csc207.exploration.FizzBuzz" "-Dexec.args=20"
(Remember you can use up-arrow and down-arrow in the terminal to scroll through your command history! This will help you avoid having to type out this command over and over again!)
The fizzbuzz problem is an example of one of the standard programs I try to write down whenever I learn a new language.
It’s ideal for this purpose because it:
- Is a short program to write, yet is complex enough to be non-trivial.
- Tests the language’s expressiveness. In other words, how do I express repetitive and conditional behavior?
Committing and Pushing Your Changes
When you reach stopping points in development, you should commit and push your changes to Github to save your work. YOu can do this through the Git menu in the left-hand sidebar of VSCode!
Part 2: The String Class
In this part, we use the String as our vehicle for exploring what an object can provide us as a client as well as get practice using the behavior of objects to solve problems.
The Standard Library Documentation
Rather than summarize the set of behavior that String objects expose, we’ll use this opportunity to explore the Java standard library. The standard library is built-in to Java; it contains a ton of classes for you to use that cover your basic needs as a programmer: containers, graphical interfaces, networking, and parsing among others. You can find the standard library documentation for Java 23 below:
(Technically, this is the link to the java.base module page which contains the standard library packages.)
In my humble opinion, the Java standard library documentation is the best organized API document out there, and is a large reason why Java is so popular. On this page, you’ll see the following things:
-
The main page, which features a description of every package available in the Java standard library. Whereas a Java source file (roughly) corresponds to a single Java class, a package corresponds to a folder in the file system. For example, the
java.utilpackage corresponds to the folderjava/utilin the standard library’s source tree. Thus, packages are a way of organizing collections of classes into logical units. -
The sidebar, which features an abbreviated list of all the packages as well as all the classes in those packages.
In the “All Classes” list, find the String class and click through to see its documentation.
All the pages of the Java documentation are organized as follows:
- An overview of the class, in particular its purposes and how to use it.
- A summary of the fields, constructors, and methods of that class. Recall that the fields and methods correspond to the state and behavior of objects of this class. The constructors correspond to how we construct objects of this class.
- Detailed descriptions of the fields, constructors, and methods.
Feel free to skim through the API page; there’s a lot of stuff here!
Lab Write-up
For this part, you’ll write code in the StringExploration.java file found in the project.
Additionally, you will write your answers in the first two subparts in the README.md file found at the root of the project.
you will write your aMarkdown file file called README.md.
This file is a Markdown file,a simple, text-based, markup language that is common when writing programming documentation.
Part 2.1: Old Hat, New Hat
You have already worked with string datatypes in other languages. Keeping in mind our theme of “mapping old knowledge to new setting,” let’s brainstorm what we could do with strings in Scheme and C and either find equivalents in the Java standard library or note that these are things we must implement ourselves.
- With your partner, brainstorm a list of (a) useful functions over strings you’ve used in other languages and (b) operations, i.e., common programming patterns, over strings.
- For each entry in your list, peruse the String class documentation and try to find an equivalent String method that performs the function/operation in question. If you can’t find such a method, write a code snippet that performs the same effect.
Part 2.2: Iceberg, Right Ahead!
One of the operations you may have identified that you want to perform over strings is equality. Equality is trickier than it seems and requires some in-depth discussion. Sometimes, seemingly simple operations hide language complexity, some of which your prior experience may account for and others, you just need to be ready to learn something new!
When you are done with section, please check your answers with a member of the course staff!
-
First, does the standard equality operator work over strings, (
==)? Try running the following code snippets (either in yourmainfunction or in JShell) and see if they work as you expect:String s1 = "hello world!"; String s2 = "hello world!"; System.out.println(s1 == s2); // A String s3 = s1.substring(0, 5); String s4 = s2.substring(0, 5); System.out.println(s3 == s4); // B String s5 = new String(new char[] { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!' }); System.out.println(s1 == s5); // C -
You may have noticed that there is an
equals(obj)method of the string class! Try replacing all the uses of==with appropriate invocations of theequalsmethod (does it matter which of the two strings you callequalson?). Do you obtain the results that you were expecting now? Based on your results, complete the following sentence:To compare two strings for equality, we must …
-
But why is this the case? Let’s focus first on the equality checks marked
BandCabove. I’ll appeal to your knowledge of C and state a subtlety about Java values not apparent until now:Values of object type (of which
Stringis one) are actually pointers (or more specifically, references) to those values in memory.With this in mind, in a sentence or two, explain why
==does not work for theBandCstring examples listed above. -
Now, let’s revisit the equality check marked
A. You might observe that your answer to the previous part doesn’t account for the results in this case. It turns out that Java does something special that our previous languages do not do!Search the String class documentation for the
intern()method and read about it. Based on this, can you explain the results of this equality check?
Part 3: A Trio of Problems
With this documentation in hand, tackle these three programming problems. You are free to use any of the methods of the String class as you see fit.
Problem 1: Intersperse
Write a function, intersperse(arr), that produces a string that is the result of interspersing a comma among all the strings found in the given array.
For example, if you pass the array { "ab", "cd", "ef" } to intersperse, you should receive the string "ab,cd,ef".
(Hint: there is a concat method of the string class.
However, the plus (+) operator also performs concatenation between strings in Java!)
Problem 2: Comma-separated Value Parsing
Write a function parseName(String s) that parses a full name from s and returns it in the order of: <first name> <middle name> <last name>.
You should assume that the string s is in the following format:
<last name>,<first name>,<middle name>
For example, parseName("Turing,Alan,Mathison") should produce the result Alan Mathison Turing.
You may assume that commas do not appear in the given name.
Problem 3: Forgiving Prompt
For this problem, we’ll use a new class, the Scanner to get input from the user.
Scanner objects provide the same functionality as the C scanf or readline functions, but are much easier to use!
Here is an example of using a Scanner attached to System.in, i.e., standard input:
// This `import` statement is necessary to make the Scanner class visible
// since it is not in the `java.lang` package.
import java.util.Scanner;
public static String fetchString() {
Scanner scanner = new Scanner(System.in);
// the nextLine() method returns the next line from the stream
// that is used to construct the scanner.
return scanner.nextLine();
}
With this in mind, write a function, forgivingPrompt(question), that prompts the user to answer yes or no to given question (specified as String).
The function returns true if the user answers positively and false if the user answers negatively.
The prompt is “forgiving” in that it accepts a variety of answers:
- Y, Yes, Yep
- N, No, Nope, and
- Any lower-case or upper-case variants of these.
If the user does not enter in one of these responses, the function prompts the user again. The function will prompt the user repeatedly until one of these responses is given.