Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[Java] ArrayList.get(index) NullPointer

Pagina: 1
Acties:

  • shadooh
  • Registratie: Mei 2009
  • Laatst online: 19-06 15:07
Hoi,

Ik ben bezig met een project in Android, Java.

Ik loop nu al een aantal keer tegen het probleem aan dat is soms een NullPointer krijg bij ArrayList.get(index).

Hieronder een klein overzicht van de code waar de exception zich (onder andere) voor doet.


Java:
1
2
3
4
5
6
7
for (int counter = 1; counter < ecgData.size(); counter++) {

...
            currentPoint = ecgData.get(counter); //Hier komt de NullPointer
..

}



ecgData is hier de ArrayList<Double>() en komt uit de onderstaande code. Deze methode is al een aantal keer aangepast (met een sublist) aangezien ik met andere implementaties waarmee ik het zelfde bereikte ook de exception kreeg.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private List<Long> times = new ArrayList<Long>();
private List<Double> values = new ArrayList<Double>();

public List<Double> getDataStart(long startTime){
        
        if(times.size() == 0 || times.get(times.size()-1) <= startTime){
            return new ArrayList<Double>();
        }
        
        List<Long> copyTimes = new ArrayList<Long>(times);
        List<Double> copyValues = new ArrayList<Double>(values);
        
        for(int i = 0; i < copyTimes.size(); i++){
            long time = copyTimes.get(i);
            if(time < startTime){
                if(index >= 0){
                    copyTimes.remove(i);
                    copyValues.remove(i);
                    i--;
                }
            } else {
                break;
            }
        }
        return copyValues;
    }


Deze methode wordt regelmatig (paar keer per seconde) aangeroepen en er wordt ook een paar keer per seconde wat toegevoegd aan beide arraylists.

De exception doet zich maar af en toe voor, soms na 1 minuut, soms na 10 minuten. Langer houdt hij het meestal ook niet uit :)

Ik hoor graag of iemand een idee heeft van wat hier fout kan gaan. Mocht er meer code nodig zijn om achter het probleem te komen zal ik het ook plaatsen, dan hoor ik het ook graag! :D

[ Voor 3% gewijzigd door shadooh op 18-04-2013 21:51 ]


  • Stukfruit
  • Registratie: Oktober 2007
  • Niet online
Ik denk dat het verstandig is om eerst eens uit te zoeken hoe een ArrayList werkt en waarom je deze beter niet kan gebruiken op deze manier. Een LinkedList is beter als je vaak en willekeurig elementen wil verwijderen omdat de interne array dan niet steeds heen en weer hoeft te worden gecopieerd.

En leer daarna ook even alles over de Map :Y

Verder is het in dit geval onverstandig om regelmatig nieuwe objecten aan te maken. Daar gaat je app op willekeurige momenten van haperen ivm de gargabe collector die in actie komt, wat je niet zelf kan voorspellen. Je kan beter bestaande objecten hergebruiken.

Kijk trouwens ook eens naar MapMaker. Zo te zien doet dat precies wat je wil? :)
Zie de gelinkte documentatie en het stukje over time expiration.

[ Voor 5% gewijzigd door Stukfruit op 17-04-2013 15:20 ]

Dat zit wel Schnorr.


  • bwerg
  • Registratie: Januari 2009
  • Niet online

bwerg

Internettrol

edit: ik kijk verkeerd. :P Ergo, stomme opmerking.

De null-reference zal trouwens niet door de getDataStart-methode komen, aangezien je daar nooit extra elementen toevoegt en er dus ook nooit null toegevoegd wordt. Kan er niet gewoon null in values zitten?

[ Voor 149% gewijzigd door bwerg op 17-04-2013 08:50 ]

Heeft geen speciale krachten en is daar erg boos over.


  • willempipi
  • Registratie: Maart 2010
  • Laatst online: 03-08 22:44
.

[ Voor 98% gewijzigd door willempipi op 24-07-2023 23:20 ]


  • oeLangOetan
  • Registratie: Maart 2002
  • Laatst online: 31-10 09:26
shadooh schreef op woensdag 17 april 2013 @ 03:17:

Java:
1
2
3
4
5
6
7
for (int counter = 1; counter < ecgData.size(); counter++) {

...
            currentPoint = ecgData.get(counter); //Hier komt de NullPointer
..

}
Als je op dat punt een NPE krijgt is het omdat ecgData null is, het heeft dus niets te maken met de inhoud van de lijst. Als ecgData een veld is in je klasse kan dit misschien ook door een race veroorzaakt zijn (zitten andere draden met ecgData te spelen?)
Stukfruit schreef op woensdag 17 april 2013 @ 08:33:
Verder is het in dit geval onverstandig om regelmatig nieuwe objecten aan te maken. Daar gaat je app op willekeurige momenten van haperen ivm de gargabe collector die in actie komt, wat je niet zelf kan voorspellen. Je kan beter bestaande objecten hergebruiken.
worst practice ever ;( (tenzij je met enorme performance problemen zit, en zelf dan zijn er meestal andere oplossingen)

[ Voor 0% gewijzigd door oeLangOetan op 17-04-2013 13:29 . Reden: typo ]


  • mulder
  • Registratie: Augustus 2001
  • Laatst online: 23-11 11:34

mulder

ik spuug op het trottoir

Als je een item uit een array verwijdert, zal de lengte van de array kleiner worden. Een ook de indexen zullen wijzigen. Je zult de array achterstevoren moeten doorlopen.

oogjes open, snaveltjes dicht


  • Stukfruit
  • Registratie: Oktober 2007
  • Niet online
oeLangOetan schreef op woensdag 17 april 2013 @ 13:28:
worst practice ever ;( (tenzij je met enorme performance problemen zit, en zelf dan zijn er meestal andere oplossingen)
Edit: scratch that :P ik ben het met je eens en zit nog te slapen. Ik had 'm beter kunnen aanraden om vectors te gebruiken.

Maar hij zou sowieso niet twee losse arrays moeten gebruiken voor dingen die blijkbaar bij elkaar horen.

[ Voor 52% gewijzigd door Stukfruit op 17-04-2013 14:22 ]

Dat zit wel Schnorr.


  • shadooh
  • Registratie: Mei 2009
  • Laatst online: 19-06 15:07
@StukFruit - LinkedList was ik altijd al een beetje fan van maar door iemand anders ben ik hier ArrayList gaan gebruiken :p Ik ga de LinkedList proberen!

Ik ben begonnen met een (Hash)Map, deze gaf echter niet de functionaliteiten die ik wou en heb daarom mijn eigen constructie bedacht, zoals te zien is :)

Verder is het wel de bedoeling dat de ArrayLists times en values buiten de methode getDataStart(long) gevuld blijft. De methode getDataStart is er alleen voor om een gedeelte van deze gevulde lijst te krijgen. SubList is hiervoor een oplossing maar gaf dezelfde NullPointers.

@bwerg - Dit zou niet voor mogen komen, maar heb ik niet getest. Dit ga ik nog even doen

@WillemWS - Bij de methode getDataStart() maak ik een nieuwe ArrayList aan, deze wordt buiten de methode getDataStart() niet meer aangepast, alleen doorlopen.

@oeLangOetan - Ik zou niet weten hoe ecgData null kan zijn, getDataStart returned altijd een ArrayList en verder wordt er ook niks mee gedaan behalve dat deze doorlopen wordt.

@Mulder - De lijst wordt buiten de methode getDataStart niet aangepast.

  • willempipi
  • Registratie: Maart 2010
  • Laatst online: 03-08 22:44
.

[ Voor 99% gewijzigd door willempipi op 24-07-2023 23:20 ]


  • shadooh
  • Registratie: Mei 2009
  • Laatst online: 19-06 15:07
@Stukfruit - De lijsten horen idd bij elkaar. Ik snap dat het een beetje raar over komt, maar het zou wel moeten werken. Het zou iig geen NullPointers op moeten leveren voor zover ik weet :)

  • oeLangOetan
  • Registratie: Maart 2002
  • Laatst online: 31-10 09:26
shadooh schreef op woensdag 17 april 2013 @ 14:12:
@oeLangOetan - Ik zou niet weten hoe ecgData null kan zijn, getDataStart returned altijd een ArrayList en verder wordt er ook niks mee gedaan behalve dat deze doorlopen wordt.
shadooh schreef op woensdag 17 april 2013 @ 03:17:
Java:
1
2
3
4
5
6
7
for (int counter = 1; counter < ecgData.size(); counter++) {

...
            currentPoint = ecgData.get(counter); //Hier komt de NullPointer
..

}
En toch, als je op DIE plaats een NPE krijgt, zal het zijn omdat ecgData null is, dat is de enige referentie die op die lijn ge-de-refereert wordt. (zet eens een conditioneel breakpoint)

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 17-11 00:33

HMS

Toch vreemd dat de call naar ecgData.size() dan geen NPE geeft.

Wordt ecgData geset binnen de loop?

Daarnaast: gebruik je multithreading? Dit ruikt een beetje naar een race condition (of andere concurrency gerelateerde bug).

edit: Misschien is een stack trace ook wel handig?

[ Voor 11% gewijzigd door HMS op 17-04-2013 14:32 ]


  • oeLangOetan
  • Registratie: Maart 2002
  • Laatst online: 31-10 09:26
Stukfruit schreef op woensdag 17 april 2013 @ 13:49:
[...]
Maar hij zou sowieso niet twee losse arrays moeten gebruiken voor dingen die blijkbaar bij elkaar horen.
Inderdaad, ik denk dat een TreeMap<Long, Double> zijn logica sterk zou vereenvoudigen.

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 17-11 00:33

HMS

oeLangOetan schreef op woensdag 17 april 2013 @ 14:42:
[...]

Inderdaad, ik denk dat een TreeMap<Long, Double> zijn logica sterk zou vereenvoudigen.
Of gewoon door een aparte class aan te maken zodat het conceptueel ook bij elkaar hoort, dus iets als:

Java:
1
2
3
4
5
6
7
8
public class EcgDataPoint {
    public final long timeStamp;
    public final double value;

    public EcgDataPoint(long timeStamp, double value) {
        // setten etc.
    }
}


Dan heb je dus niet een 'willekeurige' Long en Double die bij elkaar horen, maar heb je gelijk aangegeven wat het is en welke relatie ze hebben. Met een TreeMap<Long, Double> heb je dat voordeel niet.

Maar goed, dit was volgens mij niet het probleem van de TS ;)

  • shadooh
  • Registratie: Mei 2009
  • Laatst online: 19-06 15:07
Ik kan er nu niet meer bezig, maar zal vanavond een udpate geven van mijn nieuwe bevindingen.

Ik had een reden om geen Map te gebruiken, dit is echter al een tijd geleden. Volgens mij was het omdat ik een List moest hebben van een gedeelte van de values van een Map. Dit wil ik een beetje efficient hebben en leek het me dus niet handig om elke keer de Map bijlangs te gaan en alles wat ik moest hebben er uit te halen.

  • oeLangOetan
  • Registratie: Maart 2002
  • Laatst online: 31-10 09:26
HMS schreef op woensdag 17 april 2013 @ 14:49:
[...]


Of gewoon door een aparte class aan te maken zodat het conceptueel ook bij elkaar hoort, dus iets als:

Java:
1
2
3
4
5
6
7
8
public class EcgDataPoint {
    public final long timeStamp;
    public final double value;

    public EcgDataPoint(long timeStamp, double value) {
        // setten etc.
    }
}


Dan heb je dus niet een 'willekeurige' Long en Double die bij elkaar horen, maar heb je gelijk aangegeven wat het is en welke relatie ze hebben. Met een TreeMap<Long, Double> heb je dat voordeel niet.

Maar goed, dit was volgens mij niet het probleem van de TS ;)
Ik zou een TreeMap nemen omdat je dan vanuit een willekeurig punt in de tijd lineair vooruit/achteruit kan gaan itereren. TreeMap<Double, EcgDataPoint> gaat natuurlijk ook :)
shadooh schreef op woensdag 17 april 2013 @ 14:52:
Ik kan er nu niet meer bezig, maar zal vanavond een udpate geven van mijn nieuwe bevindingen.

Ik had een reden om geen Map te gebruiken, dit is echter al een tijd geleden. Volgens mij was het omdat ik een List moest hebben van een gedeelte van de values van een Map. Dit wil ik een beetje efficient hebben en leek het me dus niet handig om elke keer de Map bijlangs te gaan en alles wat ik moest hebben er uit te halen.
En ArrayList.remove & ArrayList.indexOf is wel efficiënt??? In plaats van elementen te verwijderen uit een bestaande lijst is het beter (leesbaarheid) èn efficiënter om een nieuwe lijst te bouwen.
Java:
1
2
3
4
5
6
7
8
9
10
List<Double> ret = Lists.newArrayList()
for(int i = 0; i < times.size(); i++) {
    long time = times.get(i);
    if(time < startTime) {
        ret.add(values.get(i));
    } else {
        break;
    }   
}
return ret;

(met een treemap wordt het bovenstaande zelf een 1-liner)

(edit: btw ik ga er van uit dat alle waardes in de lijst times uniek zijn)

  • shadooh
  • Registratie: Mei 2009
  • Laatst online: 19-06 15:07
Hehe, daar heb je wel een punt. Het gaat niet alleen om de methode getDataStart() trouwens, maar is wel redelijk vergelijkbaar met de anderen.

Ik zal kijken of de rest van de code eenvoudig aan te passen is zodat ik gewoon een Map gebruik. Dit lijkt inderdaad wel een paar problemen op te lossen.

  • bwerg
  • Registratie: Januari 2009
  • Niet online

bwerg

Internettrol

mulder schreef op woensdag 17 april 2013 @ 13:37:
Als je een item uit een array verwijdert, zal de lengte van de array kleiner worden. Een ook de indexen zullen wijzigen. Je zult de array achterstevoren moeten doorlopen.
willemWS schreef op woensdag 17 april 2013 @ 14:12:
[...]


Dit, of tussentijds checken of de lengte van je Array nog gelijk is.
oeLangOetan schreef op woensdag 17 april 2013 @ 15:52:
En ArrayList.remove & ArrayList.indexOf is wel efficiënt??? In plaats van elementen te verwijderen uit een bestaande lijst is het beter (leesbaarheid) èn efficiënter om een nieuwe lijst te bouwen.
Of gewoon een LinkedList met een ListIterator gebruiken om elementen te verwijderen. Dat is dus wél efficiënt en logisch. :P

Maar inderdaad, een HashMap of een lijst van samengestelde objecten lijkt meer kans van slagen te hebben.

Heeft geen speciale krachten en is daar erg boos over.


  • Jegorex
  • Registratie: April 2004
  • Laatst online: 03-09 23:24
shadooh schreef op woensdag 17 april 2013 @ 03:17:
Java:
1
2
3
4
5
6
7
for (int counter = 1; counter < ecgData.size(); counter++) {

...
            currentPoint = ecgData.get(counter); //Hier komt de NullPointer
..

}
Is currentPoint een double terwijl ecgData Double values heeft? Double/double.
Een Double object kan null zijn terwijl double NIET null mag zijn.
Als je dus een null waarde in de array hebt zal dat een NPE geven.

PS: Ik heb niet alle reacties doorgelezen, misschien is dit al eerder genoemd.

  • oeLangOetan
  • Registratie: Maart 2002
  • Laatst online: 31-10 09:26
Jegorex schreef op woensdag 17 april 2013 @ 21:20:
[...]

Is currentPoint een double terwijl ecgData Double values heeft? Double/double.
Een Double object kan null zijn terwijl double NIET null mag zijn.
Als je dus een null waarde in de array hebt zal dat een NPE geven.

PS: Ik heb niet alle reacties doorgelezen, misschien is dit al eerder genoemd.
Als currentpoint een 'double' (kleine d, niet Double), dan zal er idd een NPE gebeuren bij het unboxen, nice had ik niet aan gedacht :)
bwerg schreef op woensdag 17 april 2013 @ 18:06:
Of gewoon een LinkedList met een ListIterator gebruiken om elementen te verwijderen. Dat is dus wél efficiënt en logisch. :P
LinkedList heeft zeer veel pointer-indirecties & veel memory overhead, hij daardoor vele malen trager dan ArrayList voor veel operaties. Bovendien is code die met ListIterator werkt meestal moeilijk om te begrijpen/debuggen. Zie ook http://stackoverflow.com/a/323889 en http://stackoverflow.com/a/7671021

  • bwerg
  • Registratie: Januari 2009
  • Niet online

bwerg

Internettrol

oeLangOetan schreef op woensdag 17 april 2013 @ 21:48:
LinkedList heeft zeer veel pointer-indirecties & veel memory overhead, hij daardoor vele malen trager dan ArrayList voor veel operaties.
Remove in LinkedList gaat in O(1) tijdens het itereren, bij ArrayList gaat het altijd in O(n). Daarin is een ArrayList dus zéér inefficient. Het ligt er dus compleet aan waar je het voor gebruikt: in dit geval is een LinkedList gewoon geschikter tenzij ergens anders weer dingen worden gedaan waarin een ArrayList handiger is (al is een Map dus waarschijnlijk het beste hier). De bronnen die je aanhaalt zijn dan ook vrij kortzichtig. Als een LinkedList puur stom is zou hij niet in de Java-libraries zitten.
Bovendien is code die met ListIterator werkt meestal moeilijk om te begrijpen/debuggen.
Een ListIterator is toch vrij simpel. Misschien is het moeilijk te begrijpen als je het nog nooit gezien hebt, maar dat is zo met alles. Het is in ieder geval gemakkelijker te begrijpen en debuggen dan met indices gaan klooien terwijl je tegelijkertijd ook elementen uit de lijst verwijdert.

[ Voor 11% gewijzigd door bwerg op 17-04-2013 22:58 ]

Heeft geen speciale krachten en is daar erg boos over.


  • oeLangOetan
  • Registratie: Maart 2002
  • Laatst online: 31-10 09:26
bwerg schreef op woensdag 17 april 2013 @ 22:24:
[...]
Remove in LinkedList gaat in O(1) tijdens het itereren, bij ArrayList gaat het altijd in O(n). Daarin is een ArrayList dus zéér inefficient. Het ligt er dus compleet aan waar je het voor gebruikt: in dit geval is een LinkedList gewoon geschikter tenzij ergens anders weer dingen worden gedaan waarin een ArrayList handiger is (al is een Map dus waarschijnlijk het beste hier). De bronnen die je aanhaalt zijn dan ook vrij kortzichtig. Als een LinkedList puur stom is zou hij niet in de Java-libraries zitten.
Ik zeg niet dat je LinkedList nooit mag gebruiken, ik zeg gewoon dat het in 99% van de gevallen een foute keuze is omwille van leesbaarheid & ook performance. (Ik bedoel hier LinkedList als List; niet als Deque of Queue)
Je gaat toch niet beweren dat als shadooh zijn code had herschreven met een LinkedList & ListIterator ze leesbaarder was dan mijn oplossing... en al zeker niet sneller.

[ Voor 9% gewijzigd door oeLangOetan op 17-04-2013 23:31 ]


  • glvn
  • Registratie: September 2004
  • Laatst online: 16-04-2024
Jegorex schreef op woensdag 17 april 2013 @ 21:20:
[...]

Is currentPoint een double terwijl ecgData Double values heeft? Double/double.
Een Double object kan null zijn terwijl double NIET null mag zijn.
Als je dus een null waarde in de array hebt zal dat een NPE geven.

PS: Ik heb niet alle reacties doorgelezen, misschien is dit al eerder genoemd.
Dit lijkt mij ook de reden.

Is er daarnaast een reden dat je counter bij 1 start? Indices in Java starten bij 0.

  • shadooh
  • Registratie: Mei 2009
  • Laatst online: 19-06 15:07
Er gaan altijd double in, geen Doubles. Ik ben nog even bezig met wat dingen aanpassen, als het is gelukt horen jullie het. Als het niet lukt ook trouwens :)

@glennvanhaeren - Ik heb een currentPoint en een previousPoint. Voordat ik de loop in ga zet ik previousPoint op edgData.get(0)

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
HMS schreef op woensdag 17 april 2013 @ 14:30:
Daarnaast: gebruik je multithreading? Dit ruikt een beetje naar een race condition (of andere concurrency gerelateerde bug).
Dat was ook mijn eerste gedachte na 't lezen van TS:
shadooh schreef op woensdag 17 april 2013 @ 03:17:
Deze methode wordt regelmatig (paar keer per seconde) aangeroepen en er wordt ook een paar keer per seconde wat toegevoegd aan beide arraylists.
Klinkt als timers o.i.d. en die zullen allicht op een andere thread lopen. Ik zou ook gaan zoeken in concurrency (en locking toepassen om even quick-n-dirty te pinpointen of 't daar aan ligt).

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • shadooh
  • Registratie: Mei 2009
  • Laatst online: 19-06 15:07
De nieuwe methode ziet er nu zo uit. Zullen ongetwijfeld ook nog dingen voor verbeterd kunnen worden maar ik heb nog geen NPE gehad na een uurtje draaien. Ik heb een aantal methodes gesynchronized, wat ik eigenlijk niet wilde doen. Niet ideaal zo, maar het werkt zonder errors (tot nu toe :))

Java:
1
2
3
4
5
6
7
8
9
10
11
public synchronized Double[] getDataStart(long startTime){
        int i = 0;
        while(i < this.size() && times.get(i++) < startTime);
        i--;
        
        Double[] array = new Double[this.size() - i];
        
        this.subList(i, this.size()).toArray(array);
        
        return array;
    }


Edit: deze class extends een ArrayList<Double>

[ Voor 4% gewijzigd door shadooh op 18-04-2013 19:05 ]

Pagina: 1