I have a static ArrayList (masterLog) that is in my main driver class. The ArrayList contains Event objects, the Event object has an ArrayList (heats) as a global variable. the heat object as an ArrayList (racers) as a global variable. Now when I have the following line of code:
System.out.println(ChronoTimer1009System.getMasterLog().get(0).getHeats().get(getCurHeat()).getRacers().toString());
this returns [] even though the getRacers() IS NOT empty!
When I call this:
System.out.println(getHeats().get(getCurHeat()).getRacers());
this returns the proper filled array.
I think I need to sync the masterLog ArrayList but I am unsure how. I have tried syncing it the way other threads on Stack Exchange have recommended but no luck.
it seems like the static ArrayList masterLog is updated two levels deep but not three levels deep if that makes sense.
What am I doing wrong?
UPDATE:
Maybe this will help explain:
In my main (driver) class, I have a static ArrayList called masterLog. The purpose of this ArrayLIst is to store instances of Event objects for later data retrieval. Now, without making it too complicated, the Event class contains an ArrayList called heats, and the Heat class contains an ArrayList called racers. When I access the masterLog ArrayList at some point in the program (when the other ArrayLists are populated with data), say for example by the call "masterLog.getHeats().get(0).getRacers()", the masterLog does not find any data in the racers ArrayList. It does, however, find data in the heats ArrayList. In other words, the object instance that is stored in the masterLog only updates information to a depth of 2 (not 3 if that makes sense).
UPDATE:
Here is some code:
ChronoTimer1009System class (driver)
package main;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;
public class ChronoTimer1009System {
private Event curEvent;
private static Channel[] channels = new Channel[8];
private boolean state;
private static Stack<Log> log;
private static ArrayList<Event> masterLog;
private static Printer p;
public static Time globalTime;
private int oldLogSize; //used only in this.export()
public ChronoTimer1009System() throws UserErrorException{
for(int i=0; i<channels.length; ++i){channels[i] = new Channel(SensorType.NONE);} // initialize channels
masterLog = new ArrayList<Event>(); //this holds references to each event
this.newEvent(EventType.IND);
this.state = false; //system is initally off
log = new Stack<Log>();
p = new Printer();
globalTime = null;
oldLogSize = 0;
}
public void newEvent(EventType e) throws UserErrorException {
switch(e){
case IND: this.curEvent = new IND();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case PARIND: this.curEvent = new PARIND();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case GRP: this.curEvent = new GRP();ChronoTimer1009System.masterLog.add(this.curEvent);break;
case PARGRP: this.curEvent = new PARGRP();ChronoTimer1009System.masterLog.add(this.curEvent);break;
}
for(Channel x : channels){if(x.getState()) x.toggleState();}
}
public void on() throws UserErrorException{
if(state) throw new IllegalStateException();
this.curEvent = new IND();
ChronoTimer1009System.globalTime = new Time(0);
state = true;
}
public void reset() throws UserErrorException{
if(state) state = false;
on();
}
public void exit(){
this.curEvent = null;
ChronoTimer1009System.globalTime = null;
if(!state) throw new IllegalStateException();
state = false;
}
public static Time searchElapsedByID(int idNum){
Time toReturn = null;
for(Log item : log){
if(item.getCompetitorNumber() == idNum){
toReturn = item.getElapsedTime(); break;
}
}
return toReturn;
}
/**
* #return the curEvent
*/
public Event getCurEvent() {
return curEvent;
}
/**
* #return the state
*/
public boolean isState() {
return state;
}
public static Channel getChan(int chan){
if(chan < 1 || chan > 8) throw new IllegalArgumentException("Argument is not in range");
return channels[chan-1];
}
public static void export(){
//*****FORMAT JSON*****
//before formating, a sort of the runners within each heat is needed to determine place.
String toJson = "{\"events\":[";
System.out.println(ChronoTimer1009System.getMasterLog().get(0).getHeats().get(0).getRacers().size());
//iterate through each event
for(int i = 0; i < ChronoTimer1009System.getMasterLog().size(); ++i){
//iterate through each heat of each event
toJson += "{\"name\":\"" + ChronoTimer1009System.getMasterLog().get(i).getType().toString() + "\",\"heats\":[";
for(int j = 0; j < ChronoTimer1009System.getMasterLog().get(i).getHeats().size(); ++j){
//iterate through each competitor in each heat
toJson += "{\"runners\":[";
System.out.println(ChronoTimer1009System.getMasterLog().get(i).getHeats().size());
ArrayList<Competitor> x = sortByPlace(ChronoTimer1009System.getMasterLog().get(i).getHeats().get(j).getRacers()); <----- on this line, the getRacers() part has a size of zero when it isn't empty.
for(int k = 0; k < x.size(); ++k){
//notice we are working with a sorted copy
//TODO make Competitor endTime the elapsed time
toJson += "{\"place\":\"" + String.valueOf(k+1) + "\",\"compNum\":\"" + x.get(k).getIdNum() + "\", \"elapsed\":\"" + x.get(k).getEndTime().toString() + "\"},";
}
toJson += "]},";
}
toJson += "]},";
}
toJson += "}";
System.out.println(toJson);
/*try{
URL site = new URL("http://7-dot-eastern-cosmos-92417.appspot.com/chronoserver");
HttpURLConnection conn = (HttpURLConnection) site.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
String data = "data=" + toJson;
out.writeBytes(data);
out.flush();
out.close();
System.out.println("Done sent to server");
new InputStreamReader(conn.getInputStream());
}
catch (Exception e)
{
e.printStackTrace();
}*/
}
private static ArrayList<Competitor> sortByPlace(ArrayList<Competitor> unsorted)
{
ArrayList<Competitor> whole = (ArrayList<Competitor>) unsorted.clone();
ArrayList<Competitor> left = new ArrayList<Competitor>();
ArrayList<Competitor> right = new ArrayList<Competitor>();
int center;
if(whole.size()==1)
return whole;
else
{
center = whole.size()/2;
// copy the left half of whole into the left.
for(int i=0; i<center; i++)
{
left.add(whole.get(i));
}
//copy the right half of whole into the new arraylist.
for(int i=center; i<whole.size(); i++)
{
right.add(whole.get(i));
}
// Sort the left and right halves of the arraylist.
left = sortByPlace(left);
right = sortByPlace(right);
// Merge the results back together.
merge(left,right,whole);
}
return whole;
}
private static void merge(ArrayList<Competitor> left, ArrayList<Competitor> right, ArrayList<Competitor> whole) {
int leftIndex = 0;
int rightIndex = 0;
int wholeIndex = 0;
// As long as neither the left nor the right arraylist has
// been used up, keep taking the smaller of left.get(leftIndex)
// or right.get(rightIndex) and adding it at both.get(bothIndex).
while (leftIndex < left.size() && rightIndex < right.size())
{
if ((left.get(leftIndex).getEndTime().compareTo(right.get(rightIndex)))<0)
{
whole.set(wholeIndex,left.get(leftIndex));
leftIndex++;
}
else
{
whole.set(wholeIndex, right.get(rightIndex));
rightIndex++;
}
wholeIndex++;
}
ArrayList<Competitor>rest;
int restIndex;
if (leftIndex >= left.size()) {
// The left arraylist has been use up...
rest = right;
restIndex = rightIndex;
}
else {
// The right arraylist has been used up...
rest = left;
restIndex = leftIndex;
}
// Copy the rest of whichever arraylist (left or right) was
// not used up.
for (int i=restIndex; i<rest.size(); i++) {
whole.set(wholeIndex, rest.get(i));
wholeIndex++;
}
}
/**
* #return the log
*/
public static Stack<Log> getLog() {
return log;
}
/**
* #return the masterLog
*/
public static ArrayList<Event> getMasterLog() {
return masterLog;
}
/**
* #return the p
*/
public static Printer getPrinter() {
return p;
}
}
Event Class:
package main;
import java.util.ArrayList;
public abstract class Event extends Display{
private ArrayList<Heat> heats;
private int curHeat; //private means only this class can modify, not the subclasses
private Competitor curComp;
private String name;
public Event(String name) throws UserErrorException{
this.name = name;
heats = new ArrayList<Heat>();
curHeat = -1;
curComp = null;
createRun();
}
/**
* This method will be used by all EventTypes and will not change
* regardless of the EventType.
* #throws UserErrorException
*/
public void createRun() throws UserErrorException{
heats.add(new Heat()); ++curHeat;
}
/**
* #return the heats
*/
public ArrayList<Heat> getHeats() {
return heats;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #return the currentHeat
*/
public int getCurHeat() {
return curHeat;
}
/**
* #return the curComp
*/
public Competitor getCurComp() {
return curComp;
}
/**
* #param curComp the curComp to set
*/
public void setCurComp(Competitor curComp) {
this.curComp = curComp;
}
/* (non-Javadoc)
* #see Display#displayHeatNumber()
*/
#Override
public String displayHeatNumber() {
// TODO Auto-generated method stub
return "Heat: " + (curHeat+1);
}
/* (non-Javadoc)
* #see Display#displayFinished()
*/
#Override
public String displayFinished() {
String toReturn = "";
boolean noRunners = true;
for(Competitor x : getHeats().get(getCurHeat()).getRacers()){
if(x.getEndTime() != null){
toReturn += "\n" + x.getIdNum() + " " + (ChronoTimer1009System.searchElapsedByID(x.getIdNum()).equals(new Time(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE)) ? "DNF" : ChronoTimer1009System.searchElapsedByID(x.getIdNum()).toString() + " F");
noRunners = false;
}
}
if(noRunners){toReturn = "no runners have finished";}
return toReturn;
}
public abstract void endRun() throws UserErrorException;
public abstract void trigChan(int chan, boolean dnf) throws UserErrorException;
public abstract void cancel(int ln) throws UserErrorException;
public abstract EventType getType();
}
Heat class:
package main;
import java.util.ArrayList;
public class Heat {
private ArrayList<Competitor> racers;
//private ArrayList<Competitor> racers;
private int currentCompetitor;
/**
* Constructor
*/
public Heat(){
racers = new ArrayList<Competitor>();
//racers = new ArrayList<Competitor>();
currentCompetitor = 0;
}
/**
* Set selected racer as next on to start
* #param racer the racer to start next
*/
public void setNextCompetitor(Competitor x){
int pos = racers.indexOf(x);
if(pos == -1 || pos<currentCompetitor) throw new IllegalArgumentException("Competitor not in the race! Please add first");
for(int i = pos; i>currentCompetitor; --i){
racers.set(i, racers.get(i-1));
}
racers.set(currentCompetitor, x);
}
/**
* Take the selected runner (the next runner) out from the race
* #param racer the runner to be cleared
*/
public void clearNextCompetitor() throws UserErrorException {
if(racers.size()-(currentCompetitor)<1) throw new UserErrorException("No runners to clear!");
for(int i = currentCompetitor+1; i<racers.size(); ++i){
racers.set(i-1, racers.get(i));
}
racers.remove(racers.size()-1);
}
/**
* basically a remove method
* #param x
*/
public void remove(Competitor x){
int pos = racers.indexOf(x);
if(pos < 0) throw new IllegalArgumentException("runner does not exists");
racers.remove(pos);
}
/**
* Swaps two runners positions in line
*/
public void swap() throws UserErrorException{
int count = 0;
for(Competitor x : racers){
if(x.getStartTime() == null) ++count;
}
if(count > 1 && currentCompetitor + 1 <= racers.size()){
Competitor first = racers.get(currentCompetitor);
Competitor second = racers.get(currentCompetitor+1);
racers.set(currentCompetitor, second);
racers.set(currentCompetitor+1, first);
}
else{
throw new UserErrorException("Not enough competitors to swap");
}
}
/**
* Add a competitor to the end of the current line of competitors if any
* #param x the competitor to add
*/
public boolean addCompetitor(Competitor x) throws UserErrorException{
if(x.getIdNum() < 0 || x.getIdNum() > 99999) throw new UserErrorException("ID number out of range");
if(x.getRunNum() < 0) throw new IllegalArgumentException("Run Num Out of range");
boolean add = true;
for(Competitor i : racers){
if(i.getIdNum() == x.getIdNum()){
add = false;
break;
}
}
if(add){
racers.add(x);
}
return add;
}
/**
* Retrieve the next competitor if there is one
* #return the next competitor
*/
public Competitor getNextCompetitor() throws UserErrorException{
if(!hasNextCompetitor()) throw new UserErrorException("There are no more competitors!");
while(racers.get(currentCompetitor).isCompeting()){++currentCompetitor;}
return racers.get(currentCompetitor++);
}
/**
* used to fix the order of the queue after cancel is called
*/
public void fix(EventType x){
switch(x){
case IND:
--currentCompetitor;
break;
case GRP: case PARGRP: case PARIND:
for(int i = 0; i<racers.size(); ++i){
if(racers.get(i).getStartTime() == null){
currentCompetitor = i;
break;
}
}
break;
}
}
/**
* Is there another competitor to go?
* #return whether or not there is another competitor to go.
*/
public boolean hasNextCompetitor(){
return currentCompetitor < racers.size();
}
/**
* Return a 1D array view of the competitors
* #return
*/
public ArrayList<Competitor> getRacers(){
return racers;
}
}
in the export method of the ChronoTimer1009System class, I point out where the error is and what is happening
Related
My data structures project on dequeues is passing all junit tests except for one. the "removeFrontRemoveRear" test. It keeps returning null instead of the
student name.
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Dequeue <E> {
private int front;
private int rear;
private E[] elements;
private static final int DEFAULT_CAPACITY = 5;
/**
* Constructor sets up an empty double-ended
* queue
*/
#SuppressWarnings("unchecked")
public Dequeue() {
elements = (E[]) new Object[DEFAULT_CAPACITY];
front = 0;
rear = elements.length - 1;
}
/**
* Inserts item at the front of the dequeue. Throws
* an exception if the item could not be inserted
* #param anEntry the item to be added (Student)
* #return true
*/
public boolean addFront(E anEntry) {
if (empty()) {
front = rear = 0;
elements[front] = anEntry;
}
else if (isFull()) {
reallocate();
front = (front + (elements.length - 1)) % elements.length;
}
else {
front = (front + (elements.length - 1)) % elements.length;
}
elements[front] = anEntry;
return true;
}
/**
* private method to check if the dequeue is full
* #return true only if dequeue is full (has
* 1 empty spot)
*/
private boolean isFull() {
if (size() == elements.length -1) {
return true;
}
return false;
}
/**
*Doubles and adds 1 to the size of the dequeue
*then reallocates the data.
*/
#SuppressWarnings("unchecked")
private void reallocate() {
E[] newData = (E[]) new Object[size() * 2 + 1];
int indexOfFront = front;
for(int i = 0; i < size(); i++) {
newData[i] = elements[indexOfFront];
indexOfFront = (indexOfFront + 1) % elements.length;
}
rear = size() - 1;
front = 0;
elements = newData;
}
/**
* Inserts item at the rear of the dequeue.
* Throws an exception if the item could not be inserted
* #param anEntry the entry being inserted into the end of the queue
* #return true
*/
public boolean addRear(E anEntry) {
if (empty()) {
front = rear = 0;
elements[rear] = anEntry;
}
else if (isFull()) {
reallocate();
rear = (rear + 1) % elements.length;
}
else {
rear = (rear + 1) % elements.length;
}
elements[rear] = anEntry;
return true;
}
/**
* This method checks if the dequeue is empty
* #return true if the dequeue is empty. otherwise
* returns false
*/
public boolean empty() {
if (front == 0 && rear == elements.length-1) {
return true;
}
return false;
}
/**
* #return the dequeue's iterator
*/
public Iterator<E> iterator() {
return new dequeueIterator();
}
/**
* implementation of Iterator interface
* with inner class
*/
private class dequeueIterator implements Iterator<E> {
private int index;
private int count = 0;
/**
* references the front dequeue element
* and initializes the dequeueIterator object
*/
public dequeueIterator(){
index = front;
}
/**
*#return true it there are additional
* elements in the dequeue
*/
#Override
public boolean hasNext() {
return count < size();
}
/**
* #return the next element in the queue
*/
#Override
public E next() {
if(!hasNext()) {
throw new NoSuchElementException();
}
E returnValue = elements[index];
index = (index + 1) % elements.length;
count++;
return returnValue;
}
/**
* removes the elements accessed by the
* iterator object
*/
#Override
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* //Returns the entry at the front of the
* dequeue without removing it; returns
* NoSuchElementException if the dequeue
* is empty
* #return the object at the front of dequeue
*/
public E peekFront() {
if (empty())
throw new NoSuchElementException();
else
return elements[front];
}
/**
* returns the item at the rear of the dequeue, throws
* NoSuchElementException if empty.
* #return the element in the rear
*/
public E peekRear() {
if (empty())
throw new NoSuchElementException();
else
return elements[rear];
}
/**
*Removes the entry at the front of the dequeue and
*returns it if the dequeue is not empty. If the
*dequeue is empty, throws a NoSuchElementException
* #return front element before removing it
*/
public E removeFront() {
if (empty())
throw new NoSuchElementException();
E temp = elements[front];
elements[front] = null;
front = (front++) % elements.length;
return temp;
}
/**
* Removes the entry at the rear of the dequeue and
*returns it if the dequeue is not empty. If the
*dequeue is empty, throws a NoSuchElementException
* #return rear element before removing it
*/
public E removeRear() {
if (empty())
throw new NoSuchElementException();
E temp = elements[rear];
elements[rear] = null;
rear = (rear + elements.length - 1) % elements.length;
return temp;
}
/**
* Gets the amount of elements in the dequeue
* #return the number of elements in the dequeue
*/
public int size() {
int count = 0;
int indexOfFront = front;
int nextRearPosition = (rear + 1) % elements.length;
while(indexOfFront != nextRearPosition) {
count++;
indexOfFront = (indexOfFront + 1) % elements.length;
}
return count;
}
}
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.NoSuchElementException;
public class DequeueTest {
Dequeue<Student> q;
Student s1, s2, s3, s4, s5, s6, s7, s8;
#BeforeEach
public void setUp() throws Exception {
q = new Dequeue<Student> ();
s1 = new Student("John", "Doe");
s2 = new Student ("Jane", "Smith");
s3 = new Student ("Bob", "Taylor");
s4 = new Student ("Anne", "Frank");
s5 = new Student("Frank", "Gauvin");
s6 = new Student("Kevin", "Austin");
s7 = new Student ("Cindy", "Bryant");
s8 = new Student ("Peter", "Lander");
}
#Test
public void testaddFrontAddRear() {
q.addFront(s1);
q.addFront(s2);
q.addFront(s3);
assertThat(q.peekFront(), is(s3)); // assertEquals(s3, q.peekFront());
q.addRear(s4);
q.addRear(s5);
q.addFront(s6);
q.addRear(s7);
assertThat(q.peekRear(), is(s7)); // assertEquals(s7, q.peekRear());
assertThat(q.size(), is(7)); // assertEquals(7, q.size());
}
#Test
public void testRemoveFrontRemoveRear() {
q.addFront(s1);
q.addFront(s2);
q.addFront(s3);
q.addRear(s4);
q.addRear(s5);
q.addFront(s6);
q.addRear(s7);
assertThat(q.removeFront(), is(s6)); // assertEquals(s6, q.removeFront());
assertThat(q.removeRear(), is(s7)); // assertEquals(s7, q.removeRear());
assertThat(q.removeFront(), is(s3)); // assertEquals(s3, q.removeFront() );
assertThat(q.size(), is(4)); // assertEquals(4, q.size());
assertThat(q.removeRear(), is(s5)); // assertEquals(s5, q.removeRear());
assertThat(q.removeFront(), is(s2)); // assertEquals(s2, q.removeFront());
assertThat(q.size(), is(2)); // assertEquals(2, q.size());
assertThat(q.removeFront(), is(s1)); // assertEquals(s1, q.removeFront());
assertThat(q.removeRear(), is(s4)); // assertEquals(s4, q.removeRear());
assertTrue(q.empty());
assertTrue(q.size() == 0);
}
#Test
public void testIterator() {
q.addFront(s1);
q.addFront(s2);
q.addFront(s3);
q.addRear(s4);
assertEquals(4, q.size() );
q.addRear(s5);
q.addFront(s6);
q.addRear(s7);
assertEquals(7, q.size() );
Iterator <Student> iter = q.iterator();
ArrayList<Student> list = new ArrayList<Student>();
while (iter.hasNext()) {
list.add(iter.next() );
}
assertThat(list.get(0), is(s6)); // assertEquals(s6, list.get(0));
assertThat(list.get(1), is(s3)); // assertEquals(s3, list.get(1));
assertThat(list.get(2), is(s2)); // assertEquals(s2, list.get(2));
assertThat(list.get(3), is(s1)); // assertEquals(s1, list.get(3));
assertThat(list.get(4), is(s4)); // assertEquals(s4, list.get(4));
assertThat(list.get(5), is(s5)); // assertEquals(s5, list.get(5));
assertThat(list.get(6), is(s7)); // assertEquals(s7, list.get(6));
}
#Test
public void testPeekFrontOnEmptyQueue() throws NoSuchElementException {
assertThrows(NoSuchElementException.class, () ->
{Dequeue<Student> q = new Dequeue<Student>();
q.peekFront();});
}
#Test
public void testRearFrontOnEmptyQueue() throws NoSuchElementException{
assertThrows(NoSuchElementException.class, () ->
{Dequeue<Student> q = new Dequeue<Student>();
q.peekRear();});
}
#Test
public void testRemoveFrontOnEmptyQueue() throws NoSuchElementException {
assertThrows(NoSuchElementException.class, () ->
{Dequeue<Student> q = new Dequeue<Student>();
q.removeFront();});
}
#Test
public void testRemoveRearOnEmptyQueue() throws NoSuchElementException
{
assertThrows(NoSuchElementException.class, () ->
{Dequeue<Student> q = new Dequeue<Student>();
q.removeRear();});
}
}
/** Abstraction of a Student entity */
public class Student implements Comparable <Student> {
private String firstName;
private String lastName;
/** Initialize a Student
#param first firstName
#param last lastName
*/
public Student(String first, String last) {
firstName = first;
lastName = last;
}
/** Mutator Method
#param aName firstName
*/
public void setFirstName(String aName) {
firstName = aName;
}
/** Accessor Method
#return firstName of this Student
*/
public String getFirstName() {
return firstName;
}
/** Mutator Method
#param aName lastName
*/
public void setLastName(String aName) {
lastName = aName;
}
/** Accessor Method
#return lastName of this Student
*/
public String getLastName() {
return lastName;
}
#Override
public String toString() {
String str = "";
str += (lastName + "," + firstName);
return str;
}
/* this version overloads the equals method (note the
signature of this method).
*/
public boolean equals(Student s) {
return ( (this.lastName.equalsIgnoreCase(s.lastName)) &&
(this.firstName.equalsIgnoreCase(s.firstName)));
}
/* We need to override this method so indexOf and
contains methods work. Both of them use this version
equals method
*/
#Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (!(obj instanceof Student)) return false;
else {
Student s = (Student) obj;
return ( this.equals(s)); // calls the
equals(Student) method
}
}
/**
#return
a negative integer if "s1 < s2"; 0 if "s1 == s2"
a positive integer if "s1 > s2"
*/
#Override
public int compareTo(Student s) {
int result = lastName.compareToIgnoreCase(s.lastName);
if (result != 0) return result;
else
return (firstName.compareToIgnoreCase(s.firstName));
}
}
The expected result is but the actual result was null.
I am not sure what to try. I am drawing a blank. The error is brought forth in line 55 of dequeueTest.
I want my program print all the entries in HashMap, and it does if I run the app in debugger. But if I run it normaly it prints only the last entry :(
Have no idea why it does,
Please help me.
MoneyCounter:
package home.lib;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import home.interfaces.GoodsOper;
import home.interfaces.WalletOper;
import home.interfaces.WastesListOper;
public class MoneyCounter implements WastesListOper, WalletOper, GoodsOper {
private ArrayList<String> wastesPrint = new ArrayList<>();
private Map<GregorianCalendar, Good> wastesMap = new HashMap<GregorianCalendar, Good>();
private Map<String, Good> goodsMap = new HashMap<String, Good>();
private Map<String, Wallet> walletsMap = new HashMap<String, Wallet>();
private Wallet currentWallet;
private Good currentGood;
private SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-YYYY");
/**
* Provides selling (returning) of specified good puts the good
* to the wastesMap by date
* #param goodName
*/
#Override
public void sell(String goodName) {
// TODO implement the summation of wastes
if(goodsMap.containsKey(goodName)){
putMoney(goodsMap.get(goodName).getPrice());
wastesMap.put(new GregorianCalendar(), goodsMap.get(goodName));
}
}
/**
* Provides buying specified good puts the good you've bought
* to the wastesMap by date
* #param goodName
*/
#Override
public void buy(String goodName) {
// TODO implement the summation of wastes
if(goodsMap.containsKey(goodName)){
takeMoney(goodsMap.get(goodName).getPrice());
wastesMap.put(new GregorianCalendar(), goodsMap.get(goodName));
}
}
/**
* Add a new Wallet to the list if there is no the same one
* #param name
* #param currency
*/
#Override
public void createWallet(String name, String currency) {
walletsMap.putIfAbsent(name, new Wallet(name, currency));
}
/**
* Adds a new Good to the list with specified price
* #param name
* #param price
*/
#Override
public void createGood(String name, int price) {
goodsMap.putIfAbsent(name, new Good(name, price));
}
/**
* Returns array of strings with goods specifications, which
* satisfies the interval [startPrice, endPrice]
* #param startPrice
* #param endPrice
* #return array of strings String[]
*/
#Override
public String[] goodsListToStringByPrice(int startPrice, int endPrice) {
String[] goods = new String[goodsMap.size()];
int i = 0;
for (Map.Entry<String, Good> e : goodsMap.entrySet()) {
if (e.getValue().getPrice() >= startPrice && e.getValue().getPrice() <= endPrice) {
goods[i++] = e.getValue().goodToString();
}
}
return goods;
}
/**
* Returns an array of Strings with goods descriptions
* #return array of strings String[]
*/
#Override
public String[] goodsListToString() {
String[] goods = new String[goodsMap.size()];
int i = 0;
for (Map.Entry<String, Good> e : goodsMap.entrySet()) {
goods[i++] = e.getValue().goodToString();
}
return goods;
}
/**
* Replaces old Wallet's name with new one specified if one's name is absent
* #param oldName
* #param newName
*/
public void changeWalletName(String oldName, String newName) {
walletsMap.putIfAbsent(newName, new Wallet(newName, walletsMap.get(oldName)));
walletsMap.remove(oldName);
}
/**
* Returns an array of Strings with wallet descriptions
* #return array of strings String[]
*/
public String[] walletListToString() {
String[] wallets = new String[walletsMap.size()];
int i = 0;
for (Map.Entry<String, Wallet> e : walletsMap.entrySet()) {
wallets[i++] = e.getValue().walletToString();
}
return wallets;
}
/**
* Returns the wallet's money balance by name
* #param walletName
* #return String
*/
public String checkWallet(String walletName) {
return walletsMap.get(walletName).walletToString();
}
/**
* Deletes the wallet, specified by name from wallet list
* #param walletName
*/
#Override
public void delWallet(String walletName) {
walletsMap.remove(walletName);
}
/**
* Deletes the good, specified by name from good list
* #param goodName
*/
#Override
public void delGood(String goodName) {
goodsMap.remove(goodName);
}
/**
* Use this method to put more money to the wallet
* got payment for example
* #param count
*/
#Override
public void putMoney(int count) {
currentWallet.addMoney(count);
}
/**
* Use this method if you need money but not for buying a good
* #param count
*/
#Override
public void takeMoney(int count) {
currentWallet.getMoney(count);
}
/**
* Returns list of all wallets
* #return ArrayList
*/
#Override
public ArrayList<String> walletsListToString() {
ArrayList<String> array = new ArrayList<>();
for (Map.Entry<String, Wallet> entry : walletsMap.entrySet()) {
array.add(entry.getValue().walletToString());
}
return array;
}
/**
* Returns list of wallets specified by currency
* #param currency
* #return ArrayList
*/
#Override
public ArrayList<String> walletsListToStringByCurrency(String currency) {
ArrayList<String> array = new ArrayList<>();
for (Map.Entry<String, Wallet> entry : walletsMap.entrySet()) {
if (entry.getValue().getCurrency().equals(currency)) {
array.add(entry.getValue().walletToString());
}
}
return array;
}
/**
* Chooses wallet to operate with when you bus, sell, etc.
* #param walletName
*/
#Override
public void chooseTheWallet(String walletName) {
if (walletsMap.containsKey(walletName)) {
this.currentWallet = walletsMap.get(walletName);
}
}
/**
* Returns list of strings of all money wastes you've ever done
* #return ArrayList wastesPrint
*/
#Override
public void wastesListFillUp() {
for(Map.Entry<GregorianCalendar, Good> entry:wastesMap.entrySet()){
this.wastesPrint.add(dateFormat.format(entry.getKey().getTime())+" "+entry.getValue().goodToString()+
" "+currentWallet.walletToString());
}
}
/**
* Is used for tests
* #throws IOException
*/
public void printAllList() throws IOException {
for (Map.Entry<GregorianCalendar, Good> entry : wastesMap.entrySet()) {
System.out.println(dateFormat.format(entry.getKey().getTime())+" "+entry.getValue().goodToString()+
" "+currentWallet.walletToString());
}
}
/**
* Changes the specified good's price
* #param price
*/
#Override
public void changePrice(int price) {
currentGood.changePrice(price);
}
/**
* Chooses the good for operations
* #param goodName
*/
#Override
public void chooseTheGood(String goodName) {
if (goodsMap.containsKey(goodName)) {
this.currentGood = goodsMap.get(goodName);
}
}
}
Main:
package home.main;
import java.io.IOException;
import home.lib.MoneyCounter;
public class Main {
public static void main(String[] args) throws IOException {
MoneyCounter application = new MoneyCounter();
application.createGood("Snikers", 850);
application.createGood("Хрень какая-то", 1000);
application.createWallet("Основоной счет", "UAH");
application.chooseTheWallet("Основоной счет");
application.buy("Snikers");
application.buy("Хрень какая-то");
application.printAllList();
}
}
Wallet:
package home.lib;
public class Wallet {
// all money is kept
private int moneyCount;
private int debt;
private String currency;
private String name;
// constructor for new Wallet
public Wallet(String walletName, String currencyName) {
this.currency = currencyName;
this.moneyCount = 0;
this.debt = 0;
this.name = walletName;
}
// for renaming Wallet in WalletList
public Wallet(String walletName, Wallet oldWallet) {
this.name = walletName;
this.moneyCount = oldWallet.getMoneyCount();
this.debt = oldWallet.getDebt();
this.currency = oldWallet.getCurrency();
}
// actions with money
public void addMoney(int moneyCount) {
if (this.moneyCount >= 0 && this.debt == 0) {
this.moneyCount += moneyCount;
} else {
moneyCount -= this.debt;
this.debt = 0;
this.moneyCount = moneyCount;
}
}
public void getMoney(int moneyCount) {
if (this.debt == 0 && this.moneyCount > 0 && this.moneyCount >= moneyCount) {
this.moneyCount -= moneyCount;
} else {
moneyCount -= this.moneyCount;
this.moneyCount = 0;
this.debt += moneyCount;
}
}
// getters/setters block
public int getMoneyCount() {
return this.moneyCount;
}
public int getDebt() {
return this.debt;
}
public String getName() {
return this.name;
}
public String getCurrency() {
return this.currency;
}
public String walletToString() {
return this.debt <= 0 ? "("+this.name + " Остаток: " + (double)this.moneyCount/100 + " " + this.currency+")"
: "("+this.name + " Долг: -" + (double)this.debt/100 + " " + this.currency+")";
}
}
Good:
package home.lib;
public class Good {
private int price;
private String name;
public Good(String goodName, int goodPrice) {
this.name = goodName;
this.price = goodPrice;
}
public int getPrice() {
return this.price;
}
public double getPriceInDouble() {
return (double)this.price / 100;
}
public void changePrice(int price) {
this.price = price;
}
public String getName() {
return this.name;
}
public String goodToString() {
return "Товар: " + this.name + " | Цена: " + (double) this.price / 100;
}
}
I've got an answer. I used GregorainCalendar as a HashMap key. So, when I was starting program normaly, it was done in no time. So it was adding different values for ONE key. When you run the program in debugger you can't press next step 10 times in one moment so the time is different, so the keys are different too, so it returns all entries.
Be attentive when use time and all will be Ok :)
I have written a program which will show whether a word can be transformed into another by changing a single character at a time, while the intermediate words are also valid words.
For e.g CAT->COT -> DOT-> DOC
The program works when I use LinkedHashSet to represent the vertices
but it goes into an infinite loop or wrong answer when I use HashSet.
I would like to know what is the problem and if there is a better way to solve the problem then please tell me.
Here is the code: Split into 3 files:
Graph.java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
public class Graph {
private Set<GraphNode> vertices;
public Graph() {
//the code runs when I use LinkedHashSet
vertices = new LinkedHashSet<>();
//the code goes into infinite loop or wrong answer when I use HashSet to represent the vertices
//************
//vertices = new HashSet<>();
//*************
//^^^^^ strange behaviour
}
/**
* adds all the words from the given dictonary to the graph
* #param dictonary
* #return
*/
public boolean addAll(Set<String> dictonary){
boolean result= false;
for (String word : dictonary){
addNode(word);
}
return result;
}
/**
* add a single node into the graph
* #param data
* #return
*/
public GraphNode addNode(String data){
GraphNode node = new GraphNode();
node.setValue(data);
vertices.add(node);
return node;
}
/**
* add a neighbour to the "source" node
* #param source
* #param neighbour
* #return
*/
public boolean addNeighbour(GraphNode source, GraphNode neighbour) {
boolean result = false;
source.getNeighbours().add(neighbour);
return result;
}
/**
* This method assigns the neighbours of nodes depending on whether they are one edit
* away or not
*/
public void assignNeighbours(){
ArrayList<GraphNode> listOfNodes = getAllVertices();
Set<String> usedWords = new HashSet<>();
for ( int i=0 ;i <listOfNodes.size() ;i++){
String currentWord = listOfNodes.get(i).value;
for (int j=0 ; j < listOfNodes.size() ;j++ ){
if (currentWord.equals(listOfNodes.get(j).value)==false){
if (oneEditAway(currentWord, listOfNodes.get(j).value) && usedWords.contains(listOfNodes.get(j).value)==false){
listOfNodes.get(i).neighbours.add(listOfNodes.get(j));
//reflective
listOfNodes.get(j).neighbours.add(listOfNodes.get(i));
usedWords.add(listOfNodes.get(j).value);
}
}
}
}
}
public ArrayList<GraphNode> getAllVertices(){
return new ArrayList<>(vertices);
}
/**
* This method determines whether 2 strings are one edit away or not
* #param first
* #param second
* #return
*/
public boolean oneEditAway(String first, String second) {
// TODO Auto-generated method stub
if (first == null || second == null)
return false;
if (Math.abs(first.length() - second.length())>1){
return false;
}else{
int firstLength = first.length();
int secondLength = second.length();
int mismatchCount = 0;
for (int i=0 ;i < firstLength && i < secondLength ; ++i){
if (first.charAt(i) != second.charAt(i)){
mismatchCount++;
}
}
if (mismatchCount > 1 || Math.abs(firstLength - secondLength) == 1){
return false;
}
return true;
}
}
/**
* This method prints the graph and the connections
*/
public void printGraph() {
// TODO Auto-generated method stub
for (GraphNode node :vertices){
System.out.println("Node is :"+node.value);
System.out.println("Neighbours are :");
for (GraphNode graphNode : node.getNeighbours()){
System.out.print(graphNode.value+ " ");
}
System.out.println();
}
}
/**
* This function determines whether a word can be transformed into an another or not
* #param source
* #param dest
* #return
*/
public boolean canTransform(String source, String dest) {
boolean result = false;
Set<GraphNode> visited = new HashSet<>();
//BFS is the way to go
Queue<GraphNode> allNodes = new LinkedList<>();
GraphNode root=null;
//find the source node in the graph
for (GraphNode node : vertices){
if (node.value.equals(source)){
root = node;
}
}
allNodes.add(root);
System.out.println("***************");
while(!allNodes.isEmpty()){
GraphNode currentNode = allNodes.poll();
System.out.println(currentNode.value);
visited.add(currentNode);
if (currentNode.value.equals(dest)){
result = true;
break;
}
for (GraphNode node: currentNode.getNeighbours()){
if (visited.contains(node) == false){
allNodes.add(node);
}
}
}
return result;
}
#Override
public String toString() {
return "Graph is as follows :\nvertices=" + vertices + "";
}
public Set<GraphNode> getVertices() {
return vertices;
}
public void setVertices(Set<GraphNode> vertices) {
this.vertices = vertices;
}
}
Here is the GraphNode.java
import java.util.HashSet;
import java.util.Set;
public class GraphNode {
String value;
Set<GraphNode> neighbours = new HashSet<GraphNode>();
public GraphNode() {
// TODO Auto-generated constructor stub
}
public GraphNode(String value) {
super();
this.value = value;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
GraphNode other = (GraphNode) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
#Override
public String toString() {
return "GraphNode [value=" + value + ", neighbours=" + neighbours + "]";
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Set<GraphNode> getNeighbours() {
return neighbours;
}
public void setNeighbours(Set<GraphNode> neighbours) {
this.neighbours = neighbours;
}
}
Here is the driver class:
import java.util.HashSet;
import java.util.Set;
public class GraphMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
Graph graph = new Graph();
Set<String> dict = new HashSet<>();
dict.add("CAT");
dict.add("COT");
dict.add("DOT");
dict.add("DOG");
dict.add("DOC");
graph.addAll(dict);
graph.assignNeighbours();
graph.printGraph();
String source="CAT",dest = "DOC";
System.out.println("can transform from "+source+" to "+dest+" ??"+graph.canTransform(source,dest));
}
}
The method determining the neighbours of a word is incorrect as the use of the Set usedWords is incorrect. The relation neighbour(w1,w2) must be independent of the order the neighbours are determined, so using some state to decide whether one word is the neighbour of another one cannot be correct.
public void assignNeighbours(){
for ( GraphNode w1: vertices ){
for ( GraphNode w2: vertices ){
if (! w1.equals(w2) ){
if (oneEditAway(w1.getValue(), w2.getValue())){
w1.neighbours.add(w2);
//reflective
w2.neighbours.add(w1);
}
}
}
}
}
We have a memory leak problem, we don't know what/where too many instances of a certain class are created/referred from. This occurs under heavy load in production and we cannot obtain heap dump (taking heap dump hangs the HA server for too long time). Runtime profiling is also not an option on production site because of performance degradation, the customers are happier with a random crash rather than agonizing slow during monitoring trying to fish for the crash instant. We don't know how to initiate the crash (leak), it just occurs at some times.
Is there a way to obtain object referrers/instantiation points at runtime from within the application itself?
I looked at http://docs.oracle.com/javase/6/docs/jdk/api/jpda/jdi/com/sun/jdi/ObjectReference.html and it gives an idea that something like this could be possible.
Any pointers how to achieve this preferrably with custom code without the heap-dump-way? Reproducing the problem in test environment has been tried and it seems exhaustive wild goose-chase. We want now a brute force way to find the cause.
It is recommended that you try to check you code which is causing such leaks. Here are some tutorials and help regarding the same
IBM Article on Handling memory leaks in Java
http://www.ibm.com/developerworks/library/j-leaks/
Some other useful articles
http://www.openlogic.com/wazi/bid/188158/How-to-Fix-Memory-Leaks-in-Java
There is also an Eclipse Memory Analyser Tool
But the most recommended solution will be
Try running jvisualvm from the JVM on the same machine as your program is running and enable profiling.
We solved the issue by collecting stacktraces on instantiation and on clone.. and by dumping them on a scheduler and when memory goes low.
We know the Object class that causes the problem, just needed to hunt down where it is born:
#EntityListeners(AbstractDTOJpaEventListener.class)
#MappedSuperclass
public abstract class AbstractDTO implements Storeable, Serializable, Cloneable {
/** */
private static final String SHADOWED_CLASS = "Custom";
/** */
protected final static boolean DEBUG_CUSTOM_INSTANCES = true;
/** */
public static long TARGET_HITRATE_PER_INTERVAL = 400000;
/** */
public static long LOGGING_INTERVAL = Times.MILLISECONDS_IN_TEN_SECONDS;
/** */
private static long previousLoggingTime;
/** */
protected static int hits;
/** */
protected static boolean hitting;
/** */
protected static int hitsWithinInterval;
/**
* #author Martin
*/
public static class Hi {
/**
*
*/
private long hitted;
private final long createdAt;
private final StackTraceElement[] stackTraceElements;
private final String threadName;
/**
* #param threadName
* #param stackTraceElements
*/
public Hi(String threadName, StackTraceElement[] stackTraceElements) {
this.threadName = threadName;
this.createdAt = System.currentTimeMillis();
this.stackTraceElements = stackTraceElements;
}
/**
*
*/
public void hit() {
hitted++;
}
/**
* #return the hitted
*/
public long getHitted() {
return hitted;
}
/**
* #param hitted the hitted to set
*/
public void setHitted(long hitted) {
this.hitted = hitted;
}
/**
* #return the createdAt
*/
public long getCreatedAt() {
return createdAt;
}
/**
* #return the stackTraceElements
*/
public StackTraceElement[] getStackTraceElements() {
return stackTraceElements;
}
/**
* #return the threadName
*/
public String getThreadName() {
return threadName;
}
}
/** */
protected final static Map<String, Hi> INSTANCE_SHADOW = new ConcurrentHashMap<String, Hi>();
private static final Comparator<? super Entry<String, Hi>> COMPARATOR = new Comparator<Entry<String, Hi>>() {
#Override
public int compare(Entry<String, Hi> o1, Entry<String, Hi> o2) {
if (o1 == o2) {
return 0;
}
return -Utils.compareNullSafe(o1.getValue().getHitted(), o2.getValue().getHitted(), Compare.ARG0_FIRST);
}
};
/**
* #param <T>
* #return T
* #see java.lang.Object#clone()
*/
#SuppressWarnings("unchecked")
public <T extends AbstractDTO> T clone() {
try {
return (T) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
} finally {
if (DEBUG_CUSTOM_INSTANCES && getClass().getSimpleName().equals(SHADOWED_CLASS)) {
shadowInstance();
}
}
}
/**
*
*/
protected void shadowInstance() {
if (DEBUG_CUSTOM_INSTANCES) {
final long currentTimeMillis = System.currentTimeMillis();
if (TARGET_HITRATE_PER_INTERVAL <= ++hitsWithinInterval) {
hitting = true;
}
if ((TARGET_HITRATE_PER_INTERVAL / 2) <= ++hits) {
final Thread currentThread = Thread.currentThread();
final StackTraceElement[] stackTrace = currentThread.getStackTrace();
final String key = Utils.getPropertyPath(String.valueOf(System.identityHashCode(currentThread)), displayStackLocaktion(stackTrace))
.intern();
Hi hi = INSTANCE_SHADOW.get(key);
if (hi == null) {
synchronized (key) {
hi = INSTANCE_SHADOW.get(key);
if (hi == null) {
INSTANCE_SHADOW.put(key, hi = new Hi(currentThread.getName(), stackTrace));
}
}
}
hi.hit();
}
{
if (getLoggingInterval(currentTimeMillis) != getLoggingInterval(previousLoggingTime)) {
if (hitsWithinInterval < TARGET_HITRATE_PER_INTERVAL) {
if (hitting) {
hitting = false;
} else {
hits = 0; // Reset measuring on second round, give chance to burtsy hits
}
}
hitsWithinInterval = 0;
previousLoggingTime = currentTimeMillis;
}
}
}
}
/**
* #param time
* #return long
*/
private long getLoggingInterval(long time) {
return time / LOGGING_INTERVAL;
}
/**
* #return String
*/
public static String toStringShadows() {
final ArrayList<Entry<String, Hi>> entries;
synchronized (INSTANCE_SHADOW) {
entries = Convert.toMinimumArrayList(INSTANCE_SHADOW.entrySet());
INSTANCE_SHADOW.clear();
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(new Timestamp(System.currentTimeMillis()) + " " + SHADOWED_CLASS + " Class instance instantiantion summary:\n");
stringBuilder.append("hits=" + hits + ", hitting=" + hitting + ", hitsWithinInterval=" + hitsWithinInterval + ", previousLoggingTime=" + new java.sql.Timestamp(previousLoggingTime));
if (entries.isEmpty()) {
return stringBuilder.toString();
}
Collections.sort(entries, COMPARATOR);
int index = 0;
stringBuilder.append("-----------------------------------------------------------------------");
for (Entry<String, Hi> entry : entries) {
Utils.append(stringBuilder, entry.getValue().getHitted() + "\t" + entry.getKey(), "\n");
}
for (Entry<String, Hi> entry : entries) {
final Hi hi = entry.getValue();
final StackTraceElement[] stackTrace = hi.getStackTraceElements();
final String groupName = entry.getKey();
final String threadName = hi.getThreadName();
stringBuilder.append("\n").append(++index).append('\t');
stringBuilder.append(hi.getHitted()).append("\tpcs\t").append(groupName);
stringBuilder.append("\t").append(new Timestamp(hi.getCreatedAt()).toString()).append('\t').append(threadName)
.append('\t').append(Convert.toString(stackTrace));
}
return stringBuilder.toString();
}
/**
* #param stackTrace
* #return String
*/
private static String displayStackLocaktion(final StackTraceElement[] stackTrace) {
StackTraceElement firstDistinguishingStackTraceElement = null;
for (int index = 0; index < stackTrace.length; index++) {
firstDistinguishingStackTraceElement = stackTrace[index];
if (!Arrays.asList(UNWANTED_LOCATIONS).contains(firstDistinguishingStackTraceElement.getClassName())) {
break;
}
}
StackTraceElement lastDistinguishingStackTraceElement = null;
for (int index = stackTrace.length-1; 0 <= index; index--) {
lastDistinguishingStackTraceElement = stackTrace[index];
if (lastDistinguishingStackTraceElement.getClassName().startsWith(OUR_PACKAGE_DOMAIN)) {
break;
}
}
return Utils.getPropertyPath(displayName(firstDistinguishingStackTraceElement) + "<-"
+ displayName(lastDistinguishingStackTraceElement));
}
/**
* #param firstDistinguishingStackTraceElement
* #return String
*/
private static String displayName(StackTraceElement firstDistinguishingStackTraceElement) {
return Utils.getPropertyPath(firstDistinguishingStackTraceElement.getClassName(), firstDistinguishingStackTraceElement.getMethodName(),
String.valueOf(firstDistinguishingStackTraceElement.getLineNumber()));
}
}
I have three classes, those being Lister, ObjectSortedList and SortedListProgram. I'm having trouble with the iterator for the generic class. What am I doing wrong?
This is the error I get:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
at objectsortedlist.ObjectSortedList.getData(ObjectSortedList.java:122)
at objectsortedlist.Lister.hasNext(Lister.java:28)
at objectsortedlist.SortedListProgram.main(SortedListProgram.java:52)
Java Result: 1
Here are my classes:
package objectsortedlist;
import java.util.Iterator;
/**
*
* #author Steven
*/
public class ObjectSortedList<T> implements Cloneable, Iterable<T> {
private T[] data;
private int capacity;
public ObjectSortedList()
{
final int init_capacity = 10;
capacity = 0;
data = (T[])new Object[init_capacity];
}
public ObjectSortedList(int init_capacity)
{
if(init_capacity < 0)
throw new IllegalArgumentException("Initial capacity is negative: " + init_capacity);
capacity = 0;
data = (T[])new Object[init_capacity];
}
private boolean empty()
{
if(data.length == 0 || data[0] == null)
return true;
else
return false;
}
public int length()
{
return capacity;
}
public void insert(T element)
{
if(capacity == data.length)
{
ensureCapacity(capacity * 2 + 1);
}
data[capacity] = element;
capacity++;
}
public boolean delete(T target)
{
int index;
if(target == null)
{
index = 0;
while((index < capacity) && (data[index] != null))
index++;
}
else
{
index = 0;
while((index < capacity) && (!target.equals(data[index])))
index++;
}
if(index == capacity)
return false;
else
{
capacity--;
data[index] = data[capacity];
data[capacity] = null;
return true;
}
}
private void ensureCapacity(int minCapacity)
{
T[] placeholder;
if(data.length < minCapacity)
{
placeholder = (T[])new Object[minCapacity];
System.arraycopy(data, 0, placeholder, 0, capacity);
data = placeholder;
}
}
public ObjectSortedList<T> clone()
{
// Cloning
ObjectSortedList<T> answer;
try
{
answer = (ObjectSortedList<T>) super.clone();
}
catch(CloneNotSupportedException cnse)
{
throw new RuntimeException("This class does not implement cloneable.");
}
answer.data = data.clone();
return answer;
}
#Override
public Iterator<T> iterator()
{
return (Iterator<T>) new Lister<T>(this, 0);
}
public T getData(int index)
{
return (T)data[index];
}
}
package objectsortedlist;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
*
* #author Steven
*/
public class Lister<T> implements Iterator<T>
{
private ObjectSortedList<T> current;
private int index;
public Lister(ObjectSortedList<T> top, int index)
{
current = top;
this.index = index;
}
#Override
public boolean hasNext()
{
return (current.getData(index) == null);
}
#Override
public T next()
{
T answer;
if(!hasNext())
throw new NoSuchElementException("The Lister is empty.");
answer = current.getData(index+1);
return answer;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Don't use this. Use objectsortedlist.SortedList.delete(T target).");
}
}
package objectsortedlist;
import java.util.Scanner;
/**
*
* #author Steven
*/
public class SortedListProgram {
private static Scanner scan = new Scanner(System.in);
private static String[] phraseArray = {"Hullabaloo!", "Jiggery pokery!", "Fantastic!", "Brilliant!", "Clever!", "Geronimo!", "Fish sticks and custard.", "Spoilers!",
"Exterminate!", "Delete!", "Wibbly-wobbly!", "Timey-wimey!"};
private static Lister<String> print;
public static void main(String args[])
{
int phraseNo = 0;
System.out.println("I'm gonna say some things at you, and you're going to like it."
+ " How many things would you like me to say to you? Put in an integer from 1-12, please.");
try
{
phraseNo = Integer.parseInt(scan.nextLine());
while((phraseNo < 1) || (phraseNo > 12))
{
System.out.println("The integer you entered wasn't between 1 and 12. Make it in between those numbers. Please? Pleaseeeee?");
phraseNo = Integer.parseInt(scan.nextLine());
}
}
catch(NumberFormatException nfe)
{
System.out.println("C'mon, why don't you follow directions?");
phraseNo = 0;
}
if(phraseNo == 0);
else
{
ObjectSortedList<String> phrases = new ObjectSortedList<String>(phraseNo);
for(int i = 0; i < phrases.length(); i++)
{
phrases.insert(phraseArray[i]);
}
print = new Lister<String>(phrases, phraseNo);
while(print.hasNext())
System.out.println(print.next());
}
}
}
After looking at your code I found multiple issues, here are they:
In your SortedListProgram class, in following code the phrases.length() will be 0, so the it will never go in that loop.
ObjectSortedList<String> phrases = new ObjectSortedList<String>(phraseNo);
for(int i = 0; i < phrases.length(); i++)
{
phrases.insert(phraseArray[i]);
}
Moreover in SortedListProgram class's this call sequence
print.hasNext() -> current.getData(index)
the index passed is equal to size of data array field in the
ObjectSortedList class and Since in java array indexes ranges from
zero to array size -1. So you are bound to get
java.lang.ArrayIndexOutOfBoundsException always.
Please correct your code.