• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Bloki try/catch czy throw

VPS Starter Arubacloud
0 głosów
625 wizyt
pytanie zadane 3 lipca 2018 w Java przez periedynek Obywatel (1,320 p.)

Cześć, piszę konwerter zamian liczb rzymskich na arabskie.

Potrzebuję dopisać sytuację, gdy ktoś wpiszę liczby arabskie bądź litery inne niż rzymskie.

Warunek wyglądałby tak:

if(romanNumber.matches("[0-9]") || !romanNumber.matches("[MDCLXVI]")){
        ...
    }

I teraz nie wiem czy mam stworzyć osobną klasę RomanException, czy jakoś to ulokować w blokach try/catch. Nie mam pomysłu, bo się gubię w tym throw.

 

package TrainingApp;

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        int current = 0;
        int previous = 0;
        int sum = 0;
        try {

            String romanNumber = input.next();
            input.close();
            romanNumber = romanNumber.toUpperCase();

            char romanArray[] = romanNumber.toCharArray();
            for (int i = 0; i < romanNumber.length(); i++) {
                char letter = romanArray[i];

                switch (letter) {
                    case 'I': {
                        current = 1;
                        break;
                    }
                    case 'V': {
                        current = 5;
                        break;
                    }
                    case 'X': {
                        current = 10;
                        break;
                    }
                    case 'L': {
                        current = 50;
                        break;
                    }
                    case 'C': {
                        current = 100;
                        break;
                    }
                    case 'D': {
                        current = 500;
                        break;
                    }
                    case 'M': {
                        current = 1000;
                        break;
                    }
                }

                if (current > previous) {
                    sum += current - 2 * previous;
                } else {
                    sum += current;
                }
                previous = current;
            }
        } catch (RomanException e) {

        }

        System.out.println(sum);
    }
}

 

komentarz 3 lipca 2018 przez periedynek Obywatel (1,320 p.)

Zrobiłem tak:

package TrainingApp;

import java.util.Scanner;

public class Main {

    public static void main(String[] args) throws RomanException {
        Scanner input = new Scanner(System.in);

        int current = 0;
        int previous = 0;
        int sum = 0;

        String romanNumber = input.next();
        input.close();
        romanNumber = romanNumber.toUpperCase();

        if (romanNumber.matches("[0-9]") || !romanNumber.matches("[MDCLXVI]")) {
            throw new RomanException();
        }

        char romanArray[] = romanNumber.toCharArray();
        for (int i = 0; i < romanNumber.length(); i++) {
            char letter = romanArray[i];

            switch (letter) {
                case 'I': {
                    current = 1;
                    break;
                }
                case 'V': {
                    current = 5;
                    break;
                }
                case 'X': {
                    current = 10;
                    break;
                }
                case 'L': {
                    current = 50;
                    break;
                }
                case 'C': {
                    current = 100;
                    break;
                }
                case 'D': {
                    current = 500;
                    break;
                }
                case 'M': {
                    current = 1000;
                    break;
                }
            }

            if (current > previous) {
                sum += current - 2 * previous;
            } else {
                sum += current;
            }
            previous = current;
        }

        System.out.println(sum);
    }
}

I druga klasa:

RomanException

package TrainingApp;

public class RomanException extends Exception {

    public String toString() {
        return "You've written digits or wrong letters";
    }

}

Nie wiem czy jest to dobra praktyka.

 

Btw. Nie pytajcie dlaczego pakunek nazywa sie TrainingApp. Przy tworzeniu coś kliknąłem i jest to stary pakunek.

2 odpowiedzi

+2 głosów
odpowiedź 3 lipca 2018 przez Tomek Sochacki Ekspert (227,510 p.)

Nie znam jakoś super Javy ale tak na pierwszy rzut oka to chyba zapomniałeś o paru warunkach dla zbadania poprawności zapisu liczby rzymskiej, np. o fakcie, że litery stojące obok siebie mogą wystąpić max 3 razy, dlatego dla cyfry 4 poprawny jest zapis IV ale IIII nie, ponieważ "I" może być powtórzony max 3 razy. W związku z tym mamy też ograniczenie na maksymalną liczbę w zapisie podstawowym na 3999. Powyżej tej liczby w oryginalnym zapisie rzymskim stosowane są dodatkowe "kreski" pionowe i poziome ale wątpię abyś chciał się w to bawić w tym programie, zresztą w praktyce liczby rzymskie w powszechnym użytku nie przekraczają właśnie 3999.

Dodatkowo jeśli już robisz regexp do tej walidacji to proponowałbym od razu sprawdzić właśnie pełną poprawność liczby, np. wzorcem:

^(?=[MDCLXVI])M{0,3}(?:C[MD]|D?C{0,3})(?:X[CL]|L?X{0,3})(?:I[XV]|V?I{0,3})$/

który zwaliduje nam również wspomniane ponad trzykrotne powtórzenia liczb. Dodatkowo trzeba też pamiętać, że litery w pewnych konfiguracjach dają różnicę, np. CM oznacza 1000-100=900 (M-1000, C-100).

komentarz 3 lipca 2018 przez periedynek Obywatel (1,320 p.)

Tak, wiem że nie mam takiego warunku, ale nie wiedziałem jak go zrobić. 

Z tego wzorca widzę, że właśnie tak to trzeba zrobić.

 

To o czym piszesz później czyt. CM to działa i jest zastosowane w warunku:


if (current > previous) {
                    sum += current - 2 * previous;
                } else {
                    sum += current;
                }
                previous = current;
            }

 

1
komentarz 3 lipca 2018 przez Tomek Sochacki Ekspert (227,510 p.)
ok, spoko, nie zauważyłem, to tylko kwestia tego powtarzania się liczb i ogólnego maxa na 3999 i będzie całkiem fajny programik :)
1
komentarz 3 lipca 2018 przez Tomek Sochacki Ekspert (227,510 p.)
"[MDCLXVI]"{0,3}

chyba źle cudzysłów, nie powinno być:

"[MDCLXVI]{0,3}"

?

komentarz 3 lipca 2018 przez periedynek Obywatel (1,320 p.)

Takie coś zrobiłem:

if (romanNumber.matches("[0-9]") || !romanNumber.matches("[MDCLXVI]*") || romanNumber.matches("[MDCLXVI]{0,3}"))

Ale niestety nie działa. Wiesz o co chodzi? Pierwszy raz tego regexpa używam.

1
komentarz 3 lipca 2018 przez Tomek Sochacki Ekspert (227,510 p.)

ale nawet jeśli, to regex:

"[MDCLXVI]{0,3}"

sprawdzasz tylko czy jedna z liter spełnia ten warunek :) i ponad to musiałaby być flaga początku i końca... bo jako poprawny zrobisz ciąg "MMMM" ponieważ regexp dopasuje trzy litery M i dalszą się nie zainteresuje... nie masz w regexp żadnych granic.

 

komentarz 3 lipca 2018 przez periedynek Obywatel (1,320 p.)
Dobra. Działa :) Od 4 powtórzeń się usuwa. Wystarczyło dodać negację tego wszystkiego :)

Dzieki.
1
komentarz 3 lipca 2018 przez Tomek Sochacki Ekspert (227,510 p.)
/[MDCLXVI]{0,3}/.test('MMM');  //true
/[MDCLXVI]{0,3}/.test('MMMM'); //true

Wzorzec szuka tylko czy litera M znajduje się od 0 do  razy i w obu ciągach ten warunek jest spełniony. Spróbuj przeanalizować sobie mojego regexp, jakbyś miał problem to mogę go rozpisać dokładniej, ale obadaj go sobie na:

https://regexper.com/#%2F%5E%28%3F%3D%5BMDCLXVI%5D%29M%7B0%2C3%7D%28%3F%3AC%5BMD%5D%7CD%3FC%7B0%2C3%7D%29%28%3F%3AX%5BCL%5D%7CL%3FX%7B0%2C3%7D%29%28%3F%3AI%5BXV%5D%7CV%3FI%7B0%2C3%7D%29%24%2F

komentarz 3 lipca 2018 przez periedynek Obywatel (1,320 p.)

Tak, to prawda, ale zrobiłem coś takiego:

if (romanNumber.matches("[0-9]") || !romanNumber.matches("[MDCLXVI]*") || !romanNumber.matches("[MDCLXVI]{0,3}"))

Przez co teraz mamy warunek, jeśli NIE będzie od 0 do 3 tych liter, to wywala wyjątek.

komentarz 4 lipca 2018 przez periedynek Obywatel (1,320 p.)

Jednak jest problem i to dziwny problem. Nie wiem o co chodzi.

Dla niektórych liczb działa, a dla niektóych nie. Przykładowo dla liczby CMXCIX program się wywala.

To chodzi właśnie o ten ostatni warunek, bo bez niego działa, a z nim nie. Tylko nie wiem czemu, bo tak jak u góry już właśnie wspomniałem jeśli NIE będzie od 0 do 3 tych liter, to wywala wyjątek. A on wywala dla takiej np. liczby.

Cały kod wygląda tak, ale łatwo sprawdzić, że to właśnie o to chodzi.

 public static void main(String[] args) throws RomanException {
        Scanner input = new Scanner(System.in);

        int current = 0;
        int previous = 0;
        int sum = 0;

        String romanNumber = input.next();
        input.close();
        romanNumber = romanNumber.toUpperCase();

        if (romanNumber.matches("[0-9]") || !romanNumber.matches("[MDCLXVI]*") || !romanNumber.matches("[MDCLXVI]{0,3}")) {
            throw new RomanException();
        }

        char romanArray[] = romanNumber.toCharArray();
        for (int i = 0; i < romanNumber.length(); i++) {
            char letter = romanArray[i];

            switch (letter) {
                case 'I': {
                    current = 1;
                    break;
                }
                case 'V': {
                    current = 5;
                    break;
                }
                case 'X': {
                    current = 10;
                    break;
                }
                case 'L': {
                    current = 50;
                    break;
                }
                case 'C': {
                    current = 100;
                    break;
                }
                case 'D': {
                    current = 500;
                    break;
                }
                case 'M': {
                    current = 1000;
                    break;
                }
            }

            if (current > previous) {
                sum += current - 2 * previous;
            } else {
                sum += current;
            }
            previous = current;
        }

        System.out.println(sum);
    }

 

komentarz 4 lipca 2018 przez Tomek Sochacki Ekspert (227,510 p.)
poczytaj co oznacza gwiazdka i kwantyfikator w klamerkach, używasz jednej albo drugiej formy nie możesz na jednym elemencie operować dwoma różnymi kwantyfikatorami. A czemu nie chcesz użyć tego wzorca co Ci zaproponowałem?
komentarz 4 lipca 2018 przez periedynek Obywatel (1,320 p.)

Nie rozumiem Cie o którą teraz część chodzi i która jest zła. 

[MDCLXVI] - chodzi o wystepowanie tych ltierek
{0,3} - ile minimum i ile maksimum może ich być

Nie używam tego wzorca, ponieważ wydaje mi się on tutaj niepotrzebny i za dużo jest ogólnie myślenia co poszczególne znaki znaczą. A tutaj mam metodę "matches" i wystarczą mi te niby 3 warunki by spełnić cały ten wzorzec.

komentarz 4 lipca 2018 przez periedynek Obywatel (1,320 p.)

Teraz widzę, że gwiazdka oznacza, ze coś występuje więcej albo więcej razy, więc faktycznie to się myiliło.

Teraz nie rozumiem w takim razie drugiego warunku:

!romanNumber.matches("[MDCLXVI]*

Dlaczego po usunięciu gwiazdki już nie działa? Skoro to się odnosi do innych literek niż podane w nawiasach kwadratowych.

Pomijając to, nie wiem tez jak dalej zrobic ten 3 warunek.


 

komentarz 4 lipca 2018 przez Tomek Sochacki Ekspert (227,510 p.)

Dlaczego po usunięciu gwiazdki już nie działa? Skoro to się odnosi do innych literek niż podane w nawiasach kwadratowych.

A na jakiej podstawie uważasz, że odnosi się do innych liter niż te z nawiasów? Ty negujesz wartość zwracaną przez funkcję matches a nie ingerujesz  regexp. Dopasowanie wszystkiego po za literą A, B lub C to:

[^ABC]

a tak w ogóle to musisz zastanowić się co robią Twoje regexp. Zobaczmy co chcesz dopasować...

  1. Czy wzorzec [MDCLXVI]{0,3} dopasuje się do ciągu "MMM"? Tak dopasuje się, ponieważ znajdzie literę M występującą od 0 do 3 razy. (dokładniej mówiąc dopasuje 3 wystąpienia bo to kwantyfikator zachłanny ale to teraz nieistotne)
  2. Czy wzorzec [MDCLXVI]{0,3} dopasuje się do ciągu "MMMM"? Tak dopasuje się, ponieważ znajdzie literę M występującą od 0 do 3 razy i gdy to osiągnie to kończy działanie i nie interesuje się dalszymi literami czyli czwartą "M" bo nie musi tego robić.
  3. Czy wzorzec [MDCLXVI]{0,3} dopasuje się do ciągu "CMMMM"? Tak dopasuje się, ponieważ znajdzie literę C występującą od 0 do 3 razy i znowu nie interesuje się dalszymi literami.

Otóż wzorzec ten szuka litery M, lub D, lub C ... która wystąpi od 0 do 3 razy. Interesuje go tylko takie fragment ciągu. Nie masz tu żadnych granic dopasowania więc nie analizujesz ciągu jako jednego fragmentu pasującego jako całość.

Z chęcią pomogę w kwestii regexp ale nie będę omawiał tu na forum od podstaw całej składni itp. (od tego napisałem książkę o regexp :P). Poczytaj sobie o podstawach regexp i z chęcią wtedy wrócę do tematu.

Pozdrawiam

komentarz 4 lipca 2018 przez periedynek Obywatel (1,320 p.)

Zgupiałem już szczerze mówiąc.

Potrzebuje 3 warunki

1) W inpucie nie wystąpi żadna liczba, robi to ten warunek: 

romanNumber.matches("[0-9]")

2) Nie będzie żadnej innej litery niż MDCLXVI. 

I ja niby napisałem tak:

!romanNumber.matches("[MDCLXVI]*")

Ale dobrze zwróciłeś uwagę, że neguje wartość, którą zwróci to, czyli zawsze jak będzie poprawnie wpisana liczba to zwróci to fałsz (?)

Więc powinienem zrobić taki warunek?

!romanNumber.matches("[^MDCLXVI]")

Czytam to tak, jeżeli znajdzie jakąś inną liczbę to zwróci true, ale zanegowana zwróci false, czyli chyba dobrze?

3) Każda literka z podanych może wystąpić tylko 3 razy i się właśnie zagmatwałem u góry, bo nie pomyślałem o tym że neguje wyrażenie a nie regexa i tego już nie wiem jak zrobić.

 

komentarz 5 lipca 2018 przez periedynek Obywatel (1,320 p.)

@Tomek Sochacki, wiesz jak to ogarnac, ten 3 warunek? + czy ten 2 jest dobrze 

+1 głos
odpowiedź 3 lipca 2018 przez Wiciorny Ekspert (269,120 p.)

 if (romanNumber.matches("[0-9]") || !romanNumber.matches("[MDCLXVI]")) {

            throw new RomanException();

        }

jeśli zrobisz coś takiego to jak wiadomo warunek o ile nie bedzie spełniony, to nie wurzyci nigdy wyjątku.

W  bloku  TRY/CATCH  masz troszke inna sytuacje...  bo jeśli jaka-kolwiek z FUNKCJI lub jakie kolwiek działanie w bloku się nie wykona : np.

    --- np coś  t utaj pójdzie nie tak ... 

String romanNumber = input.next();

            input.close();

            romanNumber = romanNumber.toUpperCase();

;

inicjalizacja obiektu, albo obiekt zwróci   null no - inny błąd niż w  przewidywanym  IF-ie to zostanie  rzucony wyjątek.

"gubie się w tym Throw"

 

To jest to co zostanie wyrzucone, ... więc generalnie możesz wyrzucić swój wyjątek - wcześnniej inmplementując go w osobnej klasie która np rozszerza Exception  klase / lub Throwable , zależy czybardziej mamy na istocie zwrócenie warunku czy po prostu obsługę błędu poprzez wyłapanie 

komentarz 3 lipca 2018 przez periedynek Obywatel (1,320 p.)
W takim razie to w jaki sposób ja to zrobiłem jest dobry?

W takim razie w tym przypadku try/catch odpada? Czy można by było to jakoś analogicznie zrobić.
komentarz 3 lipca 2018 przez Wiciorny Ekspert (269,120 p.)
wiesz co to zależy, jeśli " chcesz zwrócić TYLKO SWÓJ BŁĄD " nabazie ... tylko twojego założenia że np liczba  jest niepoprawna  to  jeśli  nie potrafisz tego w JAVA8 stream załatwić,  to IF bedzie  lepszym rozwiązaniem, jednak  jeśli zalezy Ci na całkowitym zabezpieczeniu aplikacji  to try/catch ... wszystko sprowadza się  do SAMEJ IMPLEMENTACJI jak  i tego co masz zamiar zrobić i co dla Ciebie jest istotne
komentarz 3 lipca 2018 przez periedynek Obywatel (1,320 p.)
A na podstawie tego kodu, który wkleiłem? Jest to dobra opcja?

Podobne pytania

0 głosów
1 odpowiedź 575 wizyt
pytanie zadane 16 lutego 2019 w Java przez periedynek Obywatel (1,320 p.)
0 głosów
2 odpowiedzi 393 wizyt
pytanie zadane 22 listopada 2018 w PHP przez marcolo Obywatel (1,530 p.)
0 głosów
1 odpowiedź 620 wizyt
pytanie zadane 17 listopada 2017 w C# przez Sensej Użytkownik (540 p.)

92,451 zapytań

141,261 odpowiedzi

319,073 komentarzy

61,853 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...