null pointer exception in array - java

I am getting a null exception error from this segment of code and I am not sure what causing it. The array itemcatalog has being populate for i =0 to 8. I am new to java so any assistance will be greatly appreciated. The error message points to the line of the while statement. Thanks
public class ItemCatalog {
private static ItemCatalog instance = new ItemCatalog();
private Item itemCatalog[] = new Item[9];
private ItemCatalog(){
};
public static synchronized ItemCatalog getInstance() {
return instance;
}
public void populateCatalog()
{
itemCatalog[0] = new Item("bb","Baked Beans",new BigDecimal("0.35"));
itemCatalog[1] = new Item("cf","Cornflakes",new BigDecimal("1.00"));
itemCatalog[2] = new Item("s0","Sugar",new BigDecimal("0.50"));
itemCatalog[3] = new Item("tb","Tea Bags",new BigDecimal("1.15"));
itemCatalog[4] = new Item("ic","Instant Coffee",new BigDecimal("2.50"));
itemCatalog[5] = new Item("b0","Bread",new BigDecimal("0.50"));
itemCatalog[6] = new Item("s0","Sausages",new BigDecimal("1.30"));
itemCatalog[7] = new Item("e0","Eggs",new BigDecimal("0.75"));
itemCatalog[8] = new Item("m0","Milk",new BigDecimal("0.65"));
}
public BigDecimal getPrice(String itemCode)
{
int i = 0;
while (!itemCode.equals(itemCatalog[i].getItemCode()))
{
i++;
}
BigDecimal itemPrice = itemCatalog[i].getItemprice();
return itemPrice;
}
}
I solved the issue. I was populating the catalog in the main class which was giving the null exception error. I instantiate it in the jframe instead and it works. The follow code solved the issue, but is this the best place to populate the catalog?
private void saleButtonActionPerformed(java.awt.event.ActionEvent evt) {
String itemCode = this.itemCodeinput.getText();
int itemQuantity =Integer.parseInt(this.itemQuantityinput.getText());
ItemCatalog catalog = ItemCatalog.getInstance();
catalog.populateCatalog();
BigDecimal price = catalog.getPrice(itemCode);
itemCostoutput.setText(price.toString());
}

If your itemCode doesn't match any entries in your itemCatalog, then eventually
while (!itemCode.equals(itemCatalog[i].getItemCode()))
{
i++;
}
will increment i to 11, in which case itemCatalog[11] is either empty or out of bounds.
If addition, you should use a for loop to iterate through the itemCatalog:
for (int i = 0; i < itemCatalog.length; i++) {
if (itemCode.equals(itemCatalog[i].getItemCode()) {
return (BigDecimal) itemCatalog[i].getItemprice();
}
}
return null // you can change this from null to a flag
// value for not finding the item.

From the comments, it's clear the design isn't sound.
Here's a possible solution :
public BigDecimal getPrice(String itemCode) {
for (int i=0; i<itemCatalog.length; i++) { // not going outside the array
if (itemCatalog[i].getItemCode().equals(itemCode)) { // inversing the test to avoid npe if itemCode is null
return itemCatalog[i].getItemprice();
}
}
return null; // default value
}
This supposes your array is correctly filled with itemCatalogs having an itemCode.

How do you end your loop?
Seems that the loop will keep going until i is 10. Then your will have exceeded the limit.
Unless this is a uni assignment where you have to use arrays, I'd also suggest using a map, rather than an array. This way your lookup will be the same time, whether your collection has 100,000 entries or 10.
You will also reduce risk of NPE or ArrayOutOfBounds exception
See http://docs.oracle.com/javase/1.4.2/docs/api/java/util/HashMap.html
When adding the object use the item code as the key. Then lookup by the key.
The cost of using a map is increased memory usage.

Related

Java memory leak when using an array

wanted to confirm my assumption. I am looking at code from another developer who was using an array (not linkedhashset/sorted collection etc) and trying to keep it sorted based on insertion but also keeping it of fixed size. The logic for keeping it of fixed size was to remove the oldest item from the array. However, when removing the oldest item from the array, the object reference was not nulled out i.e. only the array index was written to with another object. I think this might let the old (not nulled out) object hang around in memory longer than needed (if not a memory leak altogether) unless I missed anything with scoping. Any thoughts (I am trying to confirm with a quick test and visualvm as well). Thanks in advance.
public class MemTest {
private TestBuffer testQuotes = new TestBuffer(10); //static inner class
public static void main(String[] args) {
System.out.println("Starting!");
MemTest memTest = new MemTest();
for (int j = 0; j < 10; j++) {
for (int i = 0; i < 2000000000; i++) {
memTest.testQuotes.push(1, 12.3);
}
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
System.out.println("exception:" + e);
}
}
}
private static class QuoteBuffer {
private Object[] keyArr;
private Price[] testArr;
public TestBuffer(int size) {
keyArr = new Object[size];
testArr = new Price[size];
}
public Price get(Object key) {
if (key != null) {
for (int i=0; i<keyArr.length; i++) {
if ( key.equals(keyArr[i]) )
return quoteArr[i];
}
}
return null;
}
private void _slideTestQuotes() {
Object prevKey = null;
Price prevQuote = null;
Object tempKey;
Price tempQuote;
for (int i=0; i<keyArr.length; i++) {
// slide key to the next index
tempKey = keyArr[i];
keyArr[i] = prevKey;
prevKey = tempKey;
// tempKey = null; //I am guessing uncommenting this should make a difference
// slide quote to the next index
tempQuote = quoteArr[i];
quoteArr[i] = prevQuote;
prevQuote = tempQuote;
// tempQuote= null; //I am guessing uncommenting this should make a difference
}
}
public void push(Object key, Double quote) {
_slideTestQuotes();
keyArr[0] = key;
quoteArr[0] = new Price(quote); //quote;
}
}
public class Price {
Double price;
Double a1;
Double a2;
Double a3;
Double a4;
Double a5;
Double a6;
Price(Double price) {
this.price = price;
this.a1 = price;
this.a2 = price;;
this.a3 = price;
this.a4 = price;
this.a5 = price;
this.a6 = price;
}
}
You don't need to actually set a reference to null to make it eligible for garbage collection. Consider the following snippet:
Double d = new Double(1.1); // (1)
d = new Double(2.2); // (2)
At line 2 the object handle "d" is assigned a new value. This means the original Double with value 1.1 is now no longer reachable in any way and is eligible for garbage collection. There is no need to specifically write "d = null" first.
The Java garbage collector will collect all objects which are not reachable any longer. You don't have to null out references;
ref = null;
ref = newRef;
and
ref = newRef;
have exactly the same effect and, if there are no other references to the object that ref was pointing to, will both cause the garbage collector to collect that object.
You only need to null out references when you want to throw away a reference to an object but do not assign a new value to the reference. In that case forgetting to null out the reference might indeed cause a memory leak, because there is still a reference to an object that you might not need anymore.
However, when removing the oldest item from the array, the object reference was not nulled out i.e. only the array index was written to with another object. - This is the key point. It doesn't matter whether you are setting the reference to null or setting it to some other object, the "original" object becomes unreachable if there are no more references to it.
Example :
arr[0] = new myObject();
MyObject my = arr[0];
arr[0]=null; // or arr[0] = new myObject(); makes no difference. Since The original MyObject is still reachable, it will not be considered for GC.
my=null; // or my=new MyObject() // now the original MyObject instance will be unreachable and hence ready for GC.

Return value from method java

I have a program in java that I wrote to return a table of values. Later on as the functions of this program grew I found that I would like to access a variable within the method that isn't returned but I am not sure the best way to go about it. I know that you cannot return more than one value but how would I go about accessing this variable without a major overhaul?
here is a simplified version of my code:
public class Reader {
public String[][] fluidigmReader(String cllmp) throws IOException {
//read in a file
while ((inpt = br.readLine()) != null) {
if (!inpt.equals("Calls")) {
continue;
}
break;
}
br.readLine();
inpt = br.readLine();
//set up parse parse parameters and parse
prse = inpt.split(dlmcma, -1);
while ((inpt = br.readLine()) != null) {
buffed.add(inpt);
}
int lncnt = 0;
String tbl[][] = new String[buffed.size()][rssnps.size()];
for (int s = 0; s < buffed.size(); s++) {
prse = buffed.get(s).split(dlmcma);
//turns out I want this smpls ArrayList elsewhere
smpls.add(prse[1]);
//making the table to search through
for (int m = 0; m < prse.length; m++) {
tbl[lncnt][m] = prse[m];
}
lncnt++;
}
//but I return just the tbl here
return tbl;
}
Can anyone recommend a way to use smpls in another class without returning it? Is this perhaps when you use a get/set sort of setup?
Sorry if this seems like an obvious question, I am still new to the world of modular programming
Right now you have this tbl variable. Wrap it in a class and add the list to the class.
class TableWrapper {
// default accessing for illustrative purposes -
// setters and getters are a good idea
String[][] table;
List<String> samples;
TableWrapper(String[][] table, List<String> samples) {
this.table = table;
this.samples = samples;
}
}
Then refactor your method to return the wrapper object.
public TableWrapper fluidigmReader(String cllmp) throws IOException {
// your code here
String tbl[][] = new String[buffed.size()][rssnps.size()];
TableWrapper tw = new TableWrapper(tbl,smpls);
// more of your code
return tw;
}
Then later in your code where you were going
String[][] tbl = fluidigmReader(cllmp);
You instead go
TableWrapper tw = fluidigmReader(cllmp);
String[][] tbl = tw.table;
List<String> smpls = tw.samples;
If you had used a dedicated class for the return value (such as the TableWrapper mentioned in another answer), then you could add additional fields there.
That is the good thing about classes - they can be extended. But you cannot extend String[][] in Java.
You can set a field, instead of a local variable, which you can retrieve later with a getter. You want to avoid it unless it is needed, but in this case it is.
You can use class(Inside Reader class) variable for this. But make sure that it's read/write is synchronized

Having trouble understanding how to maintain state using classes

I'm new to using OOP, I typically just put all my code in a single class and use methods. But I want to maintain state information and think classes are the best fit but I'm having trouble wrapping my head around it.
Say I have a list of items and I want to stop when the total sum of all previous items in the list equals X(in this case 10 so it takes item 1 + 2, then 2+3.etc..until it hits the threshold 10), I can use a method to calculate it but it involves me doing the entire process all over again when all I really need to do is increment by the last item and then see if my data exceeds the threshold. Here's my code so far but I know its not good because although it works its really just using the class as an independent method and recalculating on every loop. My goal is to,using this structure, reduce loops if not necessary to check thresholds.
Any suggestions?
Code:
public class LearningClassesCounter {
public static void main(String[] args) {
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data(current_location));
for (int i =0; i<100; i++){
if (checker.check_data(current_location) == false) {
break;
}
data_list[current_location] = (list[current_location]+1); //this is just a random function, it could be any math function I just put it in here to show that some work is being done.
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
}
class Counter {
private int[] data_list;
private int total_so_far;
// create a new counter with the given parameters
public Counter(int[] data_list) {
this.data_list = data_list;
this.total_so_far = 0;
}
public boolean check_data(int current_location) {
// TODO Auto-generated method stub
int total_so_far = 0;
//System.out.println(total_so_far);
for (int item : data_list) {
total_so_far = item + total_so_far;
if (total_so_far >= 10) {
break;
}
}
if (total_so_far>=10) {
return false;
} else {
return true;
}
}
}
I don't need anyone to fix my code or anything(I want to do it myself, the code is just to give an idea of what I'm doing). I'm more interested in the flaw in my logic and maybe a way for me to better think about designing classes so I can apply them to my own situations better.
So the solution is that you do not update the data_list directly. Instead have a setter method in the Counter class that takes the index and value to update. It updates the value in the array and also updates a count value.
Something like this:
class Counter{
private final int[] list;
private count = 0;
private final maxCount = 10;
public Counter(int[] list){
this.list = list;
}
public boolean updateValueAndCheckPastMax(int index, int value){
list[index] = value;
count += value;
return count >= maxCount;
}
}
You are way over thinking this, and a counter class is not really necessary in this case.
I'm also interested as to why you'd be doing this line:
data_list[current_location] = (list[current_location]+1);
Do you want your data_list to be the same as list, but each value is incremented by 1?
If you are merely trying to return a sub-array of the values that are < 10, i would suggest just doing this in a for loop, and using an int as a counter.

Returning searched results in an array in Java without ArrayList

I started down this path of implementing a simple search in an array for a hw assignment without knowing we could use ArrayList. I realized it had some bugs in it and figured I'd still try to know what my bug is before using ArrayList. I basically have a class where I can add, remove, or search from an array.
public class AcmeLoanManager
{
public void addLoan(Loan h)
{
int loanId = h.getLoanId();
loanArray[loanId - 1] = h;
}
public Loan[] getAllLoans()
{
return loanArray;
}
public Loan[] findLoans(Person p)
{
//Loan[] searchedLoanArray = new Loan[10]; // create new array to hold searched values
searchedLoanArray = this.getAllLoans(); // fill new array with all values
// Looks through only valid array values, and if Person p does not match using Person.equals()
// sets that value to null.
for (int i = 0; i < searchedLoanArray.length; i++) {
if (searchedLoanArray[i] != null) {
if (!(searchedLoanArray[i].getClient().equals(p))) {
searchedLoanArray[i] = null;
}
}
}
return searchedLoanArray;
}
public void removeLoan(int loanId)
{
loanArray[loanId - 1] = null;
}
private Loan[] loanArray = new Loan[10];
private Loan[] searchedLoanArray = new Loan[10]; // separate array to hold values returned from search
}
When testing this, I thought it worked, but I think I am overwriting my member variable after I do a search. I initially thought that I could create a new Loan[] in the method and return that, but that didn't seem to work. Then I thought I could have two arrays. One that would not change, and the other just for the searched values. But I think I am not understanding something, like shallow vs deep copying???....
The return value from getAllLoans is overwriting the searchedLoanArray reference, which means that both loanArray and searchedLoanArray are pointing at the same underlying array. Try making searchedLoanArray a local variable, and then use Arrays.copyOf. If you're trying not to use standard functions for your homework, manually create a new Loan array of the same size as loanArray, and then loop and copy the values over.
your searchloanarray and loanarray point to the same array. doing this
private Loan[] searchedLoanArray = new Loan[10]
does nothing as you never use that new Loan[10]
this is the key to your problem
searchedLoanArray = this.getAllLoans()
that just points searchedLoanArray at loanArray
You could rewrite it like this:
public Loan[] findLoans(Person p)
{
Loan[] allLoans = this.getAllLoans();
System.arraycopy(allLoans, searchedLoanArray, 0, 0, allLoans.length); // fill new array with all values
// remainder of method the same
}
But as it stands, the code still has some problems:
The maximum number of loans is fixed to the size of the array. You will avoid this problem when you switch to List<Loan>.
Using the id as an index means that your ids must be carefully generated. If IDs come from a database, you may find that the list tries to allocate a huge amount of memory to size itself to match the Id. You would be better using a Map, then the size of the map is based on the number of loans, rather than their IDs.
As the number of people and loans increase, the search time will also increase. You can reduce search time to a constant (irrespective of how many People) by using a Map>, which allows quick lookup of the loans associated just with that person.
Here's a version with these changes:
class AcmeLoanManager
{
public void addLoan(Loan l)
{
Person client = l.getClient();
List<Loan> loans = clientLoans.get(l);
if (loans==null)
{
loans = new ArrayList();
clientLoans.put(client, loans);
}
loans.add(l);
allLoans.put(l.getLoanId(), l);
}
public void removeLoan(int loanId)
{
Loan l = loans.remove(loanId);
clientLoans.remove(loan);
}
public Collection<Loan> getAllLoans()
{
return loans.values();
}
public List<Loan> findLoans(Person p)
{
List<Loan> loans = clientLoans.get(p);
if (loans==null)
loans = Collections.emptyList();
return loans;
}
private Map<Integer,Loan> allLoans = new HashMap<Integer,Loan>();
private Map<Person, List<Loan>> clientLoans = new HashMap<Person,List<Loan>>();
}
I hope this helps!
What I would do is loop through the values and reassign each value to the new variable. Alternatively, you could use "deep copy" technique as described here in Javaworld: http://www.javaworld.com/javaworld/javatips/jw-javatip76.html

How many dimensions in an array with no value

I'm a little lost (still working with Ron Jeffries's book). Here's a simple class:
public class Model{
private String[] lines;
public void myMethod(){
String[] newLines = new String[lines.length + 2];
for (i = 0, i <= lines.length, i++) {
newLines[i] = lines[i];
}
}
}
I have another class that initializes Model, and an empty array, by setting myModel = new String[0]. When I invoke myModel.myMethod(), I get a subscript out of range error. Looking at the debugger, what I see is that myModel.lines has zero dimensions and zero length. Shouldn't it have a dimension and length of 1? Granted the value of lines[0] is null, but the array itself shouldn't be, should it?
Any thoughts truly appreciated.
Randy
I think your example is probably not the same as your actual code based on your description. I think the problem is that arrays are zero-based and thus an array initialized as:
string[] lines = new string[0];
has no elements.
You need to change your loop so that you check that the index is strictly less than the length of the array. As others have indicated you also need to make sure that the array itself is not null before trying to reference it.
My take on your code:
public class Model{
private String[] lines = new string[0];
public Model( string[] lines ) {
this.lines = lines;
}
public void myMethod(){
int len = 2;
if (lines != null) {
len = len + lines.length;
}
String[] newLines = new String[len];
for (i = 0, i < lines.length, i++) {
newLines[i] = lines[i];
}
}
}
lines will be null, so lines.length will throw an exception.
I believe your other class initializing "Model" won't help since Lines itself is private. In fact, whatever you are doing to Model is probably illegal in at least 30 states.
lines is initalized to null, check for null or initialize it in this way :
private String[] lines = new String[0];
You cannot initialize an instance of Model by setting it equal to a String array. I'm actually surprised that the compiler will let you even try.
If you really want Model to be initializable with an external array, you should make a Constructor for the Model class that will take as an argument the array. Then in the body of your constructor, set the value of lines to that value.
Example:
public class Model {
private String []lines;
public Model(String [] inLines)
{
lines = inLines;
}
}
Usage:
myStringArray = new String[0];
myModel = new Model(myStringArray);
Take a look at my answer here - I think this will get you the background you are looking for on the differences between array initialization in Java and C/C++.

Categories