Navigation
A. Introduction
This homework is intended to reinforce various OOP concepts. You won't have to write much code, and it's unlikely you'll have to do much debugging. However, the problems will be pretty tricky. Make efficient use of your time if you're stuck by working with other students or seeking help.
The online documentation for the abstract class java.io.Reader
can be found
here. It is used as a general template to define types of objects that have
a read
operation. The idea is that each time you read from a
Reader
, it gives you the next character (or characters) from some
source; just what source depends on what subtype of Reader
you have.
A program that takes in a Reader
as a parameter doesn't need to know the
subtype of the Reader
it is reading from; it simply reads from it.
As usual, you can obtain the skeleton with:
$ git fetch shared
$ git merge shared/hw3 -m "Start hw3"
$ git push
B. TrReader
Create a new TrReader
class that extends the abstract Reader
class and translates the
characters from another Reader
. That is, a TrReader
's source of characters is
some other Reader
, which is passed into the TrReader
's
constructor. The translation of the characters given by the Reader
object will be translated in the read
routine of the TrReader
class.
public class TrReader extends Reader {
/** A new TrReader that produces the stream of characters produced
* by STR, converting all characters that occur in FROM to the
* corresponding characters in TO. That is, change occurrences of
* FROM.charAt(0) to TO.charAt(0), etc., leaving other characters
* unchanged. FROM and TO must have the same length. */
public TrReader(Reader str, String from, String to) {
// FILL IN
}
// FILL IN ANY MISSING ABSTRACT METHODS HERE
}
For example, we can define Reader r = new InputStreamReader(System.in);
which causes r
to point to a Reader
whose source of
characters is the standard input (i.e., by default, what you type on
your terminal, although you can make it come from a file if desired).
This means that the following code snippet will simply copy the standard
input to the standard output:
while (true) {
int c = r.read();
if (c == -1) {
break;
}
System.out.print((char) c);
}
Printing to standard output is just printing as you normally do. However, the following snippet of code will copy the standard input to standard output after first capitalizing all occurrences of the letters a--d. For example, if the input was "bad data structure", the correctly translated output should be "BAD DAtA struCture".
TrReader translation = new TrReader(r, "abcd", "ABCD");
while (true) {
int c = translation.read();
if (c == -1) {
break;
}
System.out.print((char) c);
}
If we define a TrReader
that does not do any perform any translation at all,
then noTrans.read()
has the same effect as someReader.read()
. As a result,
the contents of someReader
are copied to standard output with no translation:
/** A TrReader that does no translation. */
TrReader noTrans = new TrReader(someReader, "", "");
while (true) {
int c = noTrans.read();
if (c == -1) {
break;
}
System.out.print((char) c);
}
The program above will work even if you only implement the
int read(char[], int, int)
method of your reader. This is because
the default implementation of int read()
uses the int read(char[],
int, int)
method (as can be seen in the
source code for the Reader class).
Notes
- The
TrReaderWithExamplesEmbedded.java.txt
file has some examples and more explanation on some of the methods, for your convenience. - The
TrReaderTest
contains a smidgen of testing for your convenience--nothing thorough, however. - The
read()
method (which you are not required to implement) returns anint
, but we're supposedly working with items of typechar
. As can be seen in the online documentation for theReader
class,read()
returns the character read as an integer, or-1
if there are no more characters to read (-1
is used to denote the end of the stream because it not a valid character). - You should not create a new
char[]
array for theread(char[], int, int)
method. Modify the array that is given to you. Also keep in mind that allReader
s (including the built-in ones) must implement this particular version ofread
. If you get an error that contains "
unreported exception IOException
" when runningmake
, you're missing athrows IOException
in one of your method declarations (just before the opening{
). We haven't learned what this means yet, so don't worry about it too much (or read Chapter 11 of HFJ) and just do it. An example of this can be seen here:public void icy() throws IOException { ... }
C. Applying TrReader
Implement the translate
function in Translate.java
using the TrReader
class that you defined in part B. You may use any number of new
operations, one
other (non-recursive) method call, and nothing else.
In addition to StringReader
, you are free to use any library classes
whose names end with Reader
(check the online
documentation), but no others. Feel free to create unit tests
for your translate
method to ensure correctness.
/** This method should return the String S, but with all characters that
* occur in FROM changed to the corresponding characters in TO.
* FROM and TO must have the same length.
* NOTE: You must use your TrReader to achieve this. */
static String translate(String S, String from, String to) {
/* NOTE: The try {...} catch is a technicality to keep Java happy. */
char[] buffer = new char[S.length()];
try {
throw new IOException(); //TODO: REPLACE THIS LINE WITH YOUR CODE.
} catch (IOException e) {
return null;
}
}
D. WeirdList
Conceptual introduction here
Complete WeirdList.java
and WeirdListClient.java
.
Do not use any if
, switch
, while
, for
,
do
, or try
statements, and do not use the ?:
conditional operator.
The WeirdList
class may contain only private fields (except for the public
static final WeirdList EMPTY
that is already provided in the skeleton code).
The methods in WeirdListClient
should not use recursion.
DO NOT FIGHT THE PROBLEM STATEMENT! We really do mean to impose
all these restrictions in an effort to direct you towards a solution
that illustrates object-oriented features. You are going to have to
take some time to think, but the solutions themselves are quite short.
The skeleton provides some cursory tests. You may refer to
IntUnaryFunction.java
, but do not modify this file.
Do not modify IntUnaryFunction.java
:
/** An IntUnaryFunction represents a function from
* integers to integers. */
public interface IntUnaryFunction {
/** Return the result of applying this function to X. */
int apply (int x);
}
Here's the code for WeirdList.java
:
/** A WeirdList holds a sequence of integers. */
public class WeirdList {
/** The empty sequence of integers. */
public static final WeirdList EMPTY =
null; // TODO: REPLACE THIS LINE
/** A new WeirdList whose head is HEAD and tail is TAIL. */
public WeirdList(int head, WeirdList tail) { /* TODO: FILL IN */ }
/** Returns the number of elements in the sequence that
* starts with THIS. */
public int length() {
return 0; // TODO: REPLACE THIS LINE
}
/** Return a string containing my contents as a sequence of numerals
* each preceded by a blank. Thus, if my list contains
* 5, 4, and 2, this returns " 5 4 2".
Note that the toString method of an object is called whenever code attempts to print said object.*/
@Override
public String toString() {
return ""; // TODO: REPLACE THIS LINE
}
/** Part 3b: Apply FUNC.apply to every element of THIS WeirdList in
* sequence, and return a WeirdList of the resulting values. */
public WeirdList map(IntUnaryFunction func) {
return null; // TODO: REPLACE THIS LINE
}
// FILL IN WITH *PRIVATE* FIELDS ONLY.
// You should NOT need any more methods here.
}
Here's the code for WeirdListClient.java
:
/** Functions to increment and sum the elements of a WeirdList. */
class WeirdListClient {
/** Return the result of adding N to each element of L. */
static WeirdList add(WeirdList L, int n) { /* FILL IN */ }
/** Return the sum of all the elements in L. */
static int sum(WeirdList L) { /* FILL IN */ }
}
HINT: Feel free to create additional classes to use. See IntUnaryFunction.java
.
E. Submission
The files you will be turning are:
TrReader.java
Translate.java
WeirdList.java
WeirdListClient.java
- Any additional classes that you may have defined to help you with section D.
DO NOT FORGET to commit all the files you created as a part of your solution for section D.
Don't forget to push both your commits and tags for your final submission. As a reminder, you can push your tags by running:
$ git push --tags