Provjerite je li niz numerički na Javi

1. Uvod

Često dok operiram Nizs, moramo shvatiti je li a Niz je valjani broj ili ne.

U ovom uputstvu istražit ćemo više načina za otkrivanje da li je dato Niz je numerički, prvo pomoću obične Java, zatim regularnih izraza i na kraju korištenjem vanjskih knjižnica.

Kad završimo s raspravom o raznim implementacijama, upotrijebit ćemo mjerila kako bismo stekli ideju koje su metode optimalne.

2. Preduvjeti

Krenimo s nekim preduvjetima prije nego što prijeđemo na glavni sadržaj.

U drugom dijelu ovog članka koristit ćemo vanjsku knjižnicu Apache Commons za koju ćemo dodati njezinu ovisnost u našu pom.xml:

 org.apache.commons commons-lang3 3.9 

Najnoviju verziju ove knjižnice možete pronaći na Maven Central.

3. Korištenje obične Jave

Možda najlakši i najpouzdaniji način provjere je li Niz je numerički ili nije raščlanjivanjem pomoću ugrađenih Javinih metoda:

  1. Integer.parseInt (String)
  2. Float.parseFloat (niz)
  3. Double.parseDouble (niz)
  4. Long.parseLong (String)
  5. novi BigInteger (niz)

Ako ove metode ne bace nijednu NumberFormatException, onda to znači da je raščlanjivanje bilo uspješno i Niz je numerički:

javna statička logička vrijednost isNumeric (Niz strNum) {if (strNum == null) {return false; } probajte {double d = Double.parseDouble (strNum); } catch (NumberFormatException nfe) {return false; } return true; }

Pogledajmo ovu metodu na djelu:

assertThat (isNumeric ("22")). isTrue (); assertThat (isNumeric ("5.05")). isTrue (); assertThat (isNumeric ("- 200")). isTrue (); assertThat (isNumeric ("10.0d")). isTrue (); assertThat (isNumeric ("22")). isTrue (); assertThat (isNumeric (null)). isFalse (); assertThat (isNumeric ("")). isFalse (); assertThat (isNumeric ("abc")). isFalse ();

U našem isNumeric () metodom, samo provjeravamo vrijednosti koje su tipa Dvostruko, ali ova se metoda također može izmijeniti kako bi se provjerilo Cijeli broj, Plutati, Dugo i veliki broj korištenjem bilo koje od metoda raščlanjivanja koje smo prethodno naveli.

O tim se metodama govori i u članku Java String Conversions.

4. Korištenje regularnih izraza

Sada se poslužimo regularnim izrazom -? \ d + (\. \ d +)? podudarati se s brojčanim Žice koji se sastoji od pozitivnog ili negativnog cijelog broja i pluta.

Ali to se podrazumijeva, da definitivno možemo modificirati ovaj regularni izraz kako bismo identificirali i rukovali širokim rasponom pravila. Ovdje ćemo biti jednostavni.

Razbijemo ovaj regularni izraz i pogledajmo kako on funkcionira:

  • -? - ovaj dio identificira je li zadani broj negativan, crtica “"Traži crticu doslovno i upitnik"?”Označava svoju prisutnost kao neobvezujuću
  • \ d + - ovo traži jednu ili više znamenki
  • (\. \ d +)? - ovaj je dio regularnog izraza identificirati brojeve s plutajućim brojem. Ovdje tražimo jednu ili više znamenki nakon kojih slijedi točka. Znak pitanja na kraju znači da ova cjelovita grupa nije obavezna

Regularni izrazi vrlo su široka tema. Da biste dobili kratki pregled, pogledajte naš vodič o API-ju Java regularnih izraza.

Za sada, izradimo metodu koristeći gornji regularni izraz:

private Pattern pattern = Pattern.compile ("-? \ d + (\. \ d +)?"); javni boolean isNumeric (Niz strNum) {if (strNum == null) {return false; } return pattern.matcher (strNum) .matches (); }

Pogledajmo sada neke tvrdnje za gornju metodu:

assertThat (isNumeric ("22")). isTrue (); assertThat (isNumeric ("5.05")). isTrue (); assertThat (isNumeric ("- 200")). isTrue (); assertThat (isNumeric (null)). isFalse (); assertThat (isNumeric ("abc")). isFalse ();

5. Korištenje Apache Commons

U ovom ćemo odjeljku razgovarati o različitim metodama dostupnim u biblioteci Apache Commons.

5.1. NumberUtils.isCreatable (niz)

NumberUtils tvrtke Apache Commons pruža statičku metodu NumberUtils.isCreatable (niz) koja provjerava je li a Niz je li valjani Java broj ili nije.

Ova metoda prihvaća:

  1. Heksadecimalni brojevi koji počinju s 0x ili 0X
  2. Oktalni brojevi koji počinju s vodećom 0
  3. Znanstveni zapis (na primjer 1,05e-10)
  4. Brojevi označeni kvalifikatorom tipa (na primjer 1L ili 2.2d)

Ako je isporučeni niz null ili prazno / prazno, tada se to ne smatra brojem i metoda će se vratiti lažno.

Pokrenimo neke testove pomoću ove metode:

assertThat (NumberUtils.isCreatable ("22")). isTee (); assertThat (NumberUtils.isCreatable ("5.05")). isTee (); assertThat (NumberUtils.isCreatable ("- 200")). isTee (); assertThat (NumberUtils.isCreatable ("10.0d")). isTrue (); assertThat (NumberUtils.isCreatable ("1000L")). isTee (); assertThat (NumberUtils.isCreatable ("0xFF")). isTrue (); assertThat (NumberUtils.isCreatable ("07")). isTrue (); assertThat (NumberUtils.isCreatable ("2.99e + 8")). isTrue (); assertThat (NumberUtils.isCreatable (null)). isFalse (); assertThat (NumberUtils.isCreatable ("")). isFalse (); assertThat (NumberUtils.isCreatable ("abc")). isFalse (); assertThat (NumberUtils.isCreatable ("22")). isFalse (); assertThat (NumberUtils.isCreatable ("09")). isFalse ();

Primijetite kako napredujemo pravi tvrdnje za heksadecimalne brojeve, oktalne brojeve i znanstvene oznake u redovima 6, 7 i 8.

Također, u retku 14, niz “09” vraća se lažno jer prethodni “0” označava da je ovo osmički broj i “09” nije valjani oktalni broj.

Za svaki ulaz koji se vrati pravi ovom metodom možemo koristiti NumberUtils.createNumber (String) što će nam dati valjani broj.

5.2. NumberUtils.isParsable (String)

The NumberUtils.isParsable (String) metoda provjerava je li zadana Niz je rastavljiv ili nije.

Analizirajući brojevi su oni koji se uspješno raščlanjuju bilo kojom metodom raščlanjivanja poput Integer.parseInt (String), Long.parseLong (String), Float.parseFloat (niz) ili Double.parseDouble (niz).

Za razliku od NumberUtils.isCreatable (), ova metoda neće prihvatiti heksadecimalne brojeve, znanstvene zapise ili nizove koji završavaju bilo kojim kvalifikatorom tipa, to jest, "F", "F", "d", "D", "l"ili"L".

Pogledajmo neke potvrde:

assertThat (NumberUtils.isParsable ("22")). isTee (); assertThat (NumberUtils.isParsable ("- 23")). isTrue (); assertThat (NumberUtils.isParsable ("2.2")). isTee (); assertThat (NumberUtils.isParsable ("09")). isTee (); assertThat (NumberUtils.isParsable (null)). isFalse (); assertThat (NumberUtils.isParsable ("")). isFalse (); assertThat (NumberUtils.isParsable ("6.2f")). isFalse (); assertThat (NumberUtils.isParsable ("9.8d")). isFalse (); assertThat (NumberUtils.isParsable ("22L")). isFalse (); assertThat (NumberUtils.isParsable ("0xFF")). isFalse (); assertThat (NumberUtils.isParsable ("2.99e + 8")). isFalse ();

Na liniji 4, za razliku od NumberUtils.isCreatable (), broj koji počinje s nizom “0” ne smatra se osminskim brojem, već normalnim decimalnim brojem i stoga vraća vrijednost true.

Ovu metodu možemo koristiti kao zamjenu za ono što smo učinili u odjeljku 3, gdje pokušavamo raščlaniti broj i provjeriti postoji li pogreška.

5.3. StringUtils.isNumeric (CharSequence)

Metoda StringUtils.isNumeric (CharSequence) strogo provjerava Unicode znamenke. To znači:

  1. Bilo koje znamenke iz bilo kojeg jezika koji je Unicode znamenka su prihvatljive
  2. Budući da se decimalna točka ne smatra Unicode znamenkom, ona nije valjana
  3. Vodeći znakovi (bilo pozitivni ili negativni) također nisu prihvatljivi

Pogledajmo sada ovu metodu na djelu:

assertThat (StringUtils.isNumeric ("123")). isTrue (); assertThat (StringUtils.isNumeric ("١٢٣")). isTrue (); assertThat (StringUtils.isNumeric ("१२३")). isTrue (); assertThat (StringUtils.isNumeric (null)). isFalse (); assertThat (StringUtils.isNumeric ("")). isFalse (); assertThat (StringUtils.isNumeric ("")). isFalse (); assertThat (StringUtils.isNumeric ("12 3")). isFalse (); assertThat (StringUtils.isNumeric ("ab2c")). isFalse (); assertThat (StringUtils.isNumeric ("12.3")). isFalse (); assertThat (StringUtils.isNumeric ("- 123")). isFalse ();

Imajte na umu da ulazni parametri u redovima 2 i 3 predstavljaju brojeve 123 na arapskom, odnosno na devanagariju. Budući da su to važeće Unicode znamenke, ova se metoda vraća pravi na njima.

5.4. StringUtils.isNumericSpace (CharSequence)

The StringUtils.isNumericSpace (CharSequence) strogo provjerava Unicode znamenke i / ili razmak. Ovo je isto kao StringUtils.isNumeric () s jedinom razlikom u tome što prihvaća i razmake, ne samo vodeće i prateće razmake već i ako su između brojeva:

assertThat (StringUtils.isNumericSpace ("123")). isTrue (); assertThat (StringUtils.isNumericSpace ("١٢٣")). isTrue (); assertThat (StringUtils.isNumericSpace ("")). isTrue (); assertThat (StringUtils.isNumericSpace ("")). isTrue (); assertThat (StringUtils.isNumericSpace ("12 3")). isTrue (); assertThat (StringUtils.isNumericSpace (null)). isFalse (); assertThat (StringUtils.isNumericSpace ("ab2c")). isFalse (); assertThat (StringUtils.isNumericSpace ("12.3")). isFalse (); assertThat (StringUtils.isNumericSpace ("- 123")). isFalse ();

6. Mjerila

Prije nego što završimo ovaj članak, prođimo kroz neke referentne rezultate koji će nam pomoći da analiziramo koje su od gore spomenutih metoda najbolje za naš slučaj upotrebe.

6.1. Jednostavno mjerilo

Prvo, pristupamo jednostavnom pristupu. Odabiremo jednu vrijednost niza - za naš test koji koristimo Cijeli broj.MAX_VALUE. Zatim će se ta vrijednost testirati u odnosu na sve naše implementacije:

Benchmarking.usingCoreJava avgt 20 57,241 ± 0,792 ns / op Benchmarking.usingNumberUtils_isCreatable avgt 20 26,711 ± 1,110 ns / op Benchmarking.usingNumberUtils_isParsable avgt 20 46,577 ± 1,93m Benchmarking.usingStringUtils_isNumeric avgt 20 35.885 ± 1.691 ns / op Benchmarking.usingStringUtils_isNumericSpace avgt 20 31.979 ± 1.393 ns / op

Kao što vidimo, najskuplje operacije su regularni izrazi. Nakon toga je naše osnovno rješenje temeljeno na Javi.

Štoviše, imajte na umu da su operacije korištenjem biblioteke Apache Commons u velikoj mjeri iste.

6.2. Poboljšano mjerilo

Upotrijebimo raznolikiji skup testova za reprezentativnije mjerilo:

  • 95 vrijednosti su numeričke (0-94 i Cijeli broj.MAX_VALUE)
  • 3 sadrže brojeve, ali su i dalje neispravni -x0‘, ‘0..005′, i ‘–11
  • 1 sadrži samo tekst
  • 1 je a null

Nakon izvršavanja istih testova, vidjet ćemo rezultate:

Benchmarking.usingCoreJava avg 20 10162.872 ± 798.387 ns / op Benchmarking.usingNumberUtils_isCreatable avgt 20 1703.243 ± 108.244 ns / op Benchmarking.usingNumberUtils_isParsable avgt. Benchmarking.usingStringUtils_isNumeric avgt 20 1071.753 ± 8.657 ns / op Benchmarking.usingStringUtils_isNumericSpace avgt 20 1157.722 ± 24.139 ns / op

Najvažnija razlika je u tome što su se dva naša testa - rješenje regularnih izraza i osnovno rješenje temeljeno na Javi - zamijenila.

Iz ovog rezultata saznajemo da je bacanje i rukovanje NumberFormatException, koji se javlja u samo 5% slučajeva, ima relativno velik utjecaj na cjelokupnu izvedbu. Dakle, zaključujemo, da optimalno rješenje ovisi o našem očekivanom unosu.

Također, možemo sigurno zaključiti da bismo za optimalne performanse trebali koristiti metode iz biblioteke Commons ili metodu implementiranu na sličan način.

7. Zaključak

U ovom smo članku istražili različite načine kako pronaći ako Niz je numerički ili nije. Pregledali smo oba rješenja - ugrađene metode i također vanjske knjižnice.

Kao i uvijek, implementacija svih gore navedenih primjera i isječaka koda, uključujući kod koji se koristi za izvođenje mjerila, može se naći na GitHubu.