[JAVA] Return String uit een For- en If-loop in een method

Pagina: 1 2 Laatste
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Beste Tweaker,

Ik heb een vraag over een method die ik geschreven heb. Ik ben bezig een Phonebook class te schrijven met daarin een Vector die alle personen opslaat uit mijn Person class. In de Phonebook class heb ik de volgende method:


code:
1
2
3
4
5
6
7
8
9
    //Retrieves a persons phone number given the persons name.
    public String getPhoneNumber(String nameForSearch) {
        for(int i=0; i<nextEmptyPerson; i++) {
            if (phoneBookDataBase.elementAt(i).getName().equalsIgnoreCase(nameForSearch)) {
                return phoneBookDataBase.elementAt(i).getPhone();
            }
        }
        return null;
    }


Deze geeft het telefoonnummer terug als deze voorkomt in de Vector. Hij zoekt op nameForSearch en als deze gevonden is geeft de method de String Phone terug. Voor de duidelijkheid hier mijn Person class:


code:
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
27
28
29
30
31
32
33
34
35
36
public class Person {

    /////////////////////////////////////////////////////////////////////////////
    //                                                                         //
    // Class name: Person.java                                                 //
    // Date created: 27-02-2010                                                //
    // Class function: A Person object stores a persons name and phone number //
    //   in two type String data fields.                                       //
    //                                                                         //
    /////////////////////////////////////////////////////////////////////////////
    
    private String name;
    private String phone;

    //Creates a Person object, storing its arguments in the new objects data fields.
    public Person (String n, String p) {
        name = n;
        phone = p;
    }
        
    public String getName() {
        return this.name;
    }

    public String getPhone() {
        return this.phone;
    }
    
    public void changePhone(String newPhone) {
        this.phone = newPhone;
    }

    public String toString() {
        return this.name + " " + this.phone;
    }
}


Nu is mijn vraag: waarom geeft de method een error als ik de regel "return null;" weglaat? Deze heb ik toegevoegd als tussenoplossing. Ik wil eigenlijk niet werken met een tijdelijke variabele. Het moet toch ook mogelijk zijn om deze regel weg te laten? Ik test mijn programma's in eclipse en krijg dan de volgende error:
This method must return a result of type String
Ik hoop dat iemand hier mij kan helpen met een oplossing. Dit is mijn eerste post hier, dus als deze niet zo is als die hoort.. geef maar feedback! :D

Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 10:17
Als je die regel weg laat wordt er niets gereturned als nameforsearch niet gevonden wordt in je vector.

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • Tharulerz
  • Registratie: April 2009
  • Laatst online: 10-04 05:16
Die Null returnen op zich is dus niet fout. Je moet dan op de plaats waar je die getPhoneNumber aanroept enkel nog checken of hij null terugkreeg, en zoja, een foutboodschap tonen.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
sig69 schreef op maandag 01 maart 2010 @ 16:42:
Als je die regel weg laat wordt er niets gereturned als nameforsearch niet gevonden wordt in je vector.
Maar dan krijg ik ook de eerdergenoemde foutmelding.
Tharulerz schreef op maandag 01 maart 2010 @ 16:46:
Die Null returnen op zich is dus niet fout. Je moet dan op de plaats waar je die getPhoneNumber aanroept enkel nog checken of hij null terugkreeg, en zoja, een foutboodschap tonen.
Bedoel je dit?

code:
1
2
3
4
5
6
7
8
9
10
11
    public String getPhoneNumber(String nameForSearch) {
        for(int i=0; i<nextEmptyPerson; i++) {
            if (phoneBookDataBase.elementAt(i).getName().equalsIgnoreCase(nameForSearch)) { 
                if (phoneBookDataBase.elementAt(i).getPhone().equalsIgnoreCase(null)) {
                    return "No results";
                } else {
                    return phoneBookDataBase.elementAt(i).getPhone();
                }
            }
        }
    }


Ik krijg dan nog steeds error:
This method must return a result of type String

Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Omdat er nog steeds een if() omheen staat zonder else. De compiler kan niet garanderen dat er te allen tijde aan de if() wordt voldaan waardoor jouw return-code wordt aangeroepen, dus zegt 'ie dat jij dat zelf moet controleren, hetzij met een else, hetzij met nog een return na het if-blok.

[ Voor 12% gewijzigd door CodeCaster op 01-03-2010 17:12 ]

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 13:41

CoolGamer

What is it? Dragons?

Er is niet gegarandeerd dat wat binnen de for-loop staat uitgevoerd wordt. Wanneer het aantal personen 0 is wordt de inhoudt van de for-loop niet uitgevoerd en wordt het einde van de methode bereikt voordat er een return-statement is uitgevoerd.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
CodeCaster schreef op maandag 01 maart 2010 @ 17:06:
Omdat er nog steeds een if() omheen staat zonder else. De compiler kan niet garanderen dat er te allen tijde aan de if() wordt voldaan waardoor jouw return-code wordt aangeroepen, dus zegt 'ie dat jij dat zelf moet controleren, hetzij met een else, hetzij met nog een return na het if-blok.
Maar als ik een else toevoeg, als in de volgende code, dan wordt het nog steeds niet goedgekeurd. En hier is er altijd een mogelijkheid toch? Als er iets gevonden wordt, return getPhone() en als dat niet zo is return null.

code:
1
2
3
4
5
6
7
8
9
    public String getPhoneNumber(String nameForSearch) {
        for(int i=0; i<nextEmptyPerson; i++) {
            if (phoneBookDataBase.elementAt(i).getName().equalsIgnoreCase(nameForSearch)) { 
                return phoneBookDataBase.elementAt(i).getPhone();
            } else {
                return null;
            }
        }
    }
TheCoolGamer schreef op maandag 01 maart 2010 @ 17:13:
Er is niet gegarandeerd dat wat binnen de for-loop staat uitgevoerd wordt. Wanneer het aantal personen 0 is wordt de inhoudt van de for-loop niet uitgevoerd en wordt het einde van de methode bereikt voordat er een return-statement is uitgevoerd.
Dus eigenlijk is de "return null;" altijd nodig als je op deze manier werkt met een for-loop?

[ Voor 19% gewijzigd door Verwijderd op 01-03-2010 17:21 ]


Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 13:41

CoolGamer

What is it? Dragons?

Verwijderd schreef op maandag 01 maart 2010 @ 17:20:
[...]


Dus eigenlijk is de "return null;" altijd nodig als je op deze manier werkt met een for-loop?
Ja, of je zou een exceptie kunnen opgooien.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • Castor385
  • Registratie: Mei 2005
  • Laatst online: 14:31
Je kunt er dit van maken als de oplossing je niet aan staat:

Java:
1
2
3
4
5
6
7
8
9
10
11
    //Retrieves a persons phone number given the persons name.
    public String getPhoneNumber(String nameForSearch) {
        String phoneNumber = null;
        for(int i=0; i<nextEmptyPerson; i++) {
            if (phoneBookDataBase.elementAt(i).getName().equalsIgnoreCase(nameForSearch)) {
                phoneNumber = phoneBookDataBase.elementAt(i).getPhone();
                break;
            }
        }
        return phoneNumber;
    }


Edit: was bullshit wat hier stond.

[ Voor 75% gewijzigd door Castor385 op 01-03-2010 17:32 ]

Study everything, You'll find something you can use


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Dat is vooral handig als je de laatste match wilt hebben: dan moet je de break weglaten. In dit geval dus neit handig.

Acties:
  • 0 Henk 'm!

  • DEiE
  • Registratie: November 2006
  • Laatst online: 18-09 15:15
MBV schreef op maandag 01 maart 2010 @ 17:57:
Dat is vooral handig als je de laatste match wilt hebben: dan moet je de break weglaten. In dit geval dus neit handig.
Op het moment dat er meerdere mensen met dezelfde naam voorkomen, is het ontwerp sowieso niet goed, omdat je dan geen controle hebt over welke persoon je terugkrijgt. Je zal dan óf een collectie moeten teruggeven, of moeten afdwingen dat de naam van een persoon uniek is.

Namen uniek is niet handig (bij een grote telefoongids zal Henk de Vries waarschijnlijk vaker voorkomen), ik stel de TS dan ook voor om ipv een enkele string een collectie van strings terug te laten geven

Acties:
  • 0 Henk 'm!

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 10:17
Ik stel voor dat de TS het boek Java voor beginners erbij pakt (niet lullig bedoeld hoor, maar het is wel erg basic kennis..)

Roomba E5 te koop


Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Verwijderd schreef op maandag 01 maart 2010 @ 17:20:
[...]
Maar als ik een else toevoeg, als in de volgende code, dan wordt het nog steeds niet goedgekeurd. En hier is er altijd een mogelijkheid toch? Als er iets gevonden wordt, return getPhone() en als dat niet zo is return null.

code:
1
2
3
4
5
6
7
8
9
    public String getPhoneNumber(String nameForSearch) {
        for(int i=0; i<nextEmptyPerson; i++) {
            if (phoneBookDataBase.elementAt(i).getName().equalsIgnoreCase(nameForSearch)) { 
                return phoneBookDataBase.elementAt(i).getPhone();
            } else {
                return null;
            }
        }
    }
Niet waar. Als nextEmptyPerson kleiner of gelijk is aan nul, dan wordt de hele for niet uitgevoerd en heb je alsnog geen return.

Je garandeert dat deze methode een String terug geeft als resultaat. Alle execution-paths die mogelijk zijn moeten dan daar aan voldoen.

Als nextEmptyPerson kleiner of gelijk is aan nul, dan geeft je methode een void terug (automatische return aan het einde van de methode). Dat kan niet, want het moet een String zijn.

Dus ga altijd goed na hoeveel execution-paths er kunnen zijn binnen je methode en zorg er voor dat elk pad de juiste return-waarde heeft.

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Verwijderd schreef op maandag 01 maart 2010 @ 17:20:
[...]
Maar als ik een else toevoeg, als in de volgende code, dan wordt het nog steeds niet goedgekeurd. En hier is er altijd een mogelijkheid toch? Als er iets gevonden wordt, return getPhone() en als dat niet zo is return null.

code:
1
2
3
4
5
6
7
8
9
    public String getPhoneNumber(String nameForSearch) {
        for(int i=0; i<nextEmptyPerson; i++) {
            if (phoneBookDataBase.elementAt(i).getName().equalsIgnoreCase(nameForSearch)) { 
                return phoneBookDataBase.elementAt(i).getPhone();
            } else {
                return null;
            }
        }
    }
Joh, als je vector 0 elementen bevat dan wordt die hele loop toch niet uitgevoerd? Een methode met een niet-void returntype MOET hoe dan ook iets van dat type returnen, of een exception gooien. Enorm basic programmeerwerk.
Dus eigenlijk is de "return null;" altijd nodig als je op deze manier werkt met een for-loop?
Een methode die niet als returntype void heeft moet in alle mogelijke codepaden of een object van dat type (null mag ook) teruggeven, of een exception gooien.

Wat mag:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public String getFoo()
{
  for(int i = 0;i < list.size();i++)
    if(list.get(i).getBar().equal("Something")
      return "Found!";
  }
  return "Not found :(";
}

public String getFoo()
{
  for(int i = 0;i < list.size();i++)
    if(list.get(i).getBar().equal("Something")
      return "Found!";
  }
  throw new RuntimeException("YELP!");
}


Wat niet mag:

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
//List kan leeg zijn of element niet gevonden.
public String getFoo()
{
  for(int i = 0;i < list.size();i++)
    if(list.get(i).getBar().equal("Something")
      return "Found!";
  }
}

//Andere cases zorgen dat de case niet 'gevangen' wordt.
public String getFoo()
{
  switch(<something>)
    case 1: return "Foo";
    case 2: return "Bar";
  }
}

//Geen else dus eind kan bereikt worden.
public String getFoo()
{
  if(<something>)
    return "Foo";
  else if(<something else>)
    return "Bar";
}


En zo zijn er wel meer voorbeelden te verzinnen. Hoop dat je nu snapt dat een dergelijke methode in alle paden gewoon iets moet returnen of een exception moet gooien.
TheCoolGamer schreef op maandag 01 maart 2010 @ 17:13:
Er is niet gegarandeerd dat wat binnen de for-loop staat uitgevoerd wordt.
Nee, er wordt niet gegarandeerd dat elk code pad een waarde returned. Dat is ook letterlijk wat de compilermelding je vertelt.

[ Voor 6% gewijzigd door Hydra op 10-03-2010 12:02 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Nu online

Creepy

Tactical Espionage Splatterer

Alsnog een tikje door naar PRG.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Styxxy
  • Registratie: Augustus 2009
  • Laatst online: 19-09 10:57
Niet geheel relevant voor je probleem, maar toch even een opmerking omtrent de RETURN in een FOR-lus. In mijn opleiding (informatica) wordt het werkelijk erin gedramd om geen RETURN in een FOR-lus te doen omdat dit niet geheel netjes is. Bij een FOR-lus constructie, wordt er namelijk verwacht dat je een vast aantal iteraties uitvoert; met een RETURN erin, breek je eigenlijk die FOR-lus op. Een properdere oplossing is een WHILE of een DO-WHILE constructie te gebruiken.

Voor jouw problematiek zie ik eigenlijk twee oplossingen. Ten eerste is er de oplossing van Exceptions al gegeven hierboven (je gooit een Exception indien niet gevonden). Ten tweede, mijn voorkeur, is eigenlijk een tweede "out" parameter in de methode te steken en de methode zelf een BOOLEAN terug te laten geven.

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Styxxy schreef op woensdag 10 maart 2010 @ 14:02:
Niet geheel relevant voor je probleem, maar toch even een opmerking omtrent de RETURN in een FOR-lus. In mijn opleiding (informatica) wordt het werkelijk erin gedramd om geen RETURN in een FOR-lus te doen omdat dit niet geheel netjes is. Bij een FOR-lus constructie, wordt er namelijk verwacht dat je een vast aantal iteraties uitvoert; met een RETURN erin, breek je eigenlijk die FOR-lus op. Een properdere oplossing is een WHILE of een DO-WHILE constructie te gebruiken.
Een for lus gebruik je als je van te voren weet hoeveel iteraties je gaat doen, een while gebruik je als je dat niet weet (foreach ff buiten beschouwing latend). Ik vind het volslagen onzin om geen return te doen maar moeilijk te doen met een while terwijl je een simpele vector doorloopt.

Zeg zelf:

Java:
1
2
3
4
5
for (int i = 0;i < list.size();i++)
{
  if(list.get(i).equals("WhateverIWant"))
    return list.get(i);
}


of

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Enumerator en = list.getEnumerator();
Object current;
boolean found = false;
while(en.hasMoreElements())
{
  current = en.nextElement();
  if(current.equals("WhateveIWant")
  {
   found = true;
   break;
  }
}
if(found)
  return current;
else
  return false;


Doe mij die eerste maar...

https://niels.nu


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

out-parameters in Java?
http://www.javapractices.com/topic/TopicAction.do?Id=37

In java geef ik altijd een null terug, die je vervolgens kan checken met !null net zoals je met je boolean !false kan checken. Output parameter kan handig zijn, maar vind ik hier wat onnodig.

@hierboven: ja, in dit geval wel. Het is wel verstandig om die constructies te vermijden: zodra je structuur iets complexer wordt is het al snel ontestbaar door het grote aantal code-paden.
Zie ook: Wikipedia: Essential complexity

[ Voor 35% gewijzigd door MBV op 10-03-2010 14:37 ]


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
MBV schreef op woensdag 10 maart 2010 @ 14:25:
@hierboven: ja, in dit geval wel. Het is wel verstandig om die constructies te vermijden: zodra je structuur iets complexer wordt is het al snel ontestbaar door het grote aantal code-paden.
Zie ook: Wikipedia: Essential complexity
Tuurlijk, het moet geen codebrij worden, maar het is onzin dat je perse meerdere returnpaden moet voorkomen als het alternatief niet gewoon onduidelijker wordt. Voorbeeld:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
if(<iets simpels>)
{
   return null;
}
else if(<iets anders>)
{
  return "Foo";
}
else
{
  return "Bar";
}


versus

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Object result;
if(<iets simpels>)
{
   result =  null;
}
else if(<iets anders>)
{
  result =  "Foo";
}
else
{
  result = "Bar";
}
return result;


Eerste stuk is gewoon simpeler en IMHO daardoor makkelijker te lezen, maar sommige puristen vinden het per definitie slechte code omdat er "meerdere returnpaden" zijn. Code moet in de eerste plaats voor een andere persoon leesbaar zijn, dat is de reden dat er coding guidelines zijn, maar het zijn guidelines, geen wetten.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Macros
  • Registratie: Februari 2000
  • Laatst online: 15-05 16:29

Macros

I'm watching...

Hydra schreef op woensdag 10 maart 2010 @ 14:52:
[...]


Tuurlijk, het moet geen codebrij worden, maar het is onzin dat je perse meerdere returnpaden moet voorkomen als het alternatief niet gewoon onduidelijker wordt. Voorbeeld:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
if(<iets simpels>)
{
   return null;
}
else if(<iets anders>)
{
  return "Foo";
}
else
{
  return "Bar";
}


versus

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Object result;
if(<iets simpels>)
{
   result =  null;
}
else if(<iets anders>)
{
  result =  "Foo";
}
else
{
  result = "Bar";
}
return result;


Eerste stuk is gewoon simpeler en IMHO daardoor makkelijker te lezen, maar sommige puristen vinden het per definitie slechte code omdat er "meerdere returnpaden" zijn. Code moet in de eerste plaats voor een andere persoon leesbaar zijn, dat is de reden dat er coding guidelines zijn, maar het zijn guidelines, geen wetten.
Amen!

"Beauty is the ultimate defence against complexity." David Gelernter


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

De reden waarom bij informatica opleidingen over het algemeen aangeleert wordt om 1 return te gebruiken is omdat een (wiskundig)correctheidsbewijs voor een functie met meerdere return methoden enorm veel lastiger is.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Janoz schreef op woensdag 10 maart 2010 @ 15:10:
De reden waarom bij informatica opleidingen over het algemeen aangeleert wordt om 1 return te gebruiken is omdat een (wiskundig)correctheidsbewijs voor een functie met meerdere return methoden enorm veel lastiger is.
Ik heb een donkerbruin vermoeden dat het HBO informatica betreft en daar ben je niet bezig met correctheidsbewijzen voor een functie. Daarnaast ben je als developer in je dagelijks werk als het goed is meer bezig met duidelijke code schrijven dan met code die wiskundig correct is. Code met bugs is vaak ook wiskundig correct ;)

https://niels.nu


Acties:
  • 0 Henk 'm!

  • YakuzA
  • Registratie: Maart 2001
  • Niet online

YakuzA

Wat denk je nou zelluf hey :X

Hmm,

Eigenlijk roept de OP van de TS al een vraag bij mij op die niemand stelt:
Waarom wordt er geen (Dictionary/HashMap/HashTable) gebruikt?

als je een hashmap maakt van persoonnaam naar persoonobject dan stelt de functie niet zoveel meer voor
(pseudocode zonder contains/null check etc)
Java:
1
2
Person p = phoneBookDataBase(nameForSearch);
return p.getPhone();


Binnen je huidige ontwerp kan een persoon ook maar 1 telefoonnummer hebben, maar dat is vast een bewuste keuze ;)

[ Voor 13% gewijzigd door YakuzA op 10-03-2010 15:31 ]

Death smiles at us all, all a man can do is smile back.
PSN


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

Hydra schreef op woensdag 10 maart 2010 @ 15:11:
[...]


Ik heb een donkerbruin vermoeden dat het HBO informatica betreft en daar ben je niet bezig met correctheidsbewijzen voor een functie. Daarnaast ben je als developer in je dagelijks werk als het goed is meer bezig met duidelijke code schrijven dan met code die wiskundig correct is. Code met bugs is vaak ook wiskundig correct ;)
Oh, begrijp me niet verkeerd. Ikzelf spring gewoon binnen de for lus eruit. Wiskundige bewijzen is een academische gimick en als je methode te onoverzichtelijk wordt bij meerdere returns dan was hij in de eerste plaats al veel te groot.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Hydra schreef op woensdag 10 maart 2010 @ 15:11:
Ik heb een donkerbruin vermoeden dat het HBO informatica betreft en daar ben je niet bezig met correctheidsbewijzen voor een functie. Daarnaast ben je als developer in je dagelijks werk als het goed is meer bezig met duidelijke code schrijven dan met code die wiskundig correct is. Code met bugs is vaak ook wiskundig correct ;)
Op de TH Rijswijk deden we dat wel :P En code die 'wiskundig correct' is* voldoet aan de specs, en is dus bug-vrij, onder de aanname dat je compiler (en eventuele library-functies) correct is**. Ik probeer trouwens vrij vaak wiskundig correcte code te schrijven, zonder dat ik dat bewijs.
Janoz schreef op woensdag 10 maart 2010 @ 15:10:
De reden waarom bij informatica opleidingen over het algemeen aangeleert wordt om 1 return te gebruiken is omdat een (wiskundig)correctheidsbewijs voor een functie met meerdere return methoden enorm veel lastiger is.
misschien ook om het de 'regel' te laten zijn, en andere situaties (one-liner-achtigen) de 'uitzondering'.

*) of beter gezegd: code waarvoor je wiskundig kunt bewijzen dat het aan de specs voldoet
**) mijn definitie van 'bug' is een afwijking van het verwachtte gedrag, en de specs moeten dat verwachtte gedrag beschrijven.

[edit]
Janoz schreef op woensdag 10 maart 2010 @ 15:33:
[...]

Oh, begrijp me niet verkeerd. Ikzelf spring gewoon binnen de for lus eruit. Wiskundige bewijzen is een academische gimick en als je methode te onoverzichtelijk wordt bij meerdere returns dan was hij in de eerste plaats al veel te groot.
Tja, soms vallen dingen slecht uit elkaar te trekken, en wordt het daar alleen onoverzichtelijker van. En zo nu en dan overkomt het me dat ik denk "Waarom wordt deze code niet uitgevoerd?" Het antwoord mag je raden ;)

[ Voor 51% gewijzigd door MBV op 10-03-2010 15:39 ]


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Janoz schreef op woensdag 10 maart 2010 @ 15:33:
Oh, begrijp me niet verkeerd. Ikzelf spring gewoon binnen de for lus eruit. Wiskundige bewijzen is een academische gimick en als je methode te onoverzichtelijk wordt bij meerdere returns dan was hij in de eerste plaats al veel te groot.
Zeker. Ik heb in mijn eerste stage veel geleerd van mijn mentor ter plaatse. Was nogal een smalltalk / extreme programming guru en ik heb van die kerel volgens mij meer geleerd dan van m'n hele HBO-I (toen nog HIO) opleiding ;) Zoals dat een methode bijvoorbeeld nooit langer dan 1 scherm mag zijn. Als 'ie langer wordt is dat meestal een teken dat je moet refactoren.
MBV schreef op woensdag 10 maart 2010 @ 15:35:
Op de TH Rijswijk deden we dat wel :P En code die 'wiskundig correct' is* voldoet aan de specs, en is dus bug-vrij, onder de aanname dat je compiler (en eventuele library-functies) correct is**. Ik probeer trouwens vrij vaak wiskundig correcte code te schrijven, zonder dat ik dat bewijs.
Euh? AFAIK betekent "wiskundige correctheid" van code niks meer en niks minder dat het algorithme wiskundig doet wat het moet doen, maar heeft het niks te maken met wat het functioneel zou moeten doen. Voorbeeld van "wiskundig correcte code":

Java:
1
2
3
4
public int returnTwo()
{
  return 1;
}

[ Voor 33% gewijzigd door Hydra op 10-03-2010 15:43 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Wiskundige correctheid wordt vaak mee bedoeld dat als wordt voldaan aan de pre-condities, de functie ervoor zorgt dat wordt voldaan aan de post-condities.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * pre: x = 5
 * post: return = 10
 */
public int returnTwo(int x)  {
  //voldoet:
  return x + x;
}
public int returnTwo(int x) {
  //voldoet niet:
  return 2;
}

Jouw code is wiskundig correct omdat je geen specs hebt gegeven, en dan krijg je een uitspraak over een leeg domein: voor alle inputs die voldoen aan de pre-conditie voldoet jouw code aan alle eisen.
Wikipedia: Hoare logic

Wiskundige correctheid is heel handig als je uitspraken wilt doen over algoritmen, maar minder handig voor UI's. Zoek maar eens een voorbeeldje: correctness quicksort

[ Voor 13% gewijzigd door MBV op 10-03-2010 15:55 ]


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

Wat ik met met wiskundig bewijzen bedoelde was wat ik ergens vorig jaar bij dit vak heb gehad. Zoals je ziet is de hoeveelheid wiskunde een stuk groter dan de bijbehorende code (check de opgaven en uitwerking van toets1)

(wat trouwens inderedaad overeenkomt met de aangehaalde wikipedia links :) )

[ Voor 12% gewijzigd door Janoz op 10-03-2010 16:08 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Ik heb dan geen bachelor gedaan op de TU/e, maar het schijnt dat in het schakeltraject vanaf het HBO er al meer wiskundig-bewijs-vakken zitten dan je op veel andere uni's krijgt. 't is een beetje het paradepaardje van de TU/e ;) En ik had even geen zin om een leuk bachelorvak uit te zoeken.

edit:
Ik zie net tot mijn stomme verbazing dat ze die vakken uit het schakelprogramma hebben gegooid :S

[ Voor 27% gewijzigd door MBV op 10-03-2010 16:24 ]


Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

Hydra schreef op woensdag 10 maart 2010 @ 14:23:
Zeg zelf:

Java:
1
2
3
4
5
for (int i = 0;i < list.size();i++)
{
  if(list.get(i).equals("WhateverIWant"))
    return list.get(i);
}


of

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Enumerator en = list.getEnumerator();
Object current;
boolean found = false;
while(en.hasMoreElements())
{
  current = en.nextElement();
  if(current.equals("WhateveIWant")
  {
   found = true;
   break;
  }
}
if(found)
  return current;
else
  return false;


Doe mij die eerste maar...
Ten eerste lijkt het me niet slim om false te laten autoboxen naar een Object. Ten tweede vind ik de vergelijking niet helemaal eerlijk. Dit ziet er al wat mooier uit:
Java:
1
2
3
4
5
6
7
8
9
10
Object current = null; 
boolean found = false; 
Iterator it = list.iterator(); 
while(it.hasNext() && !found) 
{ 
    current = it.next(); 
    if (current.equals("WhateverIWant"))
        found = true; 
} 
return found ? current : null; 

Of voor de for-mensen:
Java:
1
2
3
4
5
6
7
8
9
Object current = null; 
boolean found = false; 
for (Iterator it = list.iterator(); it.hasNext() && !found;)
{
    current = it.next();
    if (current.equals("WhateverIWant"))
        found = true; 
}
return found ? current : null; 


Of je propt het itereren weg in een library zodat niemand ooit zeurt of er wel of geen meerdere returns worden gebruikt:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
public class CollectionUtils {
    public static <E> E findFirst(Collection<E> items, Predicate<? super E> p) {
        for (E item : items)
            if (p.apply(item))
                return item;
        return null;
    }
}

public interface Predicate<T> {
    public boolean apply(T x); 
}


Om vervolgens zonder zorgen dit te kunnen typen:
Java:
1
2
3
4
5
6
stuff = CollectionUtils.findFirst(list, new Predicate<Integer>() {
    @Override
    public boolean apply(Integer x) {
        return x.equals("TheDroidsImLookingFor");
    }
});

:p

[ Voor 0% gewijzigd door RayNbow op 10-03-2010 17:34 . Reden: Codefix :p ]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
RayNbow schreef op woensdag 10 maart 2010 @ 16:39:
Ten eerste lijkt het me niet slim om false te laten autoboxen naar een Object.
Was ook niet de bedoeling. Heb de code uit de losse pols geschreven en dat was gewoon een foutje, bedoeling was daar null te returnen :)
Ten tweede vind ik de vergelijking niet helemaal eerlijk. Dit ziet er al wat mooier uit:
[code=Java]
Ja het was niet de 'kortste' manier maar dan nog is de jouwe complexer dan een simpele for-loop met een return. Gaat me er gewoon om dat het onzin is dat dat niet met een for-loop zou mogen, lijkt me duidelijk.

Hij kan nog simpeler:
Java:
1
2
3
4
5
6
7
8
9
Object current = null; 
Iterator it = list.iterator(); 
while(it.hasNext()) 
{ 
    current = it.next(); 
    if (current.equals("WhateverIWant"))
        break; 
} 
return current;


Blijft langer dan de for-loop :)

[ Voor 16% gewijzigd door Hydra op 10-03-2010 16:57 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

Hydra schreef op woensdag 10 maart 2010 @ 16:55:
Hij kan nog simpeler:
Java:
1
2
3
4
5
6
7
8
9
Object current = null; 
Iterator it = list.iterator(); 
while(it.hasNext()) 
{ 
    current = it.next(); 
    if (current.equals("WhateverIWant"))
        break; 
} 
return current;
Nu krijg je echter de anti-break beweging met brandende fakkels achter je aan. ;)

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
RayNbow schreef op woensdag 10 maart 2010 @ 17:05:
Nu krijg je echter de anti-break beweging met brandende fakkels achter je aan. ;)
Ik weet 't, die kunnen net zo goed de digitus medius krijgen :)

https://niels.nu


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

@Hydra: wat gebeurt er bij jouw code als er wel elementen in de verzameling zitten, maar geen enkele aan de conditie voldoet?
spoiler:
dan return je de laatste, foei!

@RayNbow:
Java:
1
2
3
4
5
6
7
8
9
Object returnValue = null; 
Iterator it = list.iterator(); 
while(it.hasNext()) 
{ 
    Object temp = it.next(); 
    if (temp.equals("WhateverIWant"))
        returnValue = temp;
} 
return returnValue;

Welke groep fakkels krijg ik nu achter me aan? :+
spoiler:
Ik weet niet wat er in het Object zit, dus daar kan ik niks aan doen.
Temp is prima beschrijvend: hij wordt alleen op de 2 regels na de declaratie gebruikt, en is dus 100% tijdelijk.
Hij is snel zat: runtime blijft O(n), net als het eerste voorbeeld. Verwachtte runtime is hooguit 2x zo lang, verwaarloosbaar.
Wiskundig bewijs heeft weinig zin tot iemand me de officiele semantiek van de java library geeft.
Ik hoop dat ik nu alle fakkels heb gehad :P

[ Voor 10% gewijzigd door MBV op 10-03-2010 17:29 ]


Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

MBV schreef op woensdag 10 maart 2010 @ 17:27:
@RayNbow:
Java:
1
2
3
4
5
6
7
8
9
Object returnValue = null; 
Iterator it = list.iterator(); 
while(it.hasNext()) 
{ 
    Object temp = it.next(); 
    if (temp.equals("WhateverIWant"))
        returnValue = temp;
} 
return returnValue;

Welke groep fakkels krijg ik nu achter me aan? :+
Geen idee... de mierenneukende consistente naamgeving beweging misschien? :+ Een enge groep fanatiekelingen die vindt dat als je een naam als it gebruikt, dat je dan ook ret en tmp moet gebruiken. :p

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Ah, die 'it' was ik vergeten. Ik gebruik altijd temp, nooit tmp, en had eerst 'rv' als returnValue staan (die ik ook veel gebruik: visitor die altijd alles moet doorlopen, en de laatste return-value moet worden teruggegeven, met rv in de automatisch gegenereerde code). Maar ik kon al een schoonheidscommissie verzinnen die rv niet beschrijvend genoeg vond :P

Acties:
  • 0 Henk 'm!

  • Apache
  • Registratie: Juli 2000
  • Laatst online: 16-09 10:29

Apache

amateur software devver

Zijn er echt mensen die vaak null return en daar constant op lopen te checken in "echte" applicaties?

Das toch gewoon vragen om NPE exceptions wanneer je eens niet op null checked? Je code word ranzig van al die null checks. Dus oftewel inderdaad een exception returnen, maar in dit geval lijkt mij dit exception driven flow, of wat ik persoonlijk prefereer: Wikipedia: Null Object pattern

Verder, probeer eens OO te werken en niet zomaar strings te returnen, je zoekt adhv de persoonsnaam een telefoonnr. Wat als er ooit iets extra moet getoond worden in de zoek resultaten, bvb getMobileNumber() getWorkNumber() getHomeNumber(), ga je dan een array van strings returnen? ga je 3 methodes copy/pasten maar met een ander veld en dus ook 3x zo vaak die loop uitvoeren?

Return nou maar gewoon terug het hele parent object (Person in dit geval) en wat je er ook aan toevoegd van properties je kan er meteen aan nadien.

If it ain't broken it doesn't have enough features


Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

Apache schreef op woensdag 10 maart 2010 @ 18:04:
Zijn er echt mensen die vaak null return en daar constant op lopen te checken in "echte" applicaties?

Das toch gewoon vragen om NPE exceptions wanneer je eens niet op null checked? Je code word ranzig van al die null checks.
Exceptions zijn daarentegen ook niet zaligmakend, want dan moet je je code volsprenkelen met try/catches?

Het liefste zie ik null references verdwijnen (Tony Hoare ook waarschijnlijk, maar die talk moet ik nog kijken) en zie ik liever iets als Nullable<T> waarbij het mogelijke null-zijn expliciet in het type staat.

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Apache schreef op woensdag 10 maart 2010 @ 18:04:
Zijn er echt mensen die vaak null return en daar constant op lopen te checken in "echte" applicaties?
Als een collection een bepaald element niet bevat geeft die 'null' terug. Het gebruiken van Exceptions (die duur zijn!) voor dingen die geen fouten zijn, dat is IMHO pas echt slecht. In princiepe zouden exceptions niet voor mogen komen, het zijn letterlijk uitzonderingen.

Ik ben het er overigens wel mee eens dat 'null' waarden vaak teruggegeven worden als er wel een exception gegooid zou moeten worden zoals als een file niet gevonden wordt of een integer input waarde invalid characters bevat, en dat is ook fout.

Ik schrijf m'n code zo dat ik niet elke keer op nulls hoef te checken gewoon door zeker te weten dat een object altijd een instance heeft, of als ik er niet uit kom een exception gooi. Checken op nulls doe je dus eigenlijk alleen bij collections e.d.

Als ik een library schrijf en iemand geeft een null waarde aan een van m'n methoden waar dat niet mag, dan krijgt 'ie gewoon een NPE om z'n oren, maar zo hoort 't ook IMHO.
RayNbow schreef op woensdag 10 maart 2010 @ 18:21:
Exceptions zijn daarentegen ook niet zaligmakend, want dan moet je je code volsprenkelen met try/catches?
Het grootste probleem is dat ze gewoon duur zijn. Voor elke exception moet een stacktrace opgebouwd worden. Voorbeeld van fout gebruik van Exceptions:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
public boolean isInteger(String value)
{
  try
  {
     Integer.parseInt(value);
     return true;
  }
  catch(NumberFormatException e)
  {
     return false;
  }
}

[ Voor 19% gewijzigd door Hydra op 10-03-2010 18:28 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Apache
  • Registratie: Juli 2000
  • Laatst online: 16-09 10:29

Apache

amateur software devver

Of exceptions hier fout zijn hangt gewoon van zijn requirements af.

Indien men altijd verwacht dat er een resultaat is is niets vinden effectief een exception.

Indien hij "niets" mag returnen is null of liever een Nullable versie gereturned worden.

Dat ze duur zijn mag weinig boeien, dat valt bij mij onder premature optimizations en gaat pas echt een rol spelen als dat een hotspot in je code is die veel gecalled word.

Een gelijkaardig voorbeeld is dit:
entityManager.load(MyEntity.class, 10L);
entityManager.find(MyEntity.class, 10L);

load betekend effectief dat object laden en dan een exception is het niet geladen kan worden, find is gewoon zoeken, en vind hij het niet dan is het null.

Natuurlijk zo'n zaken zijn nooit zwart wit, en ik ben de NPE's van collega's een beetje beu :)

bvb inputString.equals("someHardcodedCrap") doe dan al op z'n minst "someHardcodedCrap".equals(inputString) dat zal nooit NPE's geven.

If it ain't broken it doesn't have enough features


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

RayNbow schreef op woensdag 10 maart 2010 @ 18:21:
[...]

Exceptions zijn daarentegen ook niet zaligmakend, want dan moet je je code volsprenkelen met try/catches?

Het liefste zie ik null references verdwijnen (Tony Hoare ook waarschijnlijk, maar die talk moet ik nog kijken) en zie ik liever iets als Nullable<T> waarbij het mogelijke null-zijn expliciet in het type staat.
Ik zie het liefste het uitroepteken uit Spec#. Of misschien een vraagteken, met als groot nadeel dat alle bestaande code in 1 klap onbruikbaar is.

In dit geval zie ik toch duidelijk een voordeel voor null returnen:
Java:
1
2
3
4
5
6
7
8
Person result = myCollection.getByName(x);
if (result != null) {
  doSomething(result);
}
else {
  // vaak geen else, omdat er bij geen resultaat niks gedaan hoeft te worden
  showWarning("nothing found");
}

versus:
Java:
1
2
3
4
5
6
7
8
try {
  Person result = myCollection.getByName(x);
  doSomething(result);
}
catch (NoSuchElementException e) {
  //kan niet weggelaten worden
  showWarning("nothing found");
}

Bij de eerste is de flow al een stuk duidelijker: je ziet direct wat er gebeurt zodra het element niet gevonden is. Stel nu dat ik 3 gegevens ophaal uit de verzameling: result1, result2 en result3, en alle resultaten onder elkaar wil opsommen op een vergelijkbare manier. Dan krijg je 3 try/catch blocks, 3 extra booleans (gevonden ja/nee), en alsnog een if/else onderaan in de weergave.

En Strings lijkt mij omdat het hier een dom voorbeeld is, bij zinnige code zal je al snel een data-container gebruiken.

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

Apache schreef op woensdag 10 maart 2010 @ 20:08:
bvb inputString.equals("someHardcodedCrap") doe dan al op z'n minst "someHardcodedCrap".equals(inputString) dat zal nooit NPE's geven.
Dit hangt echter ook af van de situatie en of je verwacht dat inputString wel of niet null is. Als je eist dat inputString nooit null is, dan wil je juist dat je code faalt in plaats van vrolijk doorhobbelt.

(Het is natuurlijk nog beter als je deze eisen/aannames documenteert d.m.v. asserts)
MBV schreef op woensdag 10 maart 2010 @ 20:20:
[...]

Ik zie het liefste het uitroepteken uit Spec#. Of misschien een vraagteken, met als groot nadeel dat alle bestaande code in 1 klap onbruikbaar is.
Daarom is null misschien ook wel de billion dollar mistake. ;) We hadden het nooit zo ver moeten laten komen. :p
In dit geval zie ik toch duidelijk een voordeel voor null returnen:
Java:
1
2
3
4
5
6
7
8
Person result = myCollection.getByName(x);
if (result != null) {
  doSomething(result);
}
else {
  // vaak geen else, omdat er bij geen resultaat niks gedaan hoeft te worden
  showWarning("nothing found");
}

versus:
Java:
1
2
3
4
5
6
7
8
try {
  Person result = myCollection.getByName(x);
  doSomething(result);
}
catch (NoSuchElementException e) {
  //kan niet weggelaten worden
  showWarning("nothing found");
}

Bij de eerste is de flow al een stuk duidelijker: je ziet direct wat er gebeurt zodra het element niet gevonden is.
Ik vind de null-aanpak hier ook duidelijker.
Stel nu dat ik 3 gegevens ophaal uit de verzameling: result1, result2 en result3, en alle resultaten onder elkaar wil opsommen op een vergelijkbare manier. Dan krijg je 3 try/catch blocks, 3 extra booleans (gevonden ja/nee), en alsnog een if/else onderaan in de weergave.

En Strings lijkt mij omdat het hier een dom voorbeeld is, bij zinnige code zal je al snel een data-container gebruiken.
Maar met nulls krijg je ook een aantal if-then-elses om te controleren op null? Het kan zijn dat ik je verkeerd begrijp, dus kun je een aangeven wat het resultaat zou zijn in het geval dat bijv. result1 en result3 non-null zijn en result2 null?

[ Voor 61% gewijzigd door RayNbow op 10-03-2010 20:30 ]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Dit bijvoorbeeld:
Java:
1
2
3
4
5
6
7
Person result = myCollection.getByName(x);
Person result2 = myCollection.getByY(x);
Person result3 = myCollection.getByZ(x);

if (result != null) showResult(result);
if (result2 != null) showResult(result2);
if (result3 != null) showResult(result3);


De oefening 'doe dit zonder null' mag jij doen ;)

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Apache schreef op woensdag 10 maart 2010 @ 20:08:
Dat ze duur zijn mag weinig boeien, dat valt bij mij onder premature optimizations en gaat pas echt een rol spelen als dat een hotspot in je code is die veel gecalled word.
Sorry maar dit is geen "premature optimization". Je moet exceptions niet misbruiken voor dingen waar ze niet voor bedoeld zijn. Om te checken of iets een int is kun je prima een regex gebruiken. Als je 100 keer per seconden een String moet checken wil je daar echt niet iedere keer een stacktrace voor op willen bouwen.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

Mwah. Imho moet je het wel of niet gebruiken van een exception niet af laten hangen van de efficientie, maar van de 'algoritmische situatie'. Exceptions hebben een specifieke betekenis. Het is een situatie die optreed waar je op dat moment eigenlijk niks mee kunt. De afhandeling wil je overlaten aan je aanroeper. Als je dit 'mantra' aanhoud kom je uiteindelijk wel tot dezelfde keuzes als Hydra, maar met een imo sterkere onderbouwing.

Wanneer je wilt kijken of iets een integer is, dan gebruik je geen exception. Wil je een String omvormen naar een Integer. Zit er in die string helemaal geen integer, dan gooi je een exception aangezien je niet weet hoe je dit op die plek af moet handelen.

De mindset 'exceptions zijn duur' zorgt er alleen maar voor dat mensen bang worden om ze te gebruiken en vervolgens terug gaan vallen op de oude C manier met het teruggeven van statuscodes.

[ Voor 12% gewijzigd door Janoz op 11-03-2010 09:26 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Janoz schreef op donderdag 11 maart 2010 @ 09:25:
De mindset 'exceptions zijn duur' zorgt er alleen maar voor dat mensen bang worden om ze te gebruiken en vervolgens terug gaan vallen op de oude C manier met het teruggeven van statuscodes.
Ik zeg volgens mij letterlijk dat je exceptions niet moet gebruiken waar ze niet voor bedoeld zijn, dat betekent ook dat je ze wel gebruikt waar ze wel voor bedoeld zijn. Dat exceptions duur zijn is gewoon een argument tegen het misbruiken van exceptions voor dergelijke 'checks', niet een reden om ze helemaal niet te gebruiken. Lijkt me duidelijk.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

Voor jou is het duidelijk. Voor mij is het duidelijk. Ik zie alleen best vaak het 'exceptions zijn zwaar' mantra terug komen in situaties waarbij mensen een legitieme toepassing van exceptions proberen te vermeiden en er allemaal vreemde boolean retournerende constructies voor in de plaats gebruiken.

Het 'exceptions zijn zwaar'- argument is makkelijk te onthouden. Het 'gebruiken wanneer ze bedoeld zijn' is een lastigere meetlat.Wanneer je dat samen neemt zullen veel wat minder ervaren mensen als snel varen op enkel het eerste en exceptions gaan vermeiden. Vandaar dat ik nogal terughoudend ben met het roepen dat exceptions zwaar zijn.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Janoz schreef op donderdag 11 maart 2010 @ 10:22:
Voor jou is het duidelijk. Voor mij is het duidelijk. Ik zie alleen best vaak het 'exceptions zijn zwaar' mantra terug komen in situaties waarbij mensen een legitieme toepassing van exceptions proberen te vermeiden en er allemaal vreemde boolean retournerende constructies voor in de plaats gebruiken.

Het 'exceptions zijn zwaar'- argument is makkelijk te onthouden. Het 'gebruiken wanneer ze bedoeld zijn' is een lastigere meetlat.Wanneer je dat samen neemt zullen veel wat minder ervaren mensen als snel varen op enkel het eerste en exceptions gaan vermeiden. Vandaar dat ik nogal terughoudend ben met het roepen dat exceptions zwaar zijn.
Ja ach, je hebt goeie developers en je hebt prutsers. Zelfs als je het "exceptions zijn zwaar" eruit slaat leveren die slechte (daily WTF-waardige) code op. We hebben er hier ook zo een gehad en daar hebben we nu jaren later nu we zijn tool moeten supporten nog last van :D

https://niels.nu


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Je hebt 3 soorten programmeurs:
- de super-geweldige programmeur, zoals iedereen hier*
- de prutser die af en toe wat script-achtige zaken doet, oppervlakkig spul wat hij nog kan begrijpen
- de prutser die een inner-platform ontwerpt op de meest WTF-worthy manier

Roepen dat exceptions zwaar zijn helpt groep 2, groep 3 weet het toch altijd wel te verprutsen :+

*) cynisch bedoeld natuurlijk

[ Voor 5% gewijzigd door MBV op 11-03-2010 11:09 ]


Acties:
  • 0 Henk 'm!

  • Apache
  • Registratie: Juli 2000
  • Laatst online: 16-09 10:29

Apache

amateur software devver

Hydra schreef op donderdag 11 maart 2010 @ 08:08:
[...]


Sorry maar dit is geen "premature optimization". Je moet exceptions niet misbruiken voor dingen waar ze niet voor bedoeld zijn. Om te checken of iets een int is kun je prima een regex gebruiken. Als je 100 keer per seconden een String moet checken wil je daar echt niet iedere keer een stacktrace voor op willen bouwen.
We zeggen toch exact hetzelfde?

* requirements afhankelijk
* geen flow genereren dmv exceptions

Als een exception word weggelaten, in het geval waar hij wel hoort en er is geen performance issue dan is dat een premature optimization.

If it ain't broken it doesn't have enough features


Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
MBV schreef op donderdag 11 maart 2010 @ 01:11:
Dit bijvoorbeeld:
Java:
1
2
3
4
5
6
7
Person result = myCollection.getByName(x);
Person result2 = myCollection.getByY(x);
Person result3 = myCollection.getByZ(x);

if (result != null) showResult(result);
if (result2 != null) showResult(result2);
if (result3 != null) showResult(result3);


De oefening 'doe dit zonder null' mag jij doen ;)
Je zou een 'NullPerson' kunnen maken die teruggegeven wordt door myCollection. showResult laat dan een melding zien (evt) dat die persoon niet bestaat / gevonden is. Hoef je die null checks niet te doen, en tenzij je nog iets anders met result en result2 etc doet ook niet in een lokale var te stoppen.

Je zou natuurlijk ook de null check naar showResult kunnen verplaatsen, aangezien je hier niks doet als result wel null is.

* YopY heeft NullObject gelezen en probeert het tegenwoordig vaker toe te passen indien mogelijk.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

Een Null person maken? IMHO is dat een veel ranzigere oplossing. Ik heb even naar het pattern gekeken en ik kan niet echt zeggen dat ik daar heel enthousiast over ben. Daarmee verplaats je het probleem alleen maar. neem bijvoorbeeld het persoon. Je kunt best garanderen dat de voornaam en de achternaam nooit null kunnen zijn (terwijl voorvoegsel dat wel zou kunnen zijn).Bij een null object kun je vervolgens weer niet van die dingen uit gaan aangezien een nullPerson ineens wel een null voor en achternaam heeft.

Zorg gewoon dat je in je javadoc opneemt of je methode wel of niet null values accepteerd danwel teruggeeft en geef ook aan in welke situaties dit het geval is. Op die manier kun je keurig je code op een jusite manier aan elkaar rijgen zonder dat je je constant druk hoeft te maken over null en nonnull values.

De null check verplaatsen lijkt mij inderdaad een veel betere oplossing. Ik neem aan dat 'showResult' beter weet hoe hij de gebruiker op de hoogte moet brengen van een leeg resultaat dan deze code.


@MBV:Eigenlijk het enige waarin Hydra (en jij aan de ene kant) en ik (aan de andere kant) van mening verschillen is over type 2. Ik ben van mening dat je met 'exceptions zijn zwaar' roepen ook groep 2 wat op het verkeerde been zet.

[ Voor 10% gewijzigd door Janoz op 11-03-2010 13:15 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

MBV schreef op donderdag 11 maart 2010 @ 01:11:
Dit bijvoorbeeld:
Java:
1
2
3
4
5
6
7
Person result = myCollection.getByName(x);
Person result2 = myCollection.getByY(x);
Person result3 = myCollection.getByZ(x);

if (result != null) showResult(result);
if (result2 != null) showResult(result2);
if (result3 != null) showResult(result3);


De oefening 'doe dit zonder null' mag jij doen ;)
Ik zou wel null gebruiken, maar niet met expliciete null checks. Hierboven wordt al door Janoz en YopY voorgesteld om de null-check te verplaatsen naar showResult, maar ik zou zelf de null-check ergens anders zetten:

Java:
1
2
3
4
5
6
for (Person p : catMaybes(
        myCollection.getByName(x),
        myCollection.getByY(x),
        myCollection.getByZ(x))
    )
    showResult(p);


Een mogelijke (non-lazy) implementatie voor catMaybes:
Java:
1
2
3
4
5
6
7
public static <E> Iterable<E> catMaybes(E ...items) {
    ArrayList<E> res = new ArrayList<E>();
    for (E item : items)
        if (item != null)
            res.add(item);
    return res;
}


Uiteraard is catMaybes geinspireerd door de Haskell functie catMaybes :: [Maybe a] -> [a]. :p

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

wacht even, die aanroep moet toch "catMaybes<Person>(....)" zijn? Verder vind ik het overkill voor dit kleine dingetje, maar dat moet jij weten.

null-check zou in showResult kunnen, maar niet als het een library-achtige functie is. Ik dacht zelf aan een functie die een tabelletje neerzet met de gegevens ofzo, en als ze alledrie false zijn een melding dat er geen resultaten zijn. Dat laatste had ik er even niet bij getikt:
Java:
1
if result == result2 == result3 == null) showNoResult();

Dat zorgt ervoor dat je de null-check in deze functie moet houden.

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

MBV schreef op donderdag 11 maart 2010 @ 14:37:
wacht even, die aanroep moet toch "catMaybes<Person>(....)" zijn?
Nee, lang leve (weliswaar in Java beperkte) type inference. :p
Verder vind ik het overkill voor dit kleine dingetje, maar dat moet jij weten.
Het komt een beetje door de verbositeit van Java en dat er geen catMaybes-achtige functie in de Java stdlib zit. :p
null-check zou in showResult kunnen, maar niet als het een library-achtige functie is. Ik dacht zelf aan een functie die een tabelletje neerzet met de gegevens ofzo, en als ze alledrie false zijn een melding dat er geen resultaten zijn. Dat laatste had ik er even niet bij getikt:
Java:
1
if result == result2 == result3 == null) showNoResult();

Dat zorgt ervoor dat je de null-check in deze functie moet houden.
Dus zoiets?
Java:
1
2
3
4
5
Iterable<Person> ps = catMaybes(myCollection.getByName(x), myCollection.getByY(x), myCollection.getByZ(x));
if (ps.iterator().hasNext()) for (Person p : ps)
    showResult(p);
else
    showNoResult();

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Goh, welke is er dan leesbaarder? B)

Ik kan me voorstellen dat het nuttig is in bepaalde gevallen, maar doe mij in dit geval maar nulls :)

Acties:
  • 0 Henk 'm!

  • Cobalt
  • Registratie: Januari 2004
  • Laatst online: 28-08 14:11
Maken jullie niet een denk fout dat er namelijk maar 1 resultaat kan zijn?? myCollection.getByName(x) zou een list moeten returnen want in het telefoonboek van de TS kunnen meerdere personen staan die 'Jan' als naam hebben. showResult(list) moet het resultaat renderen dus ook netjes weer kunnen geven dat er niks gevonden is.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
String searchName= "Jan";

List<Person> result = phoneBook.findPersonByName(searchName);
showResult(result, searchName);


public void showResult(List<Person> result, String  searchName) {
   if(result.isEmpty()) {
      // render Geen persoon gevonden met de naam: + searchName
   } else {
      // render list gevonden personen en telefoonnummers
      for(Person p : result) {
         // render p.getName()
         for(PhoneNumber nr : p.getPhoneNumbers()) {
             // render nr
         }
      }
   }
}

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

MBV schreef op donderdag 11 maart 2010 @ 16:29:
Goh, welke is er dan leesbaarder? B)
De Haskell versie natuurlijk. :Y)
Haskell:
1
2
3
4
do let ps = mapMaybe (\f -> f x myCollection) [getByName,getByY,getByZ]
   if null ps
     then showNoResults
     else mapM_ showResults ps

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Gelukkig, een variant met 'null' dus :Y)

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

MBV schreef op donderdag 11 maart 2010 @ 17:50:
Gelukkig, een variant met 'null' dus :Y)
Goed, jij je zin:
Haskell:
1
2
3
4
do let ps = mapMaybe (\f -> f x myCollection) [getByName,getByY,getByZ]
   case ps of
     [] -> showNoResults
     _  -> mapM_ showResults ps

})

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Waar leek de java-null ook al weer het meeste op, als je het met wiskunde vergelijkt? Ik denk de empty set... :P

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

Daar ben ik het eigenlijk niet mee eens. :p

De nil list case in m'n Haskell code komt uit het feit dat ik filter. Na filteren kan het resultaat een lege lijst zijn. Dat is iets heel anders dan de null van Java.

De null van Java is niets anders dan een speciaal element. Voor elke class X in Java geldt het volgende:

    X_type = {object | class(object) = C ∧ C ∈ (X ∪ subclasses(X))} ∪ {null, ⊥}

Dus het type X omvat alle instanties van class X zelf en alle instanties van subclasses van X, uitgebreid met de speciale waarden null en bottom (waarbij bottom non-termination voorstelt).


Als je toch de null met de lege set vergelijkt, wat is dan een non-null waarde? Een singleton?

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Note to self: * MBV moet niet interessant doen tegen mensen die er iets vanaf weten :+.

Wat denk je, is de TS al afgehaakt? B)

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 14:56

RayNbow

Kirika <3

MBV schreef op vrijdag 12 maart 2010 @ 12:39:
Wat denk je, is de TS al afgehaakt? B)
Ik denk dat ie een trauma aan over heeft gehouden.

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Hydra schreef op woensdag 10 maart 2010 @ 18:25:
Als een collection een bepaald element niet bevat geeft die 'null' terug. Het gebruiken van Exceptions (die duur zijn!) voor dingen die geen fouten zijn, dat is IMHO pas echt slecht. In princiepe zouden exceptions niet voor mogen komen, het zijn letterlijk uitzonderingen.
Definieer duur? Bij mijn weten is een exception in Java misschien een paar instructies meer dan het retourneren van null of een status code, maar dat het duur is lijkt mij extreem zwaar overdreven. Ik denk dat het gooien van een Exception zodat je afrolt naar de plek waarop deze wordt afgehandeld toch een stuk goedkoper is dan op ieder tussenliggend niveau te moeten gaan controleren wat je met het result moet en daar dan specifieke code voor te maken zodat je alsnog afrolt naar de plek waar de fout situatie echt wordt afgehandeld.

Acties:
  • 0 Henk 'm!

  • terje7601
  • Registratie: September 2009
  • Laatst online: 08-02-2024
Janoz schreef op donderdag 11 maart 2010 @ 13:13:
Een Null person maken? IMHO is dat een veel ranzigere oplossing. Ik heb even naar het pattern gekeken en ik kan niet echt zeggen dat ik daar heel enthousiast over ben. Daarmee verplaats je het probleem alleen maar. neem bijvoorbeeld het persoon. Je kunt best garanderen dat de voornaam en de achternaam nooit null kunnen zijn (terwijl voorvoegsel dat wel zou kunnen zijn).Bij een null object kun je vervolgens weer niet van die dingen uit gaan aangezien een nullPerson ineens wel een null voor en achternaam heeft.
Als je dat pattern gebruikt kun je toch ook gewoon definiëren dat zowel voor- als achternaam de lege string zijn & je non-null garantie behouden?
Hydra schreef op woensdag 10 maart 2010 @ 18:25:
Het grootste probleem is dat ze gewoon duur zijn. Voor elke exception moet een stacktrace opgebouwd worden. Voorbeeld van fout gebruik van Exceptions:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
public boolean isInteger(String value)
{
  try
  {
     Integer.parseInt(value);
     return true;
  }
  catch(NumberFormatException e)
  {
     return false;
  }
}
Nu ben ik wel eens heel benieuwd waarom dit "fout gebruik van exceptions" is? Enkele posts verder zeg je:
Hydra schreef op donderdag 11 maart 2010 @ 08:08:
Om te checken of iets een int is kun je prima een regex gebruiken. Als je 100 keer per seconden een String moet checken wil je daar echt niet iedere keer een stacktrace voor op willen bouwen.
Dat is zoals die programmeurs die er vroeger bij zweerden om altijd een StringBuffer te gebruiken, want "je wil toch niet de overhead van iedere keer een + i.p.v. een append"...tot in Java 5 StringBuilder geïntroduceerd werd, alle code met + automatisch kon geöptimaliseerd worden naar een StringBuilder & de performance-guru's achterbleven met hun tragere StringBuffer implementatie.

De specificatie van die isInteger methode die je opgeeft moet (logischerwijs) als volgt zijn:

@returns true if and only if new Integer(input) doesn't throw an exception (of in een lange versie ongeveer zo: contains only digits, and possibly a single minus sign as the first character. On top of that, it should be a number >= Integer.MIN_VALUE & <= Integer.MAX_VALUE)

Dan wil ik je wel eens uitdagen om een methode te schrijven met een regex die precies dit doet (een equivalent van je methode met parseInt dus). Ik weet niet of je de source van die methode (Integer.parseInt) al eens bekeken hebt, maar daar maakt men dus geen gebruik van regexes of patterns of wat dan ook. Bovendien: hoe zul je in je methode verwerken dat het getal tussen Integer.MIN_VALUE & Integer.MAX_VALUE moet liggen zonder de input ook effectief te proberen omzetten naar een int?
De methode die parseInt gebruikt, is de simpelste implementatie mogelijk & garandeert je een correcte implementatie. En bovendien: waarom zou je het wiel opnieuw uitvinden? No offense, maar zolang je geen implementatie kan geven die 1) correct & 2) beduidend sneller is dan de parseInt implementatie, vind ik dit totale onzin hoor.

[ Voor 0% gewijzigd door terje7601 op 13-03-2010 16:01 . Reden: spelfout ]


Acties:
  • 0 Henk 'm!

  • Nick The Heazk
  • Registratie: Maart 2004
  • Laatst online: 07-09-2024

Nick The Heazk

Zie jij er wat in?

Remus schreef op zaterdag 13 maart 2010 @ 14:09:
Definieer duur? Bij mijn weten is een exception in Java misschien een paar instructies meer dan het retourneren van null of een status code, maar dat het duur is lijkt mij extreem zwaar overdreven. Ik denk dat het gooien van een Exception zodat je afrolt naar de plek waarop deze wordt afgehandeld toch een stuk goedkoper is dan op ieder tussenliggend niveau te moeten gaan controleren wat je met het result moet en daar dan specifieke code voor te maken zodat je alsnog afrolt naar de plek waar de fout situatie echt wordt afgehandeld.
Meten is weten.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class test {
public static void main(String[] args) {

    final int R = 1000000;
    final int N = 500;
    
    Object[] arr = new Object[N];
    for(int i = 0; i < N; ++i) {
        arr[i] = null;
    }
    
    long start = System.currentTimeMillis();
    int count = 0;
    double z = 0;
    for(int r = 0; r < R; ++r) {
        for(int i = 0; i < N; ++i) {
            try {
                z += 1.0 / arr[i].hashCode();
            } catch(Exception e) {
                ++count;
            }
        }
    }
    long end = System.currentTimeMillis();
    
    System.out.println("Exceptions done: " + count + "\tZ: " + z) ;
    System.out.println("Took: " + (end-start) + "ms.");
    
    start = System.currentTimeMillis();
    count = 0;
    for(int r = 0; r < R; ++r) {
        for(int i = 0; i < N; ++i) {
            if(arr[i] != null) {
                z += 1.0 / arr[i].hashCode();
            } else {
                ++count;
            }
        }
    }
    end = System.currentTimeMillis();

    System.out.println("Exceptions done: " + count + "\tZ: " + z) ;
    System.out.println("Took: " + (end-start) + "ms.");
}
}


Geeft op mijn systeem met Java 1.6 (OpenJDK) de volgende uitvoer:
code:
1
2
3
4
5
heazk@laptopnick:/tmp$ java test
Exceptions done: 500000000  Z: 0.0
Took: 2504ms.
Exceptions done: 500000000  Z: 0.0
Took: 1331ms.

Exceptions gebruiken is in deze situatie dus bijna 100% trager dan een if-test.

Performance is a residue of good design.


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Inderdaad, dat kost wel 1203ms/500.000.000 = 0,0000024ms per keer :z Ik denk dat als je in 3 functies dit met if/else moet afhandelen, de exception-versie sneller is.

En wat je voor het gemak bent vergeten: de if/else-versie voert de deling niet uit, ik denk dat dat al het verschil kan zijn. Ik gok dat een versie waar je wel een deling uitvoert al langzamer is dan de if/else-versie. * MBV is even te lui om eclipse te starten en het te testen.

[ Voor 11% gewijzigd door MBV op 13-03-2010 19:34 ]


Acties:
  • 0 Henk 'm!

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Dit soort kunstmatige 'metingen' zeggen over het algemeen bar weinig. Ten eerste benadeel je de meting van de exception door hem als eerste te doen ('warmup' van de JIT compiler). Verder is de logica nu dusdanig beperkt en simpel dat je de kosten van de exception uitvergroot tov kosten van je normale code en/of de logica om exceptions to voorkomen.

Acties:
  • 0 Henk 'm!

  • Nick The Heazk
  • Registratie: Maart 2004
  • Laatst online: 07-09-2024

Nick The Heazk

Zie jij er wat in?

MBV schreef op zaterdag 13 maart 2010 @ 19:33:
Inderdaad, dat kost wel 1203ms/500.000.000 = 0,0000024ms per keer :z Ik denk dat als je in 3 functies dit met if/else moet afhandelen, de exception-versie sneller is.

En wat je voor het gemak bent vergeten: de if/else-versie voert de deling niet uit, ik denk dat dat al het verschil kan zijn. Ik gok dat een versie waar je wel een deling uitvoert al langzamer is dan de if/else-versie. * MBV is even te lui om eclipse te starten en het te testen.
Die deling wordt niet uitgevoerd zo lang de operanden niet gekend zijn. De interpreter zal de hashCode van een null-object willen uitvoeren en knalt er op dat moment uit.
Remus schreef op zondag 14 maart 2010 @ 09:36:
Dit soort kunstmatige 'metingen' zeggen over het algemeen bar weinig. Ten eerste benadeel je de meting van de exception door hem als eerste te doen ('warmup' van de JIT compiler).
Die warmup effecten worden uitgemiddeld over 1 miljoen iteraties ... Maar goed, speciaal voor jou de code in omgekeerde volgorde uitgevoerd
code:
1
2
3
4
5
heazk@laptopnick:/tmp$ java test
Exceptions done: 500000000  Z: 0.0
Took: 1380ms.
Exceptions done: 500000000  Z: 0.0
Took: 2634ms.

Maakt niets uit.
Verder is de logica nu dusdanig beperkt en simpel dat je de kosten van de exception uitvergroot tov kosten van je normale code en/of de logica om exceptions to voorkomen.
Heb je mij horen zeggen dat dit een representatief stukje code is? Ik toon hiermee aan dat het gebruik van exceptions in deze situatie best wel in de categorie "duur" valt, tenopzichte van een equivalent stuk code zonder exceptions. Het voorbeeld is trouwens helemaal niet willekeurig gekozen. Waarom exceptions hier niet goed werken mag jij uitvogelen ;).

Performance is a residue of good design.


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

MBV schreef op zaterdag 13 maart 2010 @ 19:33:
En wat je voor het gemak bent vergeten: de if/else-versie voert de deling niet uit, ik denk dat dat al het verschil kan zijn. Ik gok dat een versie waar je wel een deling uitvoert al langzamer is dan de if/else-versie.
Beide voeren 'm niet uit, maar in het ene geval is het een goedkope null-check die direct doorvalt naar de else, en in het andere geval een relatief dure exception afhandeling.

Als je de kans dat die exception optreedt veel kleiner maakt, is de kans zelfs groot dat die kwa performance wint. Overigens is het in Java heel lastig te zeggen of exceptions duur zijn of niet. De hotspot-optimizer houdt iig bij of in een bepaald code-pad de exceptions uberhaupt voorkwamen en zo niet, dan optimaliseert ie de hele afhandeling ervan vrijwel compleet weg. Hetzelfde geldt voor indexoutofbound exceptions e.d.

Als ik de code hierboven pak en refactor naar 2 methodes die een daarna 10x uitgevoerd worden, is het resp. 847ms vs 678ms bij de 10e executie. Als ik echter de array aanpas om maar 1 element met null te hebben, dan is het verschil ineens een stuk trivialer. Uiteindelijk zijn ze dan bij mij dan op 3375 vs 3374ms.
Met vervolgens de exceptions helemaal weg komt de eerste uit op 3390ms en de if-aanpak op 4557ms... blijkbaar kan hotspot (Sun's 1.6.0_18 64bits jvm) dan ineens een stukje minder goed optimaliseren.

Maar het moraal van het verhaal wordt hopelijk duidelijk zo: "Exceptions zijn duur" is tegenwoordig een onzinuitspraak. Dat gezegd hebbende moet je nu niet ineens overal Exceptions als de nieuwe performance-tool gaan misbruiken, maar je hoeft ze ook niet te mijden omdat ze de prestaties zouden verzieken :) Kortom, ik schaar me hierin achter Janoz.

Stiekem heb ik natuurlijk wel in een stuk code exceptions gebruikt om performanceredenen, maar dat is bij een stringbuffer-achtige klasse midden in het kritieke pad die anders enorm veel dubbele array-boundchecks moest doen (bijv een eigen en die van String.getChars(...)) en nu leunt op Java's eigen interne checks (die overigens anders wel weggeoptimaliseerd zouden worden) daarop met een try/catch eromheen :P

Overigens zijn, vziw, strikt genomen returns halverwege de code ietsje efficienter dan alle data tot het eind van een functie verzamelen en dan pas de boel returnen. Het scheelt een extra stackpush en een jump in de bytecode. Of die winst na hotspot-optimalisatie nog over blijft is maar de vraag, dus ook hier zou ik niet te gauw kiezen voor de 'snelste' versie, maar zou ik de leesbaarheid van de code wel voorop houden.

[ Voor 8% gewijzigd door ACM op 14-03-2010 11:35 ]


Acties:
  • 0 Henk 'm!

  • Jrz
  • Registratie: Mei 2000
  • Laatst online: 13:42

Jrz

––––––––––––

toch mooi dat zo'n post naar zoiets anders kan leiden

Ennnnnnnnnn laat losssssssss.... https://github.com/jrz/container-shell (instant container met chroot op current directory)


Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

ACM schreef op zondag 14 maart 2010 @ 11:31:
[...]

Beide voeren 'm niet uit, maar in het ene geval is het een goedkope null-check die direct doorvalt naar de else, en in het andere geval een relatief dure exception afhandeling.

Als je de kans dat die exception optreedt veel kleiner maakt, is de kans zelfs groot dat die kwa performance wint. Overigens is het in Java heel lastig te zeggen of exceptions duur zijn of niet. De hotspot-optimizer houdt iig bij of in een bepaald code-pad de exceptions uberhaupt voorkwamen en zo niet, dan optimaliseert ie de hele afhandeling ervan vrijwel compleet weg. Hetzelfde geldt voor indexoutofbound exceptions e.d.

Als ik de code hierboven pak en refactor naar 2 methodes die een daarna 10x uitgevoerd worden, is het resp. 847ms vs 678ms bij de 10e executie. Als ik echter de array aanpas om maar 1 element met null te hebben, dan is het verschil ineens een stuk trivialer. Uiteindelijk zijn ze dan bij mij dan op 3375 vs 3374ms.
Met vervolgens de exceptions helemaal weg komt de eerste uit op 3390ms en de if-aanpak op 4557ms... blijkbaar kan hotspot (Sun's 1.6.0_18 64bits jvm) dan ineens een stukje minder goed optimaliseren.

Maar het moraal van het verhaal wordt hopelijk duidelijk zo: "Exceptions zijn duur" is tegenwoordig een onzinuitspraak. Dat gezegd hebbende moet je nu niet ineens overal Exceptions als de nieuwe performance-tool gaan misbruiken, maar je hoeft ze ook niet te mijden omdat ze de prestaties zouden verzieken :) Kortom, ik schaar me hierin achter Janoz.

Stiekem heb ik natuurlijk wel in een stuk code exceptions gebruikt om performanceredenen, maar dat is bij een stringbuffer-achtige klasse midden in het kritieke pad die anders enorm veel dubbele array-boundchecks moest doen (bijv een eigen en die van String.getChars(...)) en nu leunt op Java's eigen interne checks (die overigens anders wel weggeoptimaliseerd zouden worden) daarop met een try/catch eromheen :P

Overigens zijn, vziw, strikt genomen returns halverwege de code ietsje efficienter dan alle data tot het eind van een functie verzamelen en dan pas de boel returnen. Het scheelt een extra stackpush en een jump in de bytecode. Of die winst na hotspot-optimalisatie nog over blijft is maar de vraag, dus ook hier zou ik niet te gauw kiezen voor de 'snelste' versie, maar zou ik de leesbaarheid van de code wel voorop houden.
+1

Performance in Java bewijs je niet met een benchmark. Zelfs de conclusie die Nick The Heazk trekt (dat in zijn hele specifieke voorbeeld de ifelse sneller is), is onzinnig. Op mijn laptop performen beide implementaties bijvoorbeeld exact hetzelfde (server VM btw...).

Om dit punt wat kracht bij te zetten, ik zat pas met Heinz Kabutz en Brian Goetz te discussiëren over de performance van synchronized vs. de ReentrantLock class. Brian en ik waren het synchronized kamp, Heinz was voor ReentrantLock. We kwamen er niet uit. Een geloofwaardige benchmark opstellen was zelfs niet gelukt. Gevolg: Vraag doorgezet naar Doug Lea. Hij mag een benchmark schrijven en de (door de JIT) gegenereerde instructies gaan analyseren. Ik ben benieuwd naar het resultaat, maar dit is specialistisch werk, dus ik weet het zo net nog niet...

Als je bovenstaande namen niet kent, dit zijn experts op JVM gebied. Zelfs voor deze gasten is het ontzettend tricky om een goede benchmark op te stellen. Ben je geen specialist? Dan is je test waarschijnlijk onzinnig.

Aan de andere kant, Nick The Heazk zijn gevoel dat exceptions trager zijn, lijkt mij wel valide, maar om een andere reden. Dynamic compilers zoals HotSpot zijn in principe geavanceerde pattern-matchers. Ze herkennen bepaalde constructies en vertalen deze naar efficiente code (inlining, dead code verwijderen, etc). Bij Sun moeten ze prioriteiten stellen, dus ze zullen eerst kiezen voor de optimalisaties waar veel mensen baat bij hebben. Hierdoor is de kans erg klein dat "vreemde" code efficienter zal worden bij een nieuwe Java release. Simpele, "naief geschreven", code zal dat misschien wel worden.

Om deze reden vind ik performance op dit niveau geen valide argument bij het schrijven van code. Ik programmeer het liever zo duidelijk mogelijk. En ik bouw liever een expliciete null-check dan dat ik een NPE moet catchen. Je kunt toch niet voorspellen hoe de code zich @runtime gedraagt.

Performance tuning op dit niveau is extreem speculatief. Een nieuwe (minor) versie, en de wereld kan er heel anders uitzien. Om die reden zeg ik, gewoon niet teveel aan denken. Getters en setters? Die zijn gratis. Defensief programmeren? Gewoon doen, dit is meestal ook gratis, want de JIT flikkert al je code gewoon weg. :)

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Ik denk toch dat de testcase een heel belangrijk feit aantoont: het kost ongeveer 0,0ms* per berekening. Dat kan nooit genoeg zijn om lelijke code te rechtvaardigen. Ga liever je algoritmen optimaliseren :)

*) 0,0000024ms is bij benadering 0,0ms

[ Voor 9% gewijzigd door MBV op 14-03-2010 20:42 ]


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

MBV schreef op zondag 14 maart 2010 @ 20:41:
Ik denk toch dat de testcase een heel belangrijk feit aantoont: het kost ongeveer 0,0ms* per berekening. Dat kan nooit genoeg zijn om lelijke code te rechtvaardigen. Ga liever je algoritmen optimaliseren :)
Als het je 50% aan rekentijd scheelt, ongeacht hoe klein het is per keer, is het natuurlijk wel degelijk potentieel een interessante optimalisatie. Desalniettemin is het voorkomen (wat jij waarschijnlijk bedoelt met het algoritme optimaliseren) dat de nullcheck in een loop nodig is waarschijnlijk nog veel effectiever dan hem zo snel mogelijk maken.
En sowieso zal je het in de context van de daadwerkelijke operatie moeten beoordelen. Het hierboven gestelde specifieke voorbeeld is waarschijnlijk alleen interessant als je een hashcode-methode voor een collection aan het schrijven bent :P

[ Voor 15% gewijzigd door ACM op 15-03-2010 08:12 ]


Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Performance in Java bewijs je niet met een benchmark.
Daarom kun je je ook beter richten op goeie, niet-gekke code schrijven dan afwegingen maken tussen het gooien van exceptions of werken met errorcodes. Doe gewoon exceptions, da's veel makkelijker / sneller qua programmeren, en ook vele malen sneller met refactoren. Ik bedoel, een exception afvangen is een kwestie van een paar keer ctrl+1 (Eclipse, quick fix -> add throws clause danwel add catch clause danwel surround with try / catch) en klaar (ik laat exceptions meestal gewoon naar boven gooien), maar met errorcodes werken moet je een nieuwe error code bedenken, toevoegen aan je lijstje met constants, en een afhandeling voor die error code toevoegen. Dat is minder snel / makkelijk te automatiseren, en er zitten gewoon meer onderhoudskosten aan.

En dan heb ik het nog niet eens over het schrijven van een API voor anderen. In zo'n geval kun je beter een exception laten gooien dan een errorcode teruggeven, want dan garandeer je dat de andere die opvangt. Of niet, :+.

Overigens is het voorbeeld wat Nick geeft niet echt representatief in mijn mening - bij de eerste telling voorkom je de fout, bij de tweede vang je hem af, dwz de twee functies zijn logisch gezien niet gelijk.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:15

Janoz

Moderator Devschuur®

!litemod

Nog los van dat alles. Het doorakkeren van ononderhoudbare code tijdens onderhoud is een heel stuk duurder dan wat snellere hardware. Een medior developer een week aan het werk zetten kost ongeveer evenveel als een dikke server.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
JKVA schreef op zondag 14 maart 2010 @ 19:00:
Performance in Java bewijs je niet met een benchmark.
Lekker kort door de bocht. Als je zorgt dat het een eerlijke benchmark is waarbij de code ook daadwerkelijk uitgevoerd wordt kun je best 2 simpele cases op die manier met elkaar vergelijken. Vind het grappig dat mijn opmerking over het misbruiken van exceptions voor integerchecks zo opgeblazen wordt...
Als je bovenstaande namen niet kent, dit zijn experts op JVM gebied. Zelfs voor deze gasten is het ontzettend tricky om een goede benchmark op te stellen. Ben je geen specialist? Dan is je test waarschijnlijk onzinnig.
Ad verecundiam.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Verwijderd schreef op maandag 01 maart 2010 @ 16:35:
Java:
1
2
3
4
5
6
7
8
9
    //Retrieves a persons phone number given the persons name.
    public String getPhoneNumber(String nameForSearch) {
        for(int i=0; i<nextEmptyPerson; i++) {
            if (phoneBookDataBase.elementAt(i).getName().equalsIgnoreCase(nameForSearch)) {
                return phoneBookDataBase.elementAt(i).getPhone();
            }
        }
        return null;
    }
Even iets heel anders: nextEmptyPerson is een beetje vreemde naam voor een integer die een loop begrensd. Daarnaast lijkt het me dat phoneBookDataBase waarschijnlijk gewoon 'phoneBook' kan heten, waarmee het korter en overzichtelijker wordt.
Hydra schreef op woensdag 10 maart 2010 @ 14:52:
Tuurlijk, het moet geen codebrij worden, maar het is onzin dat je perse meerdere returnpaden moet voorkomen als het alternatief niet gewoon onduidelijker wordt.
Mijn pragmatische regel daarvoor is dat meerdere returns vlak bij elkaar mogen, maar als ze niet binnen pakweg 25 regels passen, of ver uit elkaar liggen, dan komt er 1 return aan het einde van de functie.
Janoz schreef op woensdag 10 maart 2010 @ 15:10:
De reden waarom bij informatica opleidingen over het algemeen aangeleert wordt om 1 return te gebruiken is omdat een (wiskundig)correctheidsbewijs voor een functie met meerdere return methoden enorm veel lastiger is.
Ik denk niet dat dat de reden is. Een functie automatisch zo transformeren dat meerdere returnpaden omgezet worden in 1 returnpad aan het einde is niet moeilijk.
Janoz schreef op donderdag 11 maart 2010 @ 13:13:
Een Null person maken? IMHO is dat een veel ranzigere oplossing. Ik heb even naar het pattern gekeken en ik kan niet echt zeggen dat ik daar heel enthousiast over ben. Daarmee verplaats je het probleem alleen maar.
Het voornaamste voordeel daarvan is dat je getypeerde null checks krijgt. Heeft in Java niet veel nut; de Some()-achtige constructies die je dwingen om de 'None' variant af te handelen, zoals in Scala, Haskell e.d., hebben des te meer nut.
JKVA schreef op zondag 14 maart 2010 @ 19:00:
Om dit punt wat kracht bij te zetten, ik zat pas met Heinz Kabutz en Brian Goetz te discussiëren over de performance van synchronized vs. de ReentrantLock class. Brian en ik waren het synchronized kamp, Heinz was voor ReentrantLock.
Ik heb Java Concurrency in Practice niet bij de hand, maar ik weet me met aan zekerheid grenzende waarschijnlijkheid te herinneren dat daarin beweerd werd dat de ReentrantLock, in ieder geval ten tijde van dat boek (Java 5?), sneller was dan de intrinsieke synchronized.
Nick The Heazk schreef op zondag 14 maart 2010 @ 10:54:
Ik toon hiermee aan dat het gebruik van exceptions in deze situatie best wel in de categorie "duur" valt, tenopzichte van een equivalent stuk code zonder exceptions.
Omdat je hier net zoveel null checks doet als je exceptions gooit. Je dat realiserend valt de prijs erg mee: maar 2x zo duur als een if-test! Meestal gebruik je een exception in een situatie waarin die uitzonderlijk is. Een betere vergelijking is wanneer pakweg 1 op de 100 array elementen null zou zijn.
MBV schreef op zaterdag 13 maart 2010 @ 19:33:
En wat je voor het gemak bent vergeten: de if/else-versie voert de deling niet uit, ik denk dat dat al het verschil kan zijn.
Dat is wel een verschil dat inherent is aan het gebruik van exceptions en dat je dus mee moet nemen in de kosten: je probeert de deling uit te voeren. De benchmark wordt nog veel synthetischer als je dat door 'throw NullPointerException()' vervangt.
Hydra schreef op donderdag 11 maart 2010 @ 08:08:
Sorry maar dit is geen "premature optimization". Je moet exceptions niet misbruiken voor dingen waar ze niet voor bedoeld zijn. Om te checken of iets een int is kun je prima een regex gebruiken. Als je 100 keer per seconden een String moet checken wil je daar echt niet iedere keer een stacktrace voor op willen bouwen.
Gelukkig hoeft de stacktrace ook alleen opgebouwd te worden als de exceptie gegooid wordt. Niet als de string gechecked wordt.

[ Voor 88% gewijzigd door Confusion op 15-03-2010 10:37 ]

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19-09 12:39

MBV

Fout! Expert knowledge is geen drogreden. Dat wordt het pas als je een expert op een ander gebied aanhaalt, of "ja maar hij zegt dat" om een echt argument te weerleggen. Daar was hier geen sprake van.
En dat arrogante gebruik van latijn om je eigen autoriteit te versterken is pas echt een drogreden :X

Over jouw 'geweldige' benchmark heeft ACM het volgende te zeggen:
ACM schreef op zondag 14 maart 2010 @ 11:31:
[...]

Als je de kans dat die exception optreedt veel kleiner maakt, is de kans zelfs groot dat die kwa performance wint. Overigens is het in Java heel lastig te zeggen of exceptions duur zijn of niet. De hotspot-optimizer houdt iig bij of in een bepaald code-pad de exceptions uberhaupt voorkwamen en zo niet, dan optimaliseert ie de hele afhandeling ervan vrijwel compleet weg. Hetzelfde geldt voor indexoutofbound exceptions e.d.

Als ik de code hierboven pak en refactor naar 2 methodes die een daarna 10x uitgevoerd worden, is het resp. 847ms vs 678ms bij de 10e executie. Als ik echter de array aanpas om maar 1 element met null te hebben, dan is het verschil ineens een stuk trivialer. Uiteindelijk zijn ze dan bij mij dan op 3375 vs 3374ms.
Met vervolgens de exceptions helemaal weg komt de eerste uit op 3390ms en de if-aanpak op 4557ms... blijkbaar kan hotspot (Sun's 1.6.0_18 64bits jvm) dan ineens een stukje minder goed optimaliseren.
Daaraan kan je zien dat Java inderdaad bijna onmogelijk te benchmarken is, want kleine veranderingen in omstandigheden veranderen de uitkomst heel sterk.

Jij valt zo sterk over het aanhalen van een authoriteit op JVM-gebied, dat je de belangrijkste conclusie over het hoofd ziet? 8)7

[ Voor 3% gewijzigd door MBV op 15-03-2010 10:07 ]


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
MBV schreef op maandag 15 maart 2010 @ 10:06:
Fout! Expert knowledge is geen drogreden. Dat wordt het pas als je een expert op een ander gebied aanhaalt, of "ja maar hij zegt dat" om een echt argument te weerleggen. Daar was hier geen sprake van.
En dat arrogante gebruik van latijn om je eigen autoriteit te versterken is pas echt een drogreden :X
...right :)
Over jouw 'geweldige' benchmark heeft ACM het volgende te zeggen:
Het is niet 'mijn' benchmark.
Daaraan kan je zien dat Java inderdaad bijna onmogelijk te benchmarken is, want kleine veranderingen in omstandigheden veranderen de uitkomst heel sterk.

Jij valt zo sterk over het aanhalen van een authoriteit op JVM-gebied, dat je de belangrijkste conclusie over het hoofd ziet? 8)7
Komop zeg. Ik heb dat stuk gelezen maar mensen zijn nu druk aan het zoeken naar situaties waar het benchmarken van stukken code verkeerde resultaten oplevert. Als je een RL situatie probeert te testen is meten gewoon weten, zeker als je wet hoe hotspot werkt en de tests doet met verschillende settings. De Java VM biedt je niet voor niets de mogelijkheid zaken aan of uit te zetten d.m.v. de -XX opties.

Uiteindelijk wil je gaan testen met de settings waarin de app uiteindelijk gaat draaien met RL situaties. Niks mis met een benchmark als je zit te twijfelen tussen twee oplossingsrichtingen. Benchmarken onder Java is niet onmogelijk, je moet alleen weten wat de pitfalls (die zijn er zeker) zijn.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • terje7601
  • Registratie: September 2009
  • Laatst online: 08-02-2024
Hydra schreef op maandag 15 maart 2010 @ 09:57:
Vind het grappig dat mijn opmerking over het misbruiken van exceptions voor integerchecks zo opgeblazen wordt...
Lol :) Het was vooral je "dat doe je toch 1-2-3 met een regex" die het 'm deed :P Bovendien: er zijn best situaties waarin exceptions ten onrechte gebruikt worden (kan me niet meteen een voorbeeld bedenken, want ben zelf een exceptions-voorstander :P ), maar in je isInteger voorbeeld staat zelfs nergens een "throw ...", hoe kun je dan van exceptions-misbruik spreken?

Over het benchmarken: tuurlijk kun je benchmarks schrijven om bijv. zoekalgoritmes te vergelijken of zo, maar je kunt m.i. simpelweg geen benchmark schrijven met als doel "toon aan dat exceptions duur zijn", & dat was toch wat Nick probeerde.

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
terje7601 schreef op maandag 15 maart 2010 @ 10:51:
Lol :) Het was vooral je "dat doe je toch 1-2-3 met een regex" die het 'm deed :P Bovendien: er zijn best situaties waarin exceptions ten onrechte gebruikt worden (kan me niet meteen een voorbeeld bedenken, want ben zelf een exceptions-voorstander :P ), maar in je isInteger voorbeeld staat zelfs nergens een "throw ...", hoe kun je dan van exceptions-misbruik spreken?
Err. Wat?

Die code die ik gaf misbruikt een numberformatexception om te kijken of een string een integer bevat. Waarom zou daar een "throws" in moeten staan?

https://niels.nu


Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Hydra schreef op maandag 15 maart 2010 @ 09:57:
[...]
Lekker kort door de bocht. Als je zorgt dat het een eerlijke benchmark is waarbij de code ook daadwerkelijk uitgevoerd wordt kun je best 2 simpele cases op die manier met elkaar vergelijken. Vind het grappig dat mijn opmerking over het misbruiken van exceptions voor integerchecks zo opgeblazen wordt...
[...]
Ad verecundiam.
Het is geen argument op zich, maar wel een indicatie van hoe moeilijk het is om een goede benchmark op te zetten.
Confusion schreef op maandag 15 maart 2010 @ 10:05:
[...]
Ik heb Java Concurrency in Practice niet bij de hand, maar ik weet me met aan zekerheid grenzende waarschijnlijkheid te herinneren dat daarin beweerd werd dat de ReentrantLock, in ieder geval ten tijde van dat boek (Java 5?), sneller was dan de intrinsieke synchronized.
[...]
Bij de eerste release was ReentrantLock ook sneller. Met de eerste release van Java 6 presteerden ze gelijk. En de verwachting is dat synchronized in de toekomst sneller wordt dan ReentrantLock. Reden hiervoor is dat de VM bij synchronized meer kans heeft om te optimaliseren. Het gedrag van een synchronized block is namelijk dichtgetimmerd, bij ReentrantLock programeert de developer het zelf, waardoor de VM moet gaan gokken wat er precies gebeurt. Maar dat is speculatie, want er moeten wel resources voor vrijgemaakt worden bij Oracle om deze optimalisatie door te voeren...

Overigens heeft ReentrantLock wel andere voordelen, zoals herstellen van deadlocks of timeouts.
Hydra schreef op maandag 15 maart 2010 @ 10:22:
[...]
Benchmarken onder Java is niet onmogelijk, je moet alleen weten wat de pitfalls (die zijn er zeker) zijn.
En dat is precies de reden dat ik met het voorbeeld van Brian aankwam. Zelfs voor VM bouwers is dit werk extreem tricky (praktisch onmogelijk). Zeker het interpreteren van de resultaten is lastig. Daarom gebruiken ze in principe ook vrijwel geen micro benchmarks, maar gaan ze exact de gegenereerde instructies bekijken.

Met benchmarken op macro niveau is niks mis, met benchmarken op micro niveau wel, zeker als je in een VM draait.

Maar goed, ik was helemaal niet van plan om je af te zeiken ofzo. Ik wilde alleen aangeven dat micro benchmarks in Java in 99% van de gevallen fout zijn, zelfs al denk je overal aan gedacht te hebben.

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-09 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hydra schreef op maandag 15 maart 2010 @ 10:22:
Niks mis met een benchmark als je zit te twijfelen tussen twee oplossingsrichtingen. Benchmarken onder Java is niet onmogelijk, je moet alleen weten wat de pitfalls (die zijn er zeker) zijn.
Klopt. En een van die pitfalls is dat je het probleem isoleert en dat benchmarkt, en daar vervolgens conclusies uit denkt te kunnen trekken. Benchmarken doe je met RL usecases, niet met geisoleerde testcases.

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!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
.oisyn schreef op maandag 15 maart 2010 @ 12:40:
Klopt. En een van die pitfalls is dat je het probleem isoleert en dat benchmarkt, en daar vervolgens conclusies uit denkt te kunnen trekken. Benchmarken doe je met RL usecases, niet met geisoleerde testcases.
Nou, een voorbeeld waar we zelf achtergekomen zijn, na testen, is dat een class verantwoordelijk voor het parsen van 'wire' data naar java integers e.d. erg inefficient was. Aan de hand van tests hebben we toen voor een oplossingsrichting gekozen, en met die oplossing zijn we RL gaan testen om uit te sluiten dat we fouten in de aannames gemaakt hebben. Ik zeg ook niet dat microbenchmarks iets zijn waar je je 10)% je beslisingen op neemt, maar het kan wel vermoedens bevestigen of ontkrachten (wederom; wat niet wegneemt dat je het daarna met RL situaties moet testen).
JKVA schreef op maandag 15 maart 2010 @ 11:07:
En dat is precies de reden dat ik met het voorbeeld van Brian aankwam. Zelfs voor VM bouwers is dit werk extreem tricky (praktisch onmogelijk). Zeker het interpreteren van de resultaten is lastig. Daarom gebruiken ze in principe ook vrijwel geen micro benchmarks, maar gaan ze exact de gegenereerde instructies bekijken.
Bytecode of machineinstructies? Neem aan het laatste?
Met benchmarken op macro niveau is niks mis, met benchmarken op micro niveau wel, zeker als je in een VM draait.
Ik vind dat te ongenuanceerd. Micro/macrobenchmarks zijn tools, en je gebruikt een schroevendraaier ook niet om een spijker ergens in te meppen.
Maar goed, ik was helemaal niet van plan om je af te zeiken ofzo. Ik wilde alleen aangeven dat micro benchmarks in Java in 99% van de gevallen fout zijn, zelfs al denk je overal aan gedacht te hebben.
Ik vind dat nogal broad sweeping statements. Jij hebt het in voorbeelden bijvoorbeeld over synchronisatie tussen threads wat een stuk lastiger te voorspellen is dan 'slim' parsen van data bijvoorbeeld. Stel je hebt 2 implementaties van een parser en laat beide een flinke bak RL data parsen, met verschillende sets VM settings. Dan krijg je in ieder geval een beeld welke implementatie met welke settings het 'best' (zet het opzettelijk tussen quotes) werkt. Ik vind het enorm kort door de bocht te stellen dat het 99% van de gevallen fout is. Volgens mij zet je je tests dan niet goed op.

Wat betreft het 'afzeiken': ik krijg hier af en toe het gevoel dat ik met een stel pubers zit die het belangrijker vinden mekaar af te troeven dan een fatsoenlijke discussie te voeren. Vandaar dat ik af en toe daar wat allergisch op reageer ;)

[ Voor 50% gewijzigd door Hydra op 15-03-2010 13:11 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-09 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hydra schreef op maandag 15 maart 2010 @ 13:05:
[...]


Nou, een voorbeeld waar we zelf achtergekomen zijn, na testen, is dat een class verantwoordelijk voor het parsen van 'wire' data naar java integers e.d. erg inefficient was. Aan de hand van tests hebben we toen voor een oplossingsrichting gekozen, en met die oplossing zijn we RL gaan testen om uit te sluiten dat we fouten in de aannames gemaakt hebben. Ik zeg ook niet dat microbenchmarks iets zijn waar je je 10)% je beslisingen op neemt, maar het kan wel vermoedens bevestigen of ontkrachten (wederom; wat niet wegneemt dat je het daarna met RL situaties moet testen).
Uiteraard. Andersom werkt het trouwens ook. Geen of weinig verschil van een bepaalde optimalisatie in een geisoleerde case impliceert niet automatisch dat de optimalisatie in het daadwerkelijke project ook geen zin heeft.

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!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Hydra schreef op maandag 15 maart 2010 @ 13:05:
[...]
Bytecode of machineinstructies? Neem aan het laatste?
[...]
Ehm, zal het eens aan Brian vragen. Het enige dat ik weet is dat het om de output van de JIT gaat.

Dus ik denk idd machine instructies...

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

  • terje7601
  • Registratie: September 2009
  • Laatst online: 08-02-2024
Hydra schreef op maandag 15 maart 2010 @ 10:56:
Die code die ik gaf misbruikt een numberformatexception om te kijken of een string een integer bevat.
zou ik vervangen door: "Die code ... gebruikt een standaard Java API methode parseInt, om te kijken ..."
Maar goed, ik begrijp nog steeds niet waar hier nu volgens jou het "misbruik" zit. De code die je gaf is m.i. gewoon de enige zinnige implementatie voor een isInteger methode.

Of een volledig gelijkaardig voorbeeld: stel, je hebt een API beschikbaar met een methode

Java:
1
XMLDocument parseXML(File f) throws DocumentFormatException;


& er wordt je gevraagd een methode te schrijven om na te gaan of een bepaald bestand al dan niet een geldig XML-document is. Dan beweer jij dat je niet iets als:


Java:
1
2
3
4
5
6
7
8
public boolean isXML(File f) {
    try {
        parseXML(f);
        return true;
    } catch(DocumentFormatException e) {
        return false;
    }
}


zou schrijven, omdat dat dan volgens jou "een DocumentFormatException misbruiken" zou zijn?

Acties:
  • 0 Henk 'm!

  • Nick The Heazk
  • Registratie: Maart 2004
  • Laatst online: 07-09-2024

Nick The Heazk

Zie jij er wat in?

Ik verbaas me werkelijk over het onvermogen van sommigen om te lezen.
Nick The Heazk schreef op zaterdag 13 maart 2010 @ 18:41:
Geeft op mijn systeem met Java 1.6 (OpenJDK) de volgende uitvoer:
code:
1
 ...

Exceptions gebruiken is in deze situatie dus bijna 100% trager dan een if-test.
Geen woord over dat deze test representatief zou zijn. Natuurlijk is deze test niet representatief. Wie gaat er een array met null-objecten vullen en dan overal hashCode() op willen oproepen? Niemand. Het voorbeeld geeft aan dat er situaties zijn waarin exceptions trager zijn dan een equivalent stukje code die gebruik maakt van if-testen. Er werd opgemerkt dat
Bij mijn weten is een exception in Java misschien een paar instructies meer dan het retourneren van null of een status code, maar dat het duur is lijkt mij extreem zwaar overdreven.
Dat is onwaar. Vervolgens geef ik een voorbeeld waaruit blijkt dat de aanpak met exceptions bijna 100% trager wordt uitgevoerd. Wat mij betreft past het label "duur" dan wel. Dat exceptions minder performant (horen te) zijn, is uiteraard logisch want exceptions zijn bedoeld om uitzonderlijke situaties af te vangen. Niet om nominale werking van een code te programmeren. Dat is een van de redenen waarom ik mijn testvoorbeeld al zeker niet representatief zou noemen; het zou niet bij me opkomen om in een performance critical stukje code (bijvoorbeeld in een implementatie van hashCode) met exceptions te gaan werken ipv boolean tests omdat het wat makkelijker is.
ACM schreef op zondag 14 maart 2010 @ 11:31:
Als je de kans dat die exception optreedt veel kleiner maakt, is de kans zelfs groot dat die kwa performance wint. Overigens is het in Java heel lastig te zeggen of exceptions duur zijn of niet.
Absoluut. Indien er geen fout optreedt vermijd je de tests die je anders altijd zou uitvoeren.
Als ik de code hierboven pak en refactor naar 2 methodes die een daarna 10x uitgevoerd worden, is het resp. 847ms vs 678ms bij de 10e executie. Als ik echter de array aanpas om maar 1 element met null te hebben, dan is het verschil ineens een stuk trivialer. Uiteindelijk zijn ze dan bij mij dan op 3375 vs 3374ms.
Met vervolgens de exceptions helemaal weg komt de eerste uit op 3390ms en de if-aanpak op 4557ms... blijkbaar kan hotspot (Sun's 1.6.0_18 64bits jvm) dan ineens een stukje minder goed optimaliseren.
Hier is ook absoluut niets vreemd aan. Exceptions hebben "grote" overhead als de exception getriggered wordt, maar bijna geen overhead als er niets aan de hand is. Bij tests daarentegen heb je altijd de overhead. Een overhead die normaliter kleiner behoort te zijn dan het afhandelen van een exception. Dat wordt door mijn voorbeeld geïllustreerd.
Maar het moraal van het verhaal wordt hopelijk duidelijk zo: "Exceptions zijn duur" is tegenwoordig een onzinuitspraak.
Dankzij een geavanceerde VM. In puur geïnterpreteerde talen zal het performance verschil meetbaar zijn. Het verschil tussen exceptions en testen in Java met een moderne VM is natuurlijk erg klein. In een goed ontworpen stuk code horen exceptions geen bottleneck te vormen.
Dat gezegd hebbende moet je nu niet ineens overal Exceptions als de nieuwe performance-tool gaan misbruiken, maar je hoeft ze ook niet te mijden omdat ze de prestaties zouden verzieken :) Kortom, ik schaar me hierin achter Janoz.
Ik ben van mening dat als je ze op een normale manier gebruikt (voor exceptioneel gedrag, niet voor nominaal gedrag) dat het dan inderdaad geen verschil maakt welke aanpak je gebruikt.
JKVA schreef op zondag 14 maart 2010 @ 19:00:
+1
Performance in Java bewijs je niet met een benchmark. Zelfs de conclusie die Nick The Heazk trekt (dat in zijn hele specifieke voorbeeld de ifelse sneller is), is onzinnig. Op mijn laptop performen beide implementaties bijvoorbeeld exact hetzelfde (server VM btw...).
Geeft op mijn systeem met Java 1.6 (OpenJDK) de volgende uitvoer:
Ik trek geen algemene conclusies. Het is perfect mogelijk dat dat verschilt van systeem tot systeem. Al zal het in dit geval waarschijnlijk liggen aan het verschil tussen de VMs.
Aan de andere kant, Nick The Heazk zijn gevoel dat exceptions trager zijn, lijkt mij wel valide, maar om een andere reden. Dynamic compilers zoals HotSpot zijn in principe geavanceerde pattern-matchers. Ze herkennen bepaalde constructies en vertalen deze naar efficiente code (inlining, dead code verwijderen, etc). Bij Sun moeten ze prioriteiten stellen, dus ze zullen eerst kiezen voor de optimalisaties waar veel mensen baat bij hebben. Hierdoor is de kans erg klein dat "vreemde" code efficienter zal worden bij een nieuwe Java release. Simpele, "naief geschreven", code zal dat misschien wel worden.
Er zijn verscheidene redenen waarom exception handling duurder is dan een boolean test. Het probleem met Java is dat er een VM en HotSpot optimizer tussen zit. In een compiled taal is het heel wat makkelijker (maar het blijft moeilijk) om een informed guess te maken over welke aanpak sneller zal werken. Een van de nadelen bij exception handling is dat je pipeline helemaal verstoord wordt. Een basale if-test, zoals in mijn voorbeeld, kan echter genieten van een goed branch prediction mechanisme. Niet meteen iets waar men in gewone server of desktop software mee bezig is, maar in mijn branche (HPC) dus wel. Dat was ook de aim van het voorbeeld; een geval waarbij de code met testen normaliter (in een taal als C++ of FORTRAN*) veel performanter zou zijn omdat na een paar iteraties de branch prediction perfect zal werken en een zeer hoge doorvoer zal bereikt worden. Bij de aanpak met exceptions daarentegen zal typisch een exception handling routine worden opgeroepen met mogelijk een reeks argumenten. Het nadeel daarvan is dat het voorspellen van een functieadres minder triviaal is dan branch prediction en over het algemeen ook minder goed zal werken. Zoals gezegd zit bij Java de VM er nog tussen, dus het verbaast me ook niet dat de resultaten kunnen verschillen. Indien we dit voorbeeld eens zouden testen op een oudere VM (zonder HotSpot) dan zou de aanpak met testen waarschijnlijk duidelijk beter werken.
Om deze reden vind ik performance op dit niveau geen valide argument bij het schrijven van code. Ik programmeer het liever zo duidelijk mogelijk. En ik bouw liever een expliciete null-check dan dat ik een NPE moet catchen. Je kunt toch niet voorspellen hoe de code zich @runtime gedraagt.
Absoluut.
Performance tuning op dit niveau is extreem speculatief. Een nieuwe (minor) versie, en de wereld kan er heel anders uitzien. Om die reden zeg ik, gewoon niet teveel aan denken. Getters en setters? Die zijn gratis. Defensief programmeren? Gewoon doen, dit is meestal ook gratis, want de JIT flikkert al je code gewoon weg. :)
Natuurlijk. Je hebt me nergens horen beweren dat ik een tegenstander van exceptions ben. Echter de bewering dat het "extreem zwaar overdreven" is om exception handling als "duur" te bestempelen vind ik dan weer overdreven ;). Dankzij een erg goede dynamische optimizer (en goede programmeertechnieken) merk je het niet, maar exception handling is, op machineniveau, over het algemeen heel wat duurder dan problemen vermijden met een testje. Let wel, ik heb het hier over exception handling. Wanneer de exception optreedt. Als je exception maar 1% of zelfs 10% van de tijd optreedt, zal er weinig aan de hand zijn.
YopY schreef op maandag 15 maart 2010 @ 09:20:
Overigens is het voorbeeld wat Nick geeft niet echt representatief in mijn mening - bij de eerste telling voorkom je de fout, bij de tweede vang je hem af, dwz de twee functies zijn logisch gezien niet gelijk.
Nogmaals, ik beweer niet dat het representatief is. De twee lussen zijn echter volledig equivalent. Een grappige opmerking overigens; bij de eerste lus laat ik de fout optreden en bij de tweede vermijd ik de fout. Is dat niet zo een beetje een van de belangrijke verschillen tussen werken met exceptions en testen :+?
MBV schreef op maandag 15 maart 2010 @ 10:06:
Over jouw 'geweldige' benchmark heeft ACM het volgende te zeggen:
Het is de mijne. Het is geen benchmark, maar een voorbeeld van een situatie waarbij exceptions (op mijn systeem althans) niet goed werken. En tevens eentje waarvoor ze imo niet bedoeld zijn.
Daaraan kan je zien dat Java inderdaad bijna onmogelijk te benchmarken is, want kleine veranderingen in omstandigheden veranderen de uitkomst heel sterk.
Heel wat moeilijker dan in een compiled taal; daar moet je "enkel" weten wat de compiler met je code aanvangt, niet wat een dynamische compiler at runtime beslist :).
Hydra schreef op maandag 15 maart 2010 @ 10:22:
Komop zeg. Ik heb dat stuk gelezen maar mensen zijn nu druk aan het zoeken naar situaties waar het benchmarken van stukken code verkeerde resultaten oplevert. Als je een RL situatie probeert te testen is meten gewoon weten, zeker als je wet hoe hotspot werkt en de tests doet met verschillende settings. De Java VM biedt je niet voor niets de mogelijkheid zaken aan of uit te zetten d.m.v. de -XX opties.
Ik snap het probleem eigenlijk niet. Een aantal mensen hier reageert als een stier op een rode lap bij het zien van een stukje code. Plotseling is dat een representatieve benchmark die ik voorleg. Een verkeerd resultaat van een benchmark bestaat niet. Een stuk testcode kan hoogstens niet representatief zijn voor hetgene men wil testen. Maar verkeerde resultaten bestaan niet (zolang je code correct is). Mijn voorbeeld geeft een situatie waarbij exceptions op mijn systeem met de OpenJDK VM voor Java 1.6 "duur" zijn. Prachtig. Eenieder die loopt te beweren dat ik met die code de zaligmakende benchmark geef om exceptions met testen te vergelijken is spijkers in een uitgedroogd meer aan het zoeken.
terje7601 schreef op maandag 15 maart 2010 @ 10:51:
Lol :) Het was vooral je "dat doe je toch 1-2-3 met een regex" die het 'm deed :P Bovendien: er zijn best situaties waarin exceptions ten onrechte gebruikt worden (kan me niet meteen een voorbeeld bedenken, want ben zelf een exceptions-voorstander :P ), maar in je isInteger voorbeeld staat zelfs nergens een "throw ...", hoe kun je dan van exceptions-misbruik spreken?
De voorbeeld code die ik plaatste lijkt me een prachtig voorbeeld van misbruik, imo.
Over het benchmarken: tuurlijk kun je benchmarks schrijven om bijv. zoekalgoritmes te vergelijken of zo, maar je kunt m.i. simpelweg geen benchmark schrijven met als doel "toon aan dat exceptions duur zijn", dat was toch wat Nick probeerde.
Ik probeerde dat helemaal niet ;). Ik toonde aan dat er situaties zijn waarbij exception handling gerust als duur kan bestepeld worden. Dat het geen representatief stuk code is, is zo klaar als een klontje. Ik beschouw het al een slecht stuk code. Maar andere mensen zullen het daar vast mee oneens zijn :>.
.oisyn schreef op maandag 15 maart 2010 @ 12:40:
Klopt. En een van die pitfalls is dat je het probleem isoleert en dat benchmarkt, en daar vervolgens conclusies uit denkt te kunnen trekken. Benchmarken doe je met RL usecases, niet met geisoleerde testcases.
De conclusies die je uit een benchmark trekt zijn maar zo goed als de benchmark. Je kunt prachtige conclusies trekken uit een benchmark. Natuurlijk moet je benchmark wel representatief zijn voor het probleem dat je wil oplossen. Je zou de juiste conclusies moeten kunnen trekken uit je benchmark op voorwaarde dat je het probleem ook daadwerkelijk hebt geïsoleerd. Daar knelt het schoentje wel vaker. De verkeerde stukken code willen optimaliseren gaat je niet de gewenste resultaten opleveren. Maar daar vertel ik natuurlijk niets nieuws ;). Benchmarken doe je met RL use cases of met representatieve use cases. Natuurlijk ga je de verkeerde conclusies trekken als je bv. de prestaties van een hashfunctie probeert vast te stellen door bijvoorbeeld uniform verdeelde elementen te kiezen, terwijl in je RL application object a met frequentie 99% voorkomt en de rest met uniforme kans. Als je op basis van zo'n benchmark conclusies wilt trekken voor je problem at hand dan komt het natuurlijk niet goed. Dat is gewoon een voorbeeld van een benchmark die niet representatief is; hij komt niet overeen met het probleem.

*) FORTRAN heeft geen exception handling mechanisme ... te duur :> :9 8) :+ O-) .

Performance is a residue of good design.


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
terje7601 schreef op maandag 15 maart 2010 @ 13:42:
zou ik vervangen door: "Die code ... gebruikt een standaard Java API methode parseInt, om te kijken ..."
Maar goed, ik begrijp nog steeds niet waar hier nu volgens jou het "misbruik" zit. De code die je gaf is m.i. gewoon de enige zinnige implementatie voor een isInteger methode.
Gewoon met een regex checken is nooit in je opgekomen?
Of een volledig gelijkaardig voorbeeld: stel, je hebt een API beschikbaar met een methode

Java:
1
XMLDocument parseXML(File f) throws DocumentFormatException;


& er wordt je gevraagd een methode te schrijven om na te gaan of een bepaald bestand al dan niet een geldig XML-document is. Dan beweer jij dat je niet iets als:


Java:
1
2
3
4
5
6
7
8
public boolean isXML(File f) {
    try {
        parseXML(f);
        return true;
    } catch(DocumentFormatException e) {
        return false;
    }
}


zou schrijven, omdat dat dan volgens jou "een DocumentFormatException misbruiken" zou zijn?
Als er een equivalent zou zijn in de API die gewoon een bool terug zou geven in plaats van een exception te gooien dan ja.

Bovendien is het bizar om eerst een document te gaan parsen om te checken of het een valid XML file is en deze dan nog eens te gaan parsen als blijkt dat 'ie inderdaad bruikbaar is. Als jij je software op die manier implementeert dan heb je grotere problemen dan of een exception al dan niet relatief zwaar is.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • terje7601
  • Registratie: September 2009
  • Laatst online: 08-02-2024
Hydra schreef op dinsdag 16 maart 2010 @ 00:49:
Gewoon met een regex checken is nooit in je opgekomen?
Nee, want zoals ik al zei: het is m.i. simpelweg onmogelijk om dit met een regex op te lossen, aangezien je ook moet checken of het in de integer-range ligt. En bovendien: als je gebruik maakt van parseInt weet je ook zeker dat je implementatie altijd 100% compatibel blijft, wat niet het geval zou zijn mocht je je eigen regex implementatie schrijven. En als laatste: het zou me lichtelijk verbazen mocht je implementatie sneller zijn, zelfs met een gecompileerde regex.
Maar goed, laat het me zo stellen: ik zal verbaasd zijn als je me ook effectief een regex implementatie kan geven, i.p.v. het gewoon steeds te vermelden ;)
Hydra schreef op dinsdag 16 maart 2010 @ 00:49:
Als er een equivalent zou zijn in de API die gewoon een bool terug zou geven in plaats van een exception te gooien dan ja.
Nogal logisch |:( En hoe denk je dan dat dat equivalent geïmplementeerd zou zijn? ;)
Hydra schreef op dinsdag 16 maart 2010 @ 00:49:
Bovendien is het bizar om eerst een document te gaan parsen om te checken of het een valid XML file is en deze dan nog eens te gaan parsen als blijkt dat 'ie inderdaad bruikbaar is. Als jij je software op die manier implementeert dan heb je grotere problemen dan of een exception al dan niet relatief zwaar is.
Um, zover was ik ook al :X Het was simpelweg mijn bedoeling om een volledig equivalent aan je isInteger-voorbeeld te geven, maar waar je je "doe ik 1-2-3 met een regex"-argument niet meer zou kunnen gebruiken.

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Hydra schreef op dinsdag 16 maart 2010 @ 00:49:
Gewoon met een regex checken is nooit in je opgekomen?
Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.
Gewoon Integer.parseInt() en de exception afvangen is sneller qua ontwikkelsnelheid, en een dingetje

Java:
1
2
3
4
5
6
7
int i = 0;
try {
    i = Integer.parseInt(str);
} catch (NumberFormatException e) {
    LOG.log(Level.SEVERE, e.getMessage(), e);
    // verder niks doen, i blijft 0.
}


kan ik sneller typen dan een regex. Daar komt nog bij, een regex moet altijd uitgevoerd worden en matchen, en /dan/ pas Integer.parseInt() uitvoeren. Een directe aanroep naar Integer.parseInt() levert alleen minder performance als hij daadwerkelijk een exception gooit - en dat is een uitzonderlijk geval, zoals de naam van 'exception' al aangeeft.

Exceptions zijn voor de uitzonderlijke gevallen. Als het mislukken van het parsen van een int vaker voorkomt dan uitzonderlijk, dan pas ga je wat validatie toevoegen, en dan liefst op het punt waar je dat invult.

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
YopY schreef op dinsdag 16 maart 2010 @ 13:41:
kan ik sneller typen dan een regex. Daar komt nog bij, een regex moet altijd uitgevoerd worden en matchen, en /dan/ pas Integer.parseInt() uitvoeren.
/facepalm

Sorry hoor maar waar heb ik in mijn voorbeeld gezegd dat na de check ook meteen die parseint uitgevoerd zou worden? Ik geef een hele simpele case, een check of een getal een integer is, en er worden left right 'n center zaken bijverzonnen 8)7

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Ja, laten we alle gebruik van regexen afdoen met een uit zijn verband getrokken citaat...

Wie trösten wir uns, die Mörder aller Mörder?


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Confusion schreef op dinsdag 16 maart 2010 @ 16:03:
Ja, laten we alle gebruik van regexen afdoen met een uit zijn verband getrokken citaat...
Inderdaad zeg. Regexes zijn in veel gevallen een stuk handiger / beter dan puur kijken of Integer.parseInt de invoer slikt. Voorbeeld van een validation regex: "[0-9]{4}". Volgens mij snapt iedereen wel waar je die voor gebruikt.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • terje7601
  • Registratie: September 2009
  • Laatst online: 08-02-2024
Ok, laat me eens samenvatten:

1) jij geeft een "Voorbeeld van fout gebruik van Exceptions":
Hydra schreef op woensdag 10 maart 2010 @ 18:25:
Voorbeeld van fout gebruik van Exceptions:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
public boolean isInteger(String value)
{
  try
  {
     Integer.parseInt(value);
     return true;
  }
  catch(NumberFormatException e)
  {
     return false;
  }
}
en zegt:
Hydra schreef op donderdag 11 maart 2010 @ 08:08:
Om te checken of iets een int is kun je prima een regex gebruiken.
2) daarop zeg ik dat er m.i. helemaal niets fout aan die code is, & dat het totaal onzinnig is om een functioneel equivalent van die code te schrijven die gebruik maakt van een regex

3) je laatste post schept duidelijkheid:
Hydra schreef op dinsdag 16 maart 2010 @ 16:23:
Regexes zijn in veel gevallen een stuk handiger / beter dan puur kijken of Integer.parseInt de invoer slikt.
Conclusie: het enige wat er "fout" is aan je voorbeeld, is dat de methode nauwelijks bruikbaar is voor de validatie van user-input. Maar er is ook nergens gezegd dat dit het doel van de methode was, dus is er helemaal niets fout aan, & al zeker niets dat met exceptions te maken heeft. Als je het hier niet mee eens bent: geef me een functioneel equivalent van je eigen voorbeeld, met een regex, en leg me dan eens uit in welk opzicht dat equivalent beter is ;)

EDIT: @Nick hieronder: ja kom, zo ver was ik ook al hoor :X Waar het mij om gaat is dat zo 'n equivalent veel complexer, (hoogstwaarschijnlijk) trager, niet meer compatibel zodra er iets aan de parseInt specificatie verandert, ... is. Of in 2 woorden: totaal onzinnig.

[ Voor 10% gewijzigd door terje7601 op 16-03-2010 19:28 . Reden: verduidelijking ]


Acties:
  • 0 Henk 'm!

  • Nick The Heazk
  • Registratie: Maart 2004
  • Laatst online: 07-09-2024

Nick The Heazk

Zie jij er wat in?

terje7601 schreef op dinsdag 16 maart 2010 @ 17:56:
2) daarop zeg ik dat er m.i. helemaal niets fout aan die code is, & dat het onmogelijk is om een functioneel equivalent van die code te schrijven door het gebruik van een regex
Het is perfect mogelijk. Een reguliere expressie, in zijn interpretatie binnen de theorie van formele talen, is perfect in staat om uit te drukken dat enkel de getallen in de range [-xx,+xx] tot de taal behoren. Los daarvan zijn reguliere expressies, zoals ze geïmplementeerd worden in de meeste programmeertalen, ook nog eens in staat om een strikt grotere set van talen te beslissen.
terje7601 schreef op dinsdag 16 maart 2010 @ 17:56:
Als je het hier niet mee eens bent: geef me een functioneel equivalent van je eigen voorbeeld, met een regex & zonder een NumberFormatException ;)
De meest basale reguliere expressie die je de getallen in de range [-xx,+xx] geeft, is gewoon deze die alle getallen opsomt die tot de range behoren. Gaat perfect want de range is eindig. Zo dus: "1|2|3|4|5|6|7|8|9|10|11|12|" enz. Het kan overigens heel wat compacter. Maar hoe je dat doet laat ik jou graag uitvogelen.

[ Voor 18% gewijzigd door Nick The Heazk op 16-03-2010 18:41 ]

Performance is a residue of good design.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-09 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Als je dit met louter een reguliere expressie wilt afvangen begeef je je echter wel in een gebied waar de aangehaalde opmerking door YopY dan weldegelijk van toepassing is.

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!

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Ik neem aan dat iedereen het eleganter vindt om isInteger te implementeren als:

Java:
1
2
3
public boolean isInteger(String value) {
    return (value != null) && value.matches("\\d+"); 
}

Wie trösten wir uns, die Mörder aller Mörder?

Pagina: 1 2 Laatste