[java] Not initialized errors, onterecht?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • verytallman
  • Registratie: Augustus 2001
  • Laatst online: 28-09 04:08
De volgende code is slechts ter voorbeeld, maar geeft aan wat ik bedoel.
code:
1
2
3
4
5
6
7
8
9
10
String s;
boolean b;

if (true) {
  b = true;
}
if (b) {
  s = "aap";
}
s.equals(""); // <- geeft een error


Het resultaat van deze code zal zijn dat s altijd "aap" zal zijn en toch geeft de compiler een error met de melding dat s mogelijk niet gezet is. Waarom zegt de compiler dat?

Acties:
  • 0 Henk 'm!

  • Ealanrian
  • Registratie: Februari 2009
  • Laatst online: 14-10 12:56
Ik denk dat de compiler die if (true) niet zo tof vind. en in dit geval zou b niet true kunnen zijn wanneer true false blijkt te zijn (als je begrijpt wat ik bedoel)

Acties:
  • 0 Henk 'm!

  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 22:17
Omdat s niet altijd geïnitialiseerd is. Als je else clausule toevoegt bij de check op b OF s standaard initialiseerd zal het geen probleem moeten zijn.

Acties:
  • 0 Henk 'm!

  • TEterBeek
  • Registratie: Juli 2010
  • Laatst online: 10-10 07:42
Waarom initialiseer je s niet waar je hem declareerd?
Java:
1
String s = "";


Anders zou je een else kunnen toevoegen aan if (b):
Java:
1
2
3
4
5
if (b) {
  s = "aap";
} else {
  s = "";
}

[ Voor 0% gewijzigd door TEterBeek op 08-03-2011 19:00 . Reden: Sluit accolade vergeten ]


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:41
Het is in z'n algemeenheid niet altijd te bewijzen of een variabele wel of niet geïnitialiseerd wordt, vandaar dat er enkele hele specifieke (en redelijk eenvoudige) voorschriften zijn om te bepalen wanneer een variabele precies als "geïnitialiseerd" telt in Java.

Als de taal daar geen eenvoudige regels voor zou vaststellen, zou een programma door de ene compiler geaccepteert worden en door een andere geweigerd worden. Dat is natuurlijk niet de bedoeling. Vandaar dat elke Java-compiler zich specifiek aan de simpele regels uit de Java-specificatie houden, en niet proberen "slim" te zijn.

Acties:
  • 0 Henk 'm!

Verwijderd

Wat Ealanrian zegt: het is nog best veel werk om te analyseren wat die code precies doet, dus zal een compiler dit meestal ook op een eenvoudige manier aanpakken. Het kan daarbij ook zo zijn dat de compiler "if (true)" pas wil gaan optimaliseren nádat er is gekeken naar uninitialized variables.

Acties:
  • 0 Henk 'm!

  • Cobalt
  • Registratie: Januari 2004
  • Laatst online: 08-10 18:51
Je zou eventueel
Java:
1
"".equals(s);
kunnen doen. Dat zou moeten werken. Dan is de String "" geïnitialiseerd waarop je dan de call naar equals() maakt en equals() checkt of het object waarmee vergeleken wordt niet null is en dus dan maakt het niet uit of s null is of dat s geïnitialiseerd is.

[ Voor 18% gewijzigd door Cobalt op 08-03-2011 19:31 ]


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Omdat de compiler niet kan (of niet gaat) bepalen dat er in deze specifieke situatie maar één pad is. Je voorbeeld is tamelijk onzinnig omdat het triviaal kan worden herschreven als:
Java:
1
2
String s = "aap";
s.equals("");

Zodra er iets ingewikkelders staat, kunnen er allerlei reden zijn waarom s niet gezet is.

Edit: zu spät...

[ Voor 4% gewijzigd door Herko_ter_Horst op 08-03-2011 19:06 ]

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • ThaNOD
  • Registratie: Februari 2005
  • Laatst online: 13-10 13:52
Ook dit zal een compiletime error geven omdat de String s als niet geïnitialiseerd beschouwd wordt. Dit specifieke voorbeeld voorkomt wel de kans op NullPointerExceptions maar in de runtime moet de TS nog komen.

Zoals al vaker genoemd is zou ik gewoon je variabele initialiseren als lege string hoewel ik zelf een null value prefereer in de meeste gevallen alleen moet je dan goed opletten dat je er niet zomaar methode op kan aanroepen.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

Toch vind ik de error een beetje raar. Als warning zou ik het nog snappen, maar de VM default-initialiaseert sowieso naar null / 0.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
abstract class Base
{
    Base() { Foo(); }
    abstract void Foo();
}

class Derived extends Base
{
    String bla = "hoi";

    void Foo()
    {
        System.out.println(bla);
    }
}

public class Test
{
    public static void main(String[] args)
    {
        new Derived();
    }
}

Ra ra wat is de output

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • xos
  • Registratie: Januari 2002
  • Laatst online: 12-09 12:41

xos

Ik ben geen java programmeur maar ik vermoed null?
En als je bla final maakt?

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
.oisyn schreef op woensdag 09 maart 2011 @ 11:47:
Toch vind ik de error een beetje raar. Als warning zou ik het nog snappen, maar de VM default-initialiaseert sowieso naar null / 0.
Ra ra wat is de output
Volgens mij is die default initialization alleen als je een variabele in de class scope declareert, en niet in een method scope

[ Voor 29% gewijzigd door Woy op 09-03-2011 12:05 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Wat Woy zegt, je zult bij local variabele altijd een error krijgen als je niet initialiseert(mits variabele daadwerkelijk wordt gebruikt ofcourse).

[ Voor 23% gewijzigd door EddoH op 09-03-2011 12:11 ]


Acties:
  • 0 Henk 'm!

  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 14-10 10:34
De reden daarvoor is dat bij het alloceren van een nieuw object wat geheugen zero-en niet zo'n punt is maar voor iedere automatische variabele je stack zero-en wel wat uitmaakt.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dan is de member 'bla' nog steeds null, alleen zal de compiler in Derived.Foo() niet die member accessen maar direct de string "hoi" pakken.
matthijsln schreef op woensdag 09 maart 2011 @ 12:20:
De reden daarvoor is dat bij het alloceren van een nieuw object wat geheugen zero-en niet zo'n punt is maar voor iedere automatische variabele je stack zero-en wel wat uitmaakt.
Aangezien de compiler nu al kan zien wanneer een variabele geïnit wordt, kan hij ook zero-initializen als dat niet het geval is.

[ Voor 43% gewijzigd door .oisyn op 09-03-2011 12:23 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

matthijsln schreef op woensdag 09 maart 2011 @ 12:20:
De reden daarvoor is dat bij het alloceren van een nieuw object wat geheugen zero-en niet zo'n punt is maar voor iedere automatische variabele je stack zero-en wel wat uitmaakt.
Kun je uitleggen waarom dat uitmaakt? Wat gebeurt er dan bij het alloceren van een object op de stack?

[ Voor 59% gewijzigd door EddoH op 09-03-2011 12:23 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

Er is geen verschil, behalve dat stack allocaties typisch veel vaker voorkomen dan heap allocaties.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Okido, kon al geen reden bedenken..

Acties:
  • 0 Henk 'm!

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
.oisyn schreef op woensdag 09 maart 2011 @ 12:22:
Aangezien de compiler nu al kan zien wanneer een variabele geïnit wordt, kan hij ook zero-initializen als dat niet het geval is.
Als ik me goed herinner is het niet default initialiseren van method-local variables een bewuste design-keuze geweest bij Java. Het voorkomt namelijk juist initialisatie-bugs als je de flow van je method niet goed doordacht hebt, of aanpast.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dus lopen mensen nu tegen een error aan en gaan ze het ding maar gewoon op 0 zetten om de error weg te krijgen. Netto resultaat is meer ergernis maar niet betere code :). Maar ik zei al, een warning kan op zich ook.

[ Voor 11% gewijzigd door .oisyn op 09-03-2011 12:38 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
.oisyn schreef op woensdag 09 maart 2011 @ 12:37:
Dus lopen mensen nu tegen een error aan en gaan ze het ding maar gewoon op 0 zetten om de error weg te krijgen. Netto resultaat is meer ergernis maar niet betere code :). Maar ik zei al, een warning kan op zich ook.
Dat is jouw mening, ik vind het een erg handige feature die me al meerdere keren voor problemen behoed heeft. Trouwens: de meeste Java programmeurs gebruiken IDEs die dergelijke warnings en errors gewoon in de IDE weergeven, dus je merkt het al bij het coden zelf.

BTW: ter referentie: http://java.sun.com/docs/...ition/html/defAssign.html
The idea behind definite assignment is that an assignment to the local variable or blank final field must occur on every possible execution path to the access. Similarly, the idea behind definite unassignment is that no other assignment to the blank final variable is permitted to occur on any possible execution path to an assignment.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dat lijkt me een vaststaand feit ja :)
.oisyn schreef op woensdag 09 maart 2011 @ 11:47:
Toch vind ik de error een beetje raar.
Trouwens: de meeste Java programmeurs gebruiken IDEs die dergelijke warnings en errors gewoon in de IDE weergeven
En als klap op de vuurpijl zal de VM het bij het inladen van een class ook nog eens controleren :P

[ Voor 55% gewijzigd door .oisyn op 09-03-2011 12:58 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • momania
  • Registratie: Mei 2000
  • Laatst online: 21:44

momania

iPhone 30! Bam!

Remus schreef op woensdag 09 maart 2011 @ 12:40:
[...]
Trouwens: de meeste Java programmeurs gebruiken IDEs die dergelijke warnings en errors gewoon in de IDE weergeven, dus je merkt het al bij het coden zelf.
Ik heb toch meer vertrouwen in programmeurs die dit soort fouten niet maken of zelf herkennen ipv zoveel op hun IDE vertrouwen :X

Neem je whisky mee, is het te weinig... *zucht*


Acties:
  • 0 Henk 'm!

  • terje7601
  • Registratie: September 2009
  • Laatst online: 08-02-2024
.oisyn schreef op woensdag 09 maart 2011 @ 12:22:
[...]

Dan is de member 'bla' nog steeds null, alleen zal de compiler in Derived.Foo() niet die member accessen maar direct de string "hoi" pakken.
Als je 'bla' final maakt, zal je toch nog steeds "null" als output krijgen? Ik begrijp even niet wat je zegt i.v.m. de compiler...in de bytecode voor Derived.Foo() zal toch gewoon gerefereerd worden naar de member 'bla'?

Acties:
  • 0 Henk 'm!

  • Jegorex
  • Registratie: April 2004
  • Laatst online: 03-09 23:24
terje7601 schreef op donderdag 10 maart 2011 @ 09:44:
[...]


Als je 'bla' final maakt, zal je toch nog steeds "null" als output krijgen? Ik begrijp even niet wat je zegt i.v.m. de compiler...in de bytecode voor Derived.Foo() zal toch gewoon gerefereerd worden naar de member 'bla'?
Waarschijnlijk bedoel je static ipv final.
Als je 'bla' static maakt dan zal er wel gewoon "hoi" staan.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

terje7601 schreef op donderdag 10 maart 2011 @ 09:44:
[...]


Als je 'bla' final maakt, zal je toch nog steeds "null" als output krijgen? Ik begrijp even niet wat je zegt i.v.m. de compiler...in de bytecode voor Derived.Foo() zal toch gewoon gerefereerd worden naar de member 'bla'?
Nee. 'bla' is final, dus die kan nooit aangepast worden. Hij wordt direct geïnitialiseerd, dus de compiler weet dat 'bla' altijd "hoi" is, en zal daardoor direct de string "hoi" gebruiken ipv te kijken naar de waarde van 'bla'.

Echter, het blijft een member die geïnitialiseerd moet worden, wat in de default constructor gebeurt. Dit is ook te zien aan de bytecode. Die constructor runt pas nadat de constructor van Base klaar is, dus ook pas nadat Derived.Foo() wordt aangeroepen.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Derived extends Base{
final java.lang.String bla;

Derived();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method Base."<init>":()V
   4:   aload_0
   5:   ldc     #2; //String hoi
   7:   putfield        #3; //Field bla:Ljava/lang/String;
   10:  return

void Foo();
  Code:
   0:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #2; //String hoi
   5:   invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

}


Interessant is om te zien dat als je de initialisatie van 'bla' uitstelt tot in de constructor, de compiler geen kennis heeft van de waarde van 'bla', en dan dus wel die member zal accessen, ookal is de daadwerkelijk gegenereerde constructor exact identiek.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Derived extends Base
{
    final String bla;
    
    {
        bla = "hoi";
    }

    void Foo()
    {
        System.out.println(bla);
    }
}

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Compiled from "Test.java"
class Derived extends Base{
final java.lang.String bla;

Derived();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method Base."<init>":()V
   4:   aload_0
   5:   ldc     #2; //String hoi
   7:   putfield        #3; //Field bla:Ljava/lang/String;
   10:  return

void Foo();
  Code:
   0:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   aload_0
   4:   getfield        #3; //Field bla:Ljava/lang/String;
   7:   invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   10:  return

}

[ Voor 51% gewijzigd door .oisyn op 11-03-2011 19:55 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1