Deciding on lazy initialization on collection instance variables - java

The question is nested inside the code. I have 2 code options. Each listed with pros and cons. Wanted to know a preferred approach.
OPTION1:
public class Graph {
private final List<ArrayList<Integer>> adjList;
/**
* DISADVANTAGE:
* 1. Slow to create an object.
* 2. Memory allocated prematurely, lazy initialization could be used to speed up object creation.
*/
public Graph(int vertexCount) {
adjList = new ArrayList<ArrayList<Integer>>(vertexCount);
for (int i = 0; i < vertexCount; i++) {
adjList.add(new ArrayList<Integer>());
}
this.vertexCount = vertexCount;
}
/**
* ADVANTAGE:
* 1. No synchronization issues, reducing complexity and overhead of sync.
* 2. No need to null check, since constructor has taken care of lot .
*/
public void addEdge(int vertexFrom, int vertexTo) {
adjList.get(vertexFrom).add(vertexTo);
adjList.get(vertexTo).add(vertexFrom);
}
/**
* DISADVANTAGE:
*
* Inspite of knowing that none of the List<Integers> are null, an extra check for size == 0, needed to return Collections.EMPTY_LIST
* Eg:
* if (adjList.get(vertex).size == 0) { return Collections.EMPTY_LIST; }
* return adjList.get(vertex).size
*/
public List<Integer> adj(int vertex) {
return adjList.get(vertex);
}
}
OPTION 2
public class Graph {
private final List<ArrayList<Integer>> adjList;
private final int vertexCount;
private int edgeCount;
/**
* ADVANTAGE: quick construction
*
*/
public Graph(int vertexCount) {
adjList = new ArrayList<ArrayList<Integer>>(vertexCount);
this.vertexCount = vertexCount;
}
/**
* DISADVANTAGE:
* 1. Effort spent on null checks.
*
* 2. Thread safety complications.
*/
public void addEdge(int vertexFrom, int vertexTo) {
if ( adjList.get(vertexFrom) == null ) {
adjList.add(vertexFrom, new ArrayList<Integer>())
}
if ( adjList.get(vertexTo) == null ) {
adjList.add(vertexTo, new ArrayList<Integer>())
}
adjList.get(vertexFrom).add(vertexTo);
adjList.get(vertexTo).add(vertexFrom);
edgeCount++;
}
public List<Integer> adj(int vertex) {
if (adjList.get(vertex) == 0) return Collections.EMPTY_LIST;
return adjList.get(vertex);
}
public List<ArrayList<Integer>> getGraph() {
return adjList;
}
}

Related

Both methods have same erasure, yet overrides the other

I'm trying to implement a Queue but my method "enqueue(E e)" is giving me an error saying that the method clashes with the method in the Queue interface but neither override the other. What is going on?
Here is the Queue Interface
public interface Queue<E> {
/**
* Returns the number of elements in the queue.
*/
int size();
/**
* Tests whether the queue is empty.
*/
boolean isEmpty();
/**
* Inserts an element at the rear of the queue.
*/
void enqueue(E e);
/**
* Returns, but does not remove, the first element of the queue (null if empty).
*/
E first();
/**
* Removes and returns the first element of the queue (null if empty).
*/
E dequeue();
}
And here is the implementation
/**
* Implementation of the queue ADT using a fixed-length array.
* #param <E>
*/
public class ArrayQueue<E> implements Queue {
// instance variables
private E[] data;
private int f = 0;
private int sz = 0;
public static final int CAPACITY = 1000;
// Constructors
public ArrayQueue() {
this(CAPACITY);
}
public ArrayQueue(int capacity) {
data = (E[]) new Object[capacity];
}
// methods
/**
* Returns the number of elements in the queue
*/
public int size() {
return sz;
}
/**
* Tests whether the queue is empty.
*/
public boolean isEmpty() {
return sz == 0;
}
/**
* Inserts an element at the rear of the queue.
*/
public void enqueue(E e) throws IllegalStateException {
if (sz == data.length)
throw new IllegalStateException("Queue is full");
int avail = (f + sz) % data.length;
data[avail] = e;
sz++;
}
/**
* Returns, but does not remove, the first element of the queue (null if empty)
*/
public E first() {
if (isEmpty())
return null;
return data[f];
}
/**
* Removes and returns the first element of the queue (null if empty)
*/
public E dequeue() {
if (isEmpty())
return null;
E answer = data[f];
data[f] = null;
f = (f + 1) % data.length;
sz--;
return answer;
}
}
I've tried removing the "throws new IllegalStateError" and copy and pasting to make sure the spelling was the same. I can't figure out what the problem is. Both of these code fragments come straight out of a book...

Homework StackoverflowError

I'm doing some school exercises about implementing interfaces and I've already got the workspace and Test classes provided for me. What I have to do is basically implement the methods, run the Test Classes, and make sure they pass the tests.
Here is my code: http://pastebin.com/e8Vh3snC
package queue;
import java.util.*;
public class FifoQueue<E> extends AbstractQueue<E> implements Queue<E> {
private QueueNode<E> last;
private int size=0;
private FifoQueue<E> queue;
public FifoQueue() {
queue = new FifoQueue<E>();
}
/**
* Returns an iterator over the elements in this queue
* #return an iterator over the elements in this queue
*/
public Iterator<E> iterator() {
return queue.iterator();
}
/**
* Returns the number of elements in this queue
* #return the number of elements in this queue
*/
public int size() {
return size;
}
/**
* Inserts the specified element into this queue, if possible
* post: The specified element is added to the rear of this queue
* #param x the element to insert
* #return true if it was possible to add the element
* to this queue, else false
*/
public boolean offer(E x) {
if(queue.add(x)){
size++;
return true;
} else {
return false;
}
}
/**
* Retrieves and removes the head of this queue,
* or null if this queue is empty.
* post: the head of the queue is removed if it was not empty
* #return the head of this queue, or null if the queue is empty
*/
public E poll() {
if(queue.size() > 0) {
size=size-1;
}
return queue.poll();
}
/**
* Retrieves, but does not remove, the head of this queue,
* returning null if this queue is empty
* #return the head element of this queue, or null
* if this queue is empty
*/
public E peek() {
return queue.peek();
}
private static class QueueNode<E> {
E element;
QueueNode<E> next;
private QueueNode(E x) {
element = x;
next = null;
}
}
}
Here are the Test Classes, in case you want to see them (provided by the school, so I doubt they're incorrect): http://pastebin.com/uV46j0rm
package testqueue;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.NoSuchElementException;
import java.util.Iterator;
import queue.FifoQueue;
public class TestFifoQueue {
private FifoQueue<Integer> myIntQueue;
private FifoQueue<String> myStringQueue;
#Before
public void setUp() throws Exception {
myIntQueue = new FifoQueue<Integer>();
myStringQueue = new FifoQueue<String>();
}
#After
public void tearDown() throws Exception {
myIntQueue = null;
myStringQueue = null;
}
/**
* Test if a newly created queue is empty.
*/
#Test
public final void testNewFifoQueue() {
assertTrue(myIntQueue.isEmpty());
assertTrue(myIntQueue.size() == 0);
}
/** Test a single offer followed by a single peek. */
#Test
public final void testPeek() {
myIntQueue.offer(1);
int i = myIntQueue.peek();
assertEquals("peek on queue of size 1", 1, i);
assertTrue(myIntQueue.size() == 1);
}
/**
* Test a single offer followed by a single poll.
*/
#Test
public final void testPoll() {
myIntQueue.offer(1);
int i = myIntQueue.poll();
assertEquals("poll on queue of size 1", 1, i);
assertTrue("Wrong size after poll", myIntQueue.size() == 0);
}
/**
* Test peek of empty queue.
*/
#Test
public final void testPeekOfEmpty() {
assertEquals("Front of empty queue not null", null, myIntQueue.peek());
}
/**
* Test poll of empty queue.
*/
#Test
public final void testPollOfEmpty() {
assertEquals("Poll of empty queue should return null", null, myIntQueue
.poll());
}
/**
* Test that implementation works for a queue of strings.
*/
#Test
public final void testStringQueue() {
myStringQueue.offer("First");
myStringQueue.offer("Second");
myStringQueue.offer("Third");
assertTrue("Wrong size of queue", myStringQueue.size() == 3);
assertEquals("peek on queue of strings", "First", myStringQueue.peek());
assertEquals("String First expected", "First", myStringQueue.poll());
assertEquals("String Second expected", "Second", myStringQueue.poll());
assertEquals("String Third expected", "Third", myStringQueue.poll());
assertTrue("Queue of strings should be empty", myStringQueue.isEmpty());
}
/**
* Test that polling gives elements in right order.
*/
#Test
public final void testOrder() {
myIntQueue.offer(1);
myIntQueue.offer(2);
myIntQueue.offer(3);
myIntQueue.offer(4);
myIntQueue.offer(5);
for (int i = 1; i <= 5; i++) {
int k = myIntQueue.poll();
assertEquals("poll returns incorrect element", i, k);
}
assertTrue("Queue not empty", myIntQueue.isEmpty());
}
/**
* Test that polling all elements gives an empty queue.
*/
#Test
public final void testMakeQueueEmpty() {
myIntQueue.offer(1);
myIntQueue.offer(2);
myIntQueue.poll();
myIntQueue.poll();
assertTrue("Wrong size after poll", myIntQueue.size() == 0);
assertTrue("Queue not empty after poll", myIntQueue.isEmpty());
myIntQueue.offer(3);
myIntQueue.offer(4);
assertTrue("Wrong size after offer", myIntQueue.size() == 2);
for (int i = 3; i <= 4; i++) {
int k = myIntQueue.poll();
assertEquals("poll returns incorrect element", i, k);
}
assertTrue("Wrong size after poll", myIntQueue.size() == 0);
assertTrue("Queue not empty after poll", myIntQueue.isEmpty());
}
}
So when I try to run the tests, I get multiple StackOverflowErrors at queue.FifiQueue.(FifoQueue.java:10)
I've been looking through the code for some hours now but can't figure out where I've written bad code.
PS: I know some of the methods are implemented incorrectly (I will try to fix them later) but as for now I'm just trying to pass the offer() och size() methods.
Your constructor is calling itself, causing infinite recursion:
public FifoQueue() {
queue = new FifoQueue<E>();
}
Maybe you mean to wrap some other type of queue or list internally?

Java Generics - Multiple Questions (Type not within bounds, Warnings)

I have a few classes that I need to be generic. I have the following class DataSet that I want to be able to generate an average and maximum of any sort of Objects passed into class that implements my measurable interface or my Measurer interface.
When I go to test my code, I get the error that my type is not within bounds. Any ideas? When I exclude the Measurer from the DataSet, the test compiles. I am not sure if I made the DataSet correctly Generic.
DataSet.java
public class DataSet<T extends Measurable<Double> & Measurer<Double>>//
{
/**
Constructs an empty data set.
*/
public DataSet()
{
this.sum = 0;
this.count = 0;
this.maximum = null;
}
/**
Adds a data value to the data set.
#param x a data value
*/
public void add(T x)
{
sum = sum + x.getMeasure();
if (count == 0 || maximum.getMeasure() < x.getMeasure())
maximum = x;
count++;
}
/**
Gets the average of the added data.
#return the average or 0 if no data has been added
*/
public double getAverage()
{
if (count == 0) return 0;
else return sum / count;
}
/**
Gets the largest of the added data.
#return the maximum or 0 if no data has been added
*/
public T getMaximum()
{
return maximum;
}
private double sum;
private T maximum;
private int count;
}
DataSetTest.java
import java.awt.Rectangle;
public class DataSetTest
{
public static void main(String[] args)
{
DataSet<BankAccount<Double>> ds1 = new DataSet<>();
BankAccount<Double> ba1 = new BankAccount<>(100.00);
BankAccount<Double> ba2 = new BankAccount<>(300.00);
}
}
BankAccount.java
public class BankAccount<T> implements Measurable<T>
{
public BankAccount()
{
balance = null;
}
public BankAccount(T balance)
{
this.balance = balance;
}
public T getMeasure()
{
return balance;
}
private T balance;
}
Measurable.java
/**
Describes any class whose objects can be measured.
*/
public interface Measurable <T>
{
/**
Computes the measure of the object.
#return the measure
*/
T getMeasure();
}
Measurer.java
/**
Describes any class whose objects need a measurer.
*/
public interface Measurer <T>
{
/**
Computes the measurer of the object.
#return the measurer
*/
T getMeasurer(T anObject);
}
rectangleShape.java
import java.awt.Rectangle;
/**
Concrete Class RectangleMeasurer
#param Takes object as parameter. Overloads measurer class.
#return Returns the area of a object passed in.
*/
public class rectangleShape<T> implements Measurer<T>{
public T getMeasurer(T anObject)
{
Rectangle aRectangle = (Rectangle) anObject;
Double area = aRectangle.getWidth() * aRectangle.getHeight();
//#SuppressWarnings("unchecked")
a = (T)area;
return a;
}
private T a;
}
The type bounds <T extends Measurable<Double> & Measurer<Double>> imply the parameter extends Measurable AND Measurer, but you want that to be OR. You can't do that with generic parameter syntax.
You can however have overloaded methods in DataSet.
public add(Measurable<Double> m) {
//...
}
public add(Measurer<Double> m) {
//...
}
Or you can do runtime type checking, although that is not the most advisable.
public add(Object o) {
if (o instanceof Measurable) {
//...
} else if (o instanceof Measurer) {
//...
}
}
Basically, your use case does not require a type parameter on the class. You are trying to make the problem fit your solution rather than the other way around.

ArrayList is losing my reference

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

How to find all referrers of an object in Java?

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()));
}
}

Categories

Resources