In: Computer Science
Generic Stack due 10/16/2020 Friday 12 pm Mountain Time
Generic Stack
Make It Generic!
The first part of this lab is making your stack generic. Take the code from your working StringStack class - everything except the main method - and paste it into the GenericStack class. Change the name of the constructors to match the new name of the class, then modify the whole class so it uses generics, and can store any type that a programmer asks for.
Numbers and Readers
To take advantage of polymorphism, Java has a lot of inheritance hierarchies built-in. You may not have known that simple numeric classes, like Integer and Float, are actually part of one! Java contains a generic number class creatively called Number, and pretty much any class in Java whose purpose is to store numbers inherits from this class.
There are many types of Readers that can extract characters from different things, such as Strings, Files, and arrays.
Scrolls of Numbers
A few years back, I bought a box of random numbers from an intrepid salesman who insisted they were special. I'd like to find out if that's really the the case. Unfortunately, I've stored the numbers in a bunch of different places - some of them are in Strings, others are in files, it's a bit of a mess.
So I created a generic calculator that, using Readers, can read in a list of numbers from any source, put them into a stack, and then add them all up. Since I'm a good programmer, I put each of these steps in their own functions... but it looks like I accidentally erased some of them. Your next task in the lab is to repair my generic stack calculator by fixing the functions.
Wrapping up
you should get output that looks somewhat like this (exact numbers may vary due to floating-point rounding):
76.4 76.39999961853027 4584425.0 15.324
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import java.util.*;
public class GenericStack<T> {
/* YOUR CODE HERE
* Just like in the ArrayList lab, copy your StringStack code,
excluding the
* main method, here.
* Then, modify it so it's generic!
*/
public static void main(String[] args) {
// If any of these lines cause a compilation error, your stack
hasn't
// been properly made generic.
GenericStack<Integer> intStack = new
GenericStack<>();
GenericStack<String> stringStack = new
GenericStack<>();
GenericStack<ArrayList<String>> listStack = new
GenericStack<>();
}
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import java.util.*;
import java.io.*;
import java.math.*;
public class Calculator {
public static void main(String[] args) throws FileNotFoundException, IOException {
String numbers = "56 3 7 2.0 8.4";
char[] moreNumbers = "1.0 2 3 4 5 0.324".toCharArray();
GenericStack<Number> stack1 = makeStack(new
StringReader(numbers));
System.out.println(evaluate(stack1));
GenericStack<Float> stack2 = new
GenericStack<>();
for (String token : numbers.split(" ")) {
stack2.push(Float.parseFloat(token));
}
System.out.println(evaluate(stack2));
GenericStack<Number> stack3 = makeStack(new
FileReader("numbers.txt"));
System.out.println(evaluate(stack3));
GenericStack<Number> stack4 = makeStack(new
CharArrayReader(moreNumbers));
System.out.println(evaluate(stack4));
}
/* This function is meant to take in a Reader called "reader" and
return a
* stack of Numbers.
*
* Remember: don't change anything that's already there. Just add
your new
* code where the comment is to fix the function's signature.
*/
public static /* ??? */ throws IOException {
GenericStack<Number> stack = new
GenericStack<>(64);
char[] data = new char[64];
reader.read(data);
String tokens = new String(data);
for (String token : tokens.split(" ")) {
stack.push(parse(token));
}
return stack;
}
/* This function is meant to take in a stack of ANY KIND of
Number
* called "stack", and return the double you get if you add all of
the
* numbers together.
* The function must be able to accept a stack of ANY KIND of
Number!
*
* Hint: use wildcard generics!
*/
public static /* ??? */ {
/* implement me! */
return 0.0;
}
/* This function is missing a return type.
* Examine it, and see if you can tell what type it should
return.
* (Spoiler: it's probably what you think it is.)
*/
public static /* ??? */ parse(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) { }
try {
return Double.parseDouble(s);
} catch (NumberFormatException e) { }
return new BigDecimal(s);
}
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
import java.util.*;
public class StringStack {
private String [] stack;
public int size, top;
public StringStack(int size) {
this.top=-1;
this.size=size;
stack= new String[size];
}
public StringStack() {
this.size=10;
this.top=-1;
stack= new String[this.size];
}
public boolean empty() {
return this.top==-1;
}
public String peek() {
if (this.top==-1) {
throw new
NoSuchElementException("Empty stack!");
}
else {
return this.stack[this.top];
}
}
public String pop() {
if (this.top==-1) {
throw new NoSuchElementException("Empty
stack!");
}
else {
return this.stack[this.top--];
}
}
public String push(String s) {
if (this.top>=this.size-1) {
throw new IllegalStateException("Stack is
full!");
}
this.stack[++this.top]= s;
return this.stack.toString();
}
public int search(String s) {
int dist = 0;
int top = this.top;
while(top>=0) {
if(this.stack[top]==s) {
return
dist;
}
dist++;
top--;
}
return -1;
}
// I removed the main method from StringStack Class because I was getting a prompt saying the question is too long. This all the //information
// GenericStack.java
import java.util.*;
public class GenericStack<T> {
/*
* Just like in the ArrayList lab, copy your
StringStack code, excluding the
* main method, here.
* Then, modify it so it's generic!
*/
// convert the array to generic type T
private T [] stack;
public int size, top;
// parameterized constructor
public GenericStack(int size) {
this.top=-1;
this.size=size;
stack= (T[])new Object[size];
}
// default constructor
public GenericStack() {
this.size=10;
this.top=-1;
stack= (T[])new Object[this.size];
}
// returns true if stack is empty else return
false
public boolean empty() {
return this.top == -1;
}
// return the top element of stack
public T peek() {
if (this.top==-1) {
throw new NoSuchElementException("Empty
stack!");
}
else {
return this.stack[this.top];
}
}
// remove and return the top element of stack
public T pop() {
if (this.top==-1) {
throw new
NoSuchElementException("Empty stack!");
}
else {
return
this.stack[this.top--];
}
}
// you can convert the method to void type because
there is no need to return anything for the method
// insert s at top of stack
public void push(T s) {
if (this.top>=this.size-1)
{
throw new
IllegalStateException("Stack is full!");
}
this.stack[++this.top]= s;
// return
this.stack.toString();
}
public int search(String s) {
int dist = 0;
int top = this.top;
while(top>=0) {
if(this.stack[top]==s) {
return dist;
}
dist++;
top--;
}
return -1;
}
public static void main(String[] args) {
// If any of these lines cause a
compilation error, your stack hasn't
// been properly made
generic.
GenericStack<Integer>
intStack = new GenericStack<>();
GenericStack<String>
stringStack = new GenericStack<>();
GenericStack<ArrayList<String>> listStack = new
GenericStack<>();
}
}
//end of GenericStack.java
// Calculator.java
import java.util.*;
import java.io.*;
import java.math.*;
public class Calculator {
public static void main(String[] args) throws
FileNotFoundException, IOException {
String numbers = "56 3 7 2.0
8.4";
char[] moreNumbers = "1.0 2 3 4 5
0.324".toCharArray();
GenericStack<Number>
stack1 = makeStack(new StringReader(numbers));
System.out.println(evaluate(stack1));
GenericStack<Float> stack2
= new GenericStack<>();
for (String token : numbers.split("
")) {
stack2.push(Float.parseFloat(token));
}
System.out.println(evaluate(stack2));
// Uncomment the below lines so
that it works for the file
/*
GenericStack<Number> stack3 =
makeStack(new FileReader("numbers.txt"));
System.out.println(evaluate(stack3));
*/
GenericStack<Number>
stack4 = makeStack(new CharArrayReader(moreNumbers));
System.out.println(evaluate(stack4));
}
/* This function is meant to take in a Reader called
"reader" and return a
* stack of Numbers.
*
* Remember: don't change anything that's already
there. Just add your new
* code where the comment is to fix the function's
signature.
*/
public static GenericStack<Number>
makeStack(Reader reader) throws IOException {
GenericStack<Number> stack =
new GenericStack<>(64);
char[] data = new char[64];
reader.read(data);
String tokens = new
String(data);
for (String token : tokens.split("
")) {
stack.push(parse(token));
}
return stack;
}
/* This function is meant to take in a stack of ANY
KIND of Number
* called "stack", and return the double you get if you
add all of the
* numbers together.
* The function must be able to accept a stack of ANY
KIND of Number!
*
* Hint: use wildcard generics!
*/
public static double evaluate(GenericStack<?
extends Number> stack) {
double sum = 0; // set sum to
0
// loop over the stack, adding the
numbers together
while(!stack.empty())
{
sum +=
((Number)stack.pop()).doubleValue(); // remove and return the top
element of the stack, convert it to double and add it to sum
}
return sum;
}
/* This function is missing a return type.
* Examine it, and see if you can tell what type it
should return.
* (Spoiler: it's probably what you think it is.)
*/
public static Number parse(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
}
try {
return Double.parseDouble(s);
} catch (NumberFormatException e) {
}
return new BigDecimal(s);
}
}
//end of Calculator.java
Output: