Avatar billede fenjas Nybegynder
07. april 2003 - 23:55 Der er 28 kommentarer og
1 løsning

Check af indhold i en streng

Jeg sidder med en String-variabel som jeg meget gerne vil checke for at se om den udelukkende indeholder tal (det skal den meget gerne i det givne tilfælde). Hvordan får jeg mit program til at gøre det?
Avatar billede a_eriksen Nybegynder
07. april 2003 - 23:57 #1
Parse den med Integer.parseInt(String s) den smider en exception hvis der er andet end tal.
Avatar billede disky Nybegynder
08. april 2003 - 00:03 #2
Ja den metode virker, men exceptions er IKKE beregnet til at håndtere ting som IKKE er en exception.

Den pæne måde er at løbe strengen igennem og køre en .isDigit() på alle chars.
Avatar billede fenjas Nybegynder
08. april 2003 - 00:06 #3
Er jeg helt på vildspor når jeg sidder og læser op på try-catch-metoder?

Jeg er vist det vi på vores studie kalder for en java-sinke ;-)
Avatar billede disky Nybegynder
08. april 2003 - 00:13 #4
try/catch er beregnet til at fange uventede fejl, så som at en fil ikke findes, men skal helst ikke misbruges til at gøre ting man forventer vil ske.

F.eks. skal man ikke fange division med nul, når man kan checke i forvejen osv.

Exception handling er håndtering af nødstilfælde, ikke bare fordi man er doven :)

Det skal dog siges try/catch løsningen vil helt klart virke i dette tilfælde, men det tangerer misbrug.
Avatar billede a_eriksen Nybegynder
08. april 2003 - 00:20 #5
Det kunne være sjovt at lave benchmarks på hvad der er hurtigst.
Avatar billede a_eriksen Nybegynder
08. april 2003 - 00:23 #6
Iøvrigt er det vel en "uventet" fejl at der er bogstaver i strengen når nu man forventer at der kun skal være tal :)
Avatar billede disky Nybegynder
08. april 2003 - 00:38 #7
nej det er det ikke, for tror man der kan komme andet end tal, checker man det før.

try/catch løsningen er forresten langsommere, resultat:
test 1 (try/catch)  = 140
test 2 (hjemmelavet)= 20
test 3 (isDigit() ) = 50


/**
* Created by IntelliJ IDEA.
* User: Søren Reinke
* Date: Apr 8, 2003
* Time: 12:21:38 AM
* To change this template use Options | File Templates.
*/
public class Benchmark
{
    private static final int antal=10000;

    private static final String text="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890a";

    public Benchmark()
    {
        long start1=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            test1(text);
        }
        long stop1=System.currentTimeMillis();
        long start2=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            test2(text);
        }
        long stop2=System.currentTimeMillis();
        long start3=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            test3(text);
        }
        long stop3=System.currentTimeMillis();
        System.out.println("test 1 (try/catch)  = "+(stop1-start1) );
        System.out.println("test 2 (hjemmelavet)= "+(stop2-start2) );
        System.out.println("test 3 (isDigit() ) = "+(stop3-start3) );
    }

    private boolean test1(String t)
    {
        try
        {
            int tal=Integer.parseInt(t);
        }
        catch (NumberFormatException e)
        {
            return false;
        }
        return true;
    }

    private boolean test2(String t)
    {
        int len=t.length();
        char temp;
        for(int x=0;x<len;x++)
        {
            temp=t.charAt(x);
            if(temp<'0' || temp>'9')
            {
                return false;
            }
        }
        return true;
    }

    private boolean test3(String t)
    {
        int len=t.length();
        for(int x=0;x<len;x++)
        {
            if(!Character.isDigit(t.charAt(x)))
            {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args)
    {
        new Benchmark();
    }
}
Avatar billede disky Nybegynder
08. april 2003 - 00:40 #8
Selv ved 10000 tal før et bogstav, er min hjemmelavede stadigvæk mere end dobbelt så hurtig. !!

Altså der er slet ingen grund overhovedet til at springe over hvor gærdet er lavest.
Avatar billede a_eriksen Nybegynder
08. april 2003 - 00:40 #9
Tja, der kan man bare se..
Avatar billede disky Nybegynder
08. april 2003 - 00:41 #10
Som sagt try/catch skal kun bruges til 'exceptions' altså tilfælde man IKKE kan beskytte sig imod på forhånd, f.eks. at en socket forbindelse mistes osv.
Avatar billede a_eriksen Nybegynder
08. april 2003 - 00:44 #11
Jeg er generelt enig med dig, jeg havde nok bare forventet at det interne check ville være hurtigere.
Avatar billede disky Nybegynder
08. april 2003 - 00:46 #12
:-)
Avatar billede a_eriksen Nybegynder
08. april 2003 - 00:55 #13
Men du glemte iøvrigt at lave den parse det hele handlede om i de to sidste funktioner :)
Avatar billede fenjas Nybegynder
08. april 2003 - 00:57 #14
Er det derfor jeg ikke kan få det til at virke når jeg prøver at bruge den sidste model?
Avatar billede a_eriksen Nybegynder
08. april 2003 - 01:00 #15
Kun hvis du forventer at der kommer et tal ud af dem
Avatar billede disky Nybegynder
08. april 2003 - 01:02 #16
a_eriksen:
Hvad mener du ?

Mine check her returnerer 'true' hvis der kun er tal i streng, og ellers false.

Ud fra dette kan man så lave en Integer.parseInt() bagefter hvis svaret er true.

Selvfølgelig kan metoderne rettes til så de automatisk returnerer tallet som en int, eller f.eks. -1 hvis der er en fejl.
Avatar billede a_eriksen Nybegynder
08. april 2003 - 01:10 #17
Jeg mener bare at testen næsten er nyttesløs hvis ikke man fortager konverteringen bagefter. Spørgsmålet er så hvor lang tid det tager parseInt at køre hvis man først har sikret sig at strengen kun indeholder tal.
Avatar billede disky Nybegynder
08. april 2003 - 01:26 #18
ja jeg må skuffe dig så bliver det bare endnu værrere:

test 1 (try/catch)  = 842
test 2 (hjemmelavet)= 10
test 3 (isDigit() ) = 50

/**
* Created by IntelliJ IDEA.
* User: Søren Reinke
* Date: Apr 8, 2003
* Time: 12:21:38 AM
* To change this template use Options | File Templates.
*/
public class Benchmark
{
    private static final int antal=100000;

    private static final String text="0123456a789";

    public Benchmark()
    {
        long start1=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            int tal=test1(text);
        }
        long stop1=System.currentTimeMillis();
        long start2=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            int tal=test2(text);
        }
        long stop2=System.currentTimeMillis();
        long start3=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            int tal=test3(text);
        }
        long stop3=System.currentTimeMillis();
        System.out.println("test 1 (try/catch)  = "+(stop1-start1) );
        System.out.println("test 2 (hjemmelavet)= "+(stop2-start2) );
        System.out.println("test 3 (isDigit() ) = "+(stop3-start3) );
    }

    private int test1(String t)
    {
        try
        {
            int tal=Integer.parseInt(t);
        }
        catch (NumberFormatException e)
        {
            return -1;
        }
        return Integer.parseInt(t);
    }

    private int test2(String t)
    {
        int len=t.length();
        char temp;
        for(int x=0;x<len;x++)
        {
            temp=t.charAt(x);
            if(temp<'0' || temp>'9')
            {
                return -1;
            }
        }
        return Integer.parseInt(t);

    }

    private int test3(String t)
    {
        int len=t.length();
        for(int x=0;x<len;x++)
        {
            if(!Character.isDigit(t.charAt(x)))
            {
                return -1;
            }
        }
        return Integer.parseInt(t);

    }

    public static void main(String[] args)
    {
        new Benchmark();
    }
}
Avatar billede a_eriksen Nybegynder
08. april 2003 - 01:32 #19
Tror du ikke du er ved at være træt? Du har jo parset én gang i test1 :)
Men nok om det, det var da meget sjovt at kigge på.
Avatar billede disky Nybegynder
08. april 2003 - 01:37 #20
hvad snakker du om ?

Jeg laver den samme konvertering på 3 forskellige måder netop for at fremhæve din løsning er performance mæssigt en særdeles dårlig ide. Så selvfølgelig gentager jeg det igen mange gange, og på flere måder for at understrege min påstand. Er det ikke nærmere dig der ikke vil acceptere din løsning er brugbar bare ikke særlig smart ?

At det sidste eksempel viste det rigtigt meget skyldes at de store tal bestående af 100 cifre alligevel ikke kan være i en int, så derfor er længden af strengen kortet ned til en størrelse der er realistisk.
Avatar billede a_eriksen Nybegynder
08. april 2003 - 01:52 #21
Det jeg mente var at i test1 funktionen udfører du parseInt to gange hvilket der ikke er noget formål med i forhold til benchmarken.

private int test1(String t)
    {
        try
        {
            return Integer.parseInt(t);
        }
        catch (NumberFormatException e)
        {
            return -1;
        }
    }
Avatar billede disky Nybegynder
08. april 2003 - 01:56 #22
fair nok :)
  private int test1(String t)
    {
        int tal;
        try
        {
            tal=Integer.parseInt(t);
        }
        catch (NumberFormatException e)
        {
            tal=-1;
        }
        return tal;
    }

Dog er try/catch metoden stadigvæk en del langsomere, her er tallene ved 1000000 gennemløb:
test 1 (try/catch)  = 7641
test 2 (hjemmelavet)= 90
test 3 (isDigit() ) = 420

Som sagt kan try/catch sagtens bruges i en håndevending, men tilrådeligt er det bestemt ikke. Jeg kan ikke huske hvad det specifik er en try/catch gør på JVM niveau, men der sker en hel del nede i JVM'en
Avatar billede arne_v Ekspert
08. april 2003 - 09:03 #23
Øh.

Lige et par kommentarer !

1)  Den benchmark viser tydeligt at try-catch er meget langsommere
    hvis alle kaldene fejler.

    Hvis man laver en benchmark hvor ingen kald fejler, så er try-catch
    faktisk hurtigst.

    Så udfra en performance betragtning afhænger det bedste af
    hvad den forventede fejl procent er.

2)  Vær iøvrigt opmærksom på at test1 accepterer negative integers
    men at test2 og test3 ikke gør det.
Avatar billede arne_v Ekspert
08. april 2003 - 09:05 #24
Med hensyn til hvad jeg selv ville gøre, så ville jeg nok
enten bruge try-catch eller Character.isDigit lidt afhængig
af humøret den pågældende dag.

For decimal tal ville det blive try-catch. Det er bare for bøvlet at
validere sådanne.
Avatar billede disky Nybegynder
08. april 2003 - 10:18 #25
Arne:
try/catch er minimalt hurtigere end test2 hvis der ikke opstår fejl.
Vi snakker om 30 ms ved 1*10^6 tests på en P4 1.7 GHz

Her er resultatet fra 1*10^6 tests hvor strengen indenholder '-123456789'
test 1 (try/catch)  = 661
test 2 (hjemmelavet)= 701
test 3 (isDigit() ) = 1081

Her hvor der er et bogstav: -123456789a
test 1 (try/catch)  = 7771
test 2 (hjemmelavet)= 120
test 3 (isDigit() ) = 501

Hvilket igen tydeligt viser, man skal ikke bruge try/catchs til den slags, da hvis man ryger ind i catch så betaler man dyrt i performance.

Rent performancemæssigt er prisen for at bruge test2 meget lille i forhold til prisen hvis test1 fejler.

Som sagt try/catch skal bruges til situationer hvor man ikke kan sikre at man ikke lander i catch på forhånd, da prisen er høj rent performance mæssigt.
Avatar billede arne_v Ekspert
08. april 2003 - 10:51 #26
disky>

Det argument køber jeg ikke.

De to mest sandsynelige scenarier er:

meget få kald og en vis sandsynelighed for fejl (manuel indtastning)

rigtigt mange kald og meget lille sandsynelighed for fejl (læsning fra fil)

og i det første tilfælde er try-catch overheadet ligegyldigt og i
det andet tilfælde er try-catch hurtigere.
Avatar billede disky Nybegynder
08. april 2003 - 10:53 #27
Selv den lille sansynlighed er nok til at man får dårligere performance.
Men fair nok, hvis du gerne vil have det, er det da helt fint.
Avatar billede arne_v Ekspert
08. april 2003 - 11:09 #28
Nope.

Man skal over 1% i fejl hyppighed for a try-catch er langsommere.

1% fejl er absolut ikke urealistisk ved en manuel indtastning.

Men alt for stort ved læsning fra fil.

Jeg ville ikke optimere et program som skal læse 1 million tal fra en fil
udfra en forudsætning om at der nok er over 10000 tal der p.g.a.
fejl indeholder bogstaver.
Avatar billede disky Nybegynder
08. april 2003 - 12:06 #29
og som sædvanligt bliver du ved og ved og ved og ved, kører du på duracell ?
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester



IT-JOB