Navigation
A. Introduction
As usual, you can obtain the skeleton with:
$ git fetch shared
$ git merge shared/hw3 -m "Start hw3"
$ git push
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.
B. TrReader
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.
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 (i.e., by default, text that shows up on your terminal):
while (true) {
int c = r.read();
if (c == -1) {
break;
}
System.out.print((char) c);
}
Note that -1
is used to denote the end of the stream because it not a valid character. The notes at the bottom of the spec explain more, if you're curious.
Printing to standard output is just printing as you normally do.
After you implement your translating reader, the following snippet of code will copy the standard input to
standard output, but capitalize 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 noTranslate.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 noTranslate = new TrReader(someReader, "", "");
while (true) {
int c = noTranslate.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 the
from
string contains the same character twice (e.g.from
is "aabc" andto
is "wxyz"), it doesn't matter whether you go with the first or second translation for that character. We also will not test behavior forfrom
andto
strings of different lengths. 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.
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.
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 add and 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