Java NullPointerException in ArrayList - java

This simple piece of code removes any Statistic in an arrayList if its properties are null. Unfortunately, I'm getting a java.lang.NullPointerException on the first line of the if Statement (if tempStat.serialName==null...). Thoughts?
public static ArrayList<Statistic> removeEmptyStats(ArrayList<Statistic> al) {
Statistic tempStat=new Statistic();
for (int i=0; i<al.size(); i++) {
tempStat=al.get(i);
if (tempStat.serialName==null || tempStat.serialPublisher==null || tempStat.serialISSN==null || tempStat.serialOnlineISSN==null) {
al.remove(i);
}
}
return al;
}

It must be because tempStat itself is null. However you need to be very careful with this.
Say you have 5 elements in your list element 2 is invalid so you remove it, element 3 has now dropped back to element 2, but you're going to move on to check element 3 next, however this is now the old element 4 (if that makes any sense!)

You should not remove entries of a list on which you are doing a loop.
tempstat is null, because when doing for (int i=0; i<al.size(); i++), it stores the initial value of al.size().
Then when you are doing al.get(i) after having removed some values, you can have a i which is higher than the size of the list. (BTW, once you remove a value, it also mean that you will skip one in your list).
You'd to have to use an iterator and iterator.remove().
Iterator<Statistic> iterator = al.iterator();
while(iterator.hasNext()) {
Statistic tempStat = iterator.next();
if (tempStat.serialName==null || tempStat.serialPublisher==null || tempStat.serialISSN==null || tempStat.serialOnlineISSN==null) {
iterator.remove();
}
}

The variable tempStat is null! check the values contained in passed array al

Related

Properly delete duplicates in a list

Given the following datatype Testcase (XQuery, Testpath, FirstInputFile, SecondInputFile, Expected)
how can I properly delete duplicates.
Definition of duplicates:
If FirstInputFile already in the list as SecondInputFile vice versa.
Here is the Testdata
tcs.add(new HeaderAndBodyTestcase("XQ 1", "/1", "FAIL", "FAIL2", "FAILED"));
tcs.add(new HeaderAndBodyTestcase("XQ 1", "/1", "FAIL2", "FAIL", "FAILED"));
tcs.add(new HeaderAndBodyTestcase("XQ 2", "/2", "FAIL4", "FAIL3", "FAILED2"));
tcs.add(new HeaderAndBodyTestcase("XQ 2", "/2", "FAIL3", "FAIL4", "FAILED2"));
and here is the function
protected void deleteExistingDuplicatesInArrayList(final ArrayList<HeaderAndBodyTestcase> list) {
for (int idx = 0; idx < list.size() - 1; idx++) {
if (list.get(idx).firstInputFile.equals(list.get(idx).secondInputFile)
|| (list.get(idx + 1).firstInputFile.equals(list.get(idx).firstInputFile)
&& list.get(idx).secondInputFile.equals(list.get(idx + 1).secondInputFile)
|| (list.get(idx).firstInputFile.equals(list.get(idx + 1).secondInputFile)
&& list.get(idx).secondInputFile.equals(list.get(idx + 1).firstInputFile)))) {
list.remove(idx);
}
}
}
This solution is already working, but seems very crappy, so is there a better solution to this?
put everything in a Set using a comparator if necessary, and create a list from this set if you really need a List (and not a Collection)
Set<HeaderAndBodyTestcase> set = new Hashset<>(list);
Given your rather peculiar "equality" constraints, I think the best way would be to maintain two sets of already seen first- and second input files and a loop:
Set<String> first = new HashSet<>();
Set<String> second = new HashSet<>();
for (HeaderAndBodyTestcase tc : tcs) {
if (! first.contains(tc.getSecondInputFile()) &&
! second.contains(tc.getFirstInputFile())) {
first.add(tc.getFirstInputFile());
second.add(tc.getSecondInputFile());
System.out.println(tc); // or add to result list
}
}
This will also work if "equal" elements do not appear right after each other in the original list.
Also note that removing elements from a list while iterating the same list, while working sometimes, will often yield unexpected results. Better create a new, filtered list, or if you have to remove, create an Iterator from that list and use it's remove method.
On closer inspections (yes, it took me that long to understand your code), the conditions in your current working code are in fact much different than what I understood from your question, namely:
remove element if first and second is the same (actually never checked for the last element in the list)
remove element if first is the same as first on last, and second the same as second on last
remove if first is same as last second and vice versa
only consider consecutive elements (from comments)
Given those constraints, the sets are not needed and also would not work properly considering that both the elements have to match (either 'straight' or 'crossed'). Instead you can use pretty much your code as-is, but I would still use an Iterator and keep track of the last element, and also split the different checks to make the whole code much easier to understand.
HeaderAndBodyTestcase last = null;
for (Iterator<HeaderAndBodyTestcase> iter = list.iterator(); iter.hasNext();) {
HeaderAndBodyTestcase curr = iter.next();
if (curr.firstInputFile.equals(curr.secondInputFile)) {
iter.remove();
}
if (last != null) {
boolean bothEqual = curr.firstInputFile.equals(last.firstInputFile)
&& curr.secondInputFile.equals(last.secondInputFile);
boolean crossedEqual = curr.secondInputFile.equals(last.firstInputFile)
&& curr.firstInputFile.equals(last.secondInputFile);
if (bothEqual || crossedEqual) {
iter.remove();
}
}
last = curr;
}

How to obtain first 5 values from a LinkedHashSet?

I have a LinkedHashSet which contains multiple number of values.
LinkedHashSet<String> lhs = new LinkedHashSet<String>();
I want to iterate through the set of values and display the first five values from the number of items stored in the set. I have used a for loop to iterate through values and display data, see below:
for (String sent : lhs) {
text.append(sent);
}
This outputs all the values stored in the LinkedHashSet. What alterations should I make to my code in order to only get the first 5 values from the set.
You can get your sets Iterator
Iterator<String> it = yourSet.iterator();
and move to next() element N times (assuming that it still hasNext() element)
int counter = 0;
while(it.hasNext() && counter++ < N){
String element = it.next();
...
}
int i = 0;
for (String sentences : lhs) {
if (i > 4) break;
text.append(sentences);
i++;
}
If you had java8, then I would suggest something like this:
yourLinkedHashSet
.stream()
.limit(5)
.forEachOrdered(text::append);
Explanation:
stream() will take one String after another from the collection
limit(5) will stop the calculations after five elements are processed
forEachOrdered(...) takes an action for each item, one after another
text::append is the action to be done per item
You can use subList without counter declaration
Iterator<String> iter = new ArrayList<>(lhs).subList(5, lhs.size())
.iterator();
while (iter.hasNext()) {
text.append(iter.next());
}

Next element using for loops java

Very rudimentary question but I have a loop e.g.
List<ObjectList> = //set of values inside.
for(Object data : ObjectList){
// how to access next element?
// current element is accesed by 'data'. I could get the index position and then increment but is there a easier way?
}
How would you get the next element/previous? I know there are iterators i can use and so on but i want to know a neat way to do it in a for loop.
You can but don't do it as the time complexity of the loop will
increase. Just use a normal loop with an int i looping variable.
If you still want to do it you can find the index this way:
int index = lst.indexOf(data);
Then index+1 is the index of the next element.
And index-1 is the index of the previous element.
Make two methods for next and pervious and pass list and element.
public static <T> T nextElement(List<T> list,T element){
int nextIndex=list.indexOf(element)+1;
return list.size()<nextIndexlist?null:list.get(nextIndex);
}
public static <T> T previousElement(List<T> list,T element){
int previousIndex=list.indexOf(element)-1;
return list.size()>previousIndexlist?null:list.get(previousIndex);
}
1)First way
for(ObjectList data : objectList){
ObjectList previousElement=previousElement(objectList,data);
ObjectList nextElement=nextElement(objectList,data);
}
2) Second way
for(int i=0;i<=objectList.size();i++){
ObjectList previousElement=objectList.size>i-1?null:objectList.get(i-1);
ObjectList nextElement=objectList.size<i+1?null:objectList.get(i+1);
}
3) Third way using iterator
Actually, your for-each isn't iterating a List. This,
List<ObjectList> = //set of values inside.
for(Object data : ObjectList){
}
Should look something like,
List<ObjectList> al = new ArrayList<>();
for(ObjectList data : al){ // <-- like so.
}
But that won't find any data until you populate the List.
Using a "normal" for-loop, this might be, what you are looking for:
List<Object> objectList = new ArrayList<>();
// add some data
for (int i = 0; i < objectList.size(); i++) {
System.out.println((i > 0) ? "previous Object: " + objectList.get(i - 1) : "No previous object, current is the first one.");
System.out.println("Current Object: " + objectList.get(i));
System.out.println((i < objectList.size()) ? "Next Object: " + objectList.get(i + 1) : "No next object, current is the last one.");
}
Key aspect is, that you have to use your loop variable (i in this case) to access your actual elements. i + 1 gives you the next element and i - 1 the previous.
I think what you is an iterator, its used like this:
List<ObjectList> list= //set of values inside.
Iterator<ObjectList> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
System.out.println(iterator.previous());
iterator.next()
}
It allows you to access the next and previous objects.
ListIterator:
There is the ListIterator which can a bit of stepping back and forth.
Mind in the code below previousIndex() yields -1 at the start.
for (ListIterator<Object> iter = objectList.listIterator(); iter.hasNext(); ) {
Object object = iter.next();
Object previous = objectList.get(iter.previousIndex()); // Might fail
Object next = objectList.get(iter.nextIndex()); // Might fail
if (iter.hasPrevious()) ... iter.previous();
}

Java concurrent modification

I have the following code:
System.out.println(dislist.size());
for (int k = 0; k < 10; k++) {
System.out.println(k + dislist.get(k).first + dislist.get(k).second);
if (!dislist.get(k).first.equals(Nodename)) {
if (dislist.get(k).first.equals(myfirst) ||
dislist.get(k).first.equals(mysecond) ||
dislist.get(k).second.equals(myfirst) ||
dislist.get(k).second.equals(mysecond)) {
dislist.remove(k);
}
}
}
}
The Problem is: the print at the beginning clearly says that dislist.size() is 10.
However, I get an array out of bounds exception, telling me that the size of the list is no more than 6.
And yes, I DID add new objects to the list a few lines before that.
I guess when the loop starts that has not been finished yet.
Is there a way to force Java (within the same method) to start the loop only when there is really 10 objects in the list?
You're removing elements from the List as you iterate though it. That's the reason the size is changing.
dislist.remove(k);
Create a new list, and add each element you want to remove to it. After your loop is finished, use disList.removeAll(listOfElementsToRemove) to remove them all at once.
Iterator<YourClass> iter = dislist.iterator();
while (iter.hasNext()) {
YourClass obj = iter.next();
if (/* your expression */) {
iter.remove();
}
}

Java LinkedList issues - how to remove items that meet certain qualifications

I have a question,
Here is what I need to do -
I have BankItems that are associated with numbers. I fill the list but when an objects enters that is $100 more than the lowest dollar value currently in the list, I want to delete the object that has the low value.
First - I create the list
List<BankItem> listOfBankItems = new LinkedList<BankItem>();
Later in the program I create a new BankItem object and it to the list
listOfBankItems.add(createdItem);
and after adding each item I want to check to see if the new item is $100 more than any object already in the list so I run something like this
for (int i = 0; i < listOfBankItems.size(); i++) {
int oldValue =listOfBankItems.get(i).getAmount();
int newValue = createdItem.getAmount();
int calculatedDif = newValue - oldValue;
if (calculatedDif > 100) {
listOfBankItems.remove(i);
}
}
Unfortunately, this isn't working. I don't know what it up. Maybe I shouldn't use a LinkedList? Maybe my logic is way off-base. Please help.
Thanks!!!
The problem is that the index of all items after the removed one will change after you remove that element; therefore you'll basically skip the next element after you remove one.
Use an iterator:
for (Iterator<BankItem> itr = listOfBankItems.iterator(); itr.hasNext();) {
BankItem item = itr.next();
int oldValue = item.getAmount();
int newValue = createdItem.getAmount();
int calculatedDif = newValue - oldValue;
if (calculatedDif > 100) {
itr.remove();
}
}
Your most significant issue probably relates to concurrent modification. For example, if element #49 is the one to be removed, once you remove it, the next element will now be #49, but you will be checking for #50 (as i was still incremented) - so you're probably missing elements from your check.
There are a few ways to handle this. You could remove the i++ from your for loop (leaving only the trailing semi-colon), then do this:
if (calculatedDif > 100) {
listOfBankItems.remove(i);
} else {
i++;
}
Alternatively, you could use an Iterator and its remove() method, which would handle this for you automatically.
You can also improve the performance of this by not obtaining newValue and recalculating calculatedDif on every step of the loop. Declare these 2 lines above the for loop.

Categories