Programuję w Javie od kilku lat, ale niedawno wróciłem do szkoły, aby uzyskać formalny stopień naukowy. Byłem bardzo zaskoczony, gdy dowiedziałem się, że podczas ostatniego zadania straciłem punkty za użycie pętli takiej jak ta poniżej.
do{
//get some input.
//if the input meets my conditions, break;
//Otherwise ask again.
} while(true)
Teraz do testu szukam tylko danych wejściowych konsoli, ale powiedziano mi, że tego rodzaju pętla jest odradzana, ponieważ używanie break
jest podobne goto
, po prostu tego nie robimy.
Rozumiem w pełni pułapki goto
i kuzyna Javy break:label
i mam zdrowy rozsądek, aby z nich nie korzystać. Zdaję sobie również sprawę, że bardziej kompletny program zapewniłby inne sposoby ucieczki, powiedzmy na przykład, aby po prostu zakończyć program, ale to nie był powód, o którym wspomniał mój profesor, więc ...
Co jest nie tak z do-while(true)
?
źródło
break
prawdopodobnie ma sens, ale w rzeczywistości jest źle zrozumiane. Być może możesz wyszkolić swojego profesora na ten temat;) Z mojego doświadczenia wynika, że profesorowie niewiele wiedzą o rzemiośle programowania.do {} while (true)
jest to równoważne,while(true) {}
a ta ostatnia jest zdecydowanie bardziej konwencjonalna i znacznie bardziej przejrzysta.break
, powinien spróbować programować w języku bez niego. Nie potrzeba zbyt wielu pętli, zanim będziesz tego chciał!Odpowiedzi:
Nie powiedziałbym, że to źle - ale normalnie szukałbym przynajmniej alternatywy.
W sytuacjach, w których to pierwsza rzecz, którą piszę, prawie zawsze przynajmniej staram się przekształcić to w coś bardziej przejrzystego. Czasami nic nie można na to poradzić (lub alternatywnie jest mieć
bool
zmienną, która nie robi nic znaczącego poza wskazaniem końca pętli, mniej wyraźnie niżbreak
instrukcja), ale warto przynajmniej spróbować.Jako przykład tego, gdzie łatwiej jest używać
break
niż flagę, rozważ:Teraz zmusimy go do użycia flagi:
Uważam, że ten ostatni jest bardziej skomplikowany do czytania: ma dodatkowy
else
blok,actOnInput
jest bardziej wcięty, a jeśli próbujesz dowiedzieć się, co się stanie, gdytestCondition
powrócitrue
, musisz uważnie przejrzeć resztę bloku, aby sprawdzić, czy tam jest nie jest to coś po tymelse
bloku, które mogłyby wystąpić, czyrunning
został ustawionyfalse
lub nie.To
break
oświadczenie komunikuje intencję jaśniej i pozwala pozostałej części bloku zająć się tym, co musi zrobić, nie martwiąc się o wcześniejsze warunki.Zauważ, że jest to dokładnie ten sam argument, który ludzie mają na temat wielu instrukcji return w metodzie. Na przykład, jeśli potrafię wypracować wynik metody w pierwszych kilku wierszach (np. Ponieważ niektóre dane wejściowe są puste, puste lub zerowe), łatwiej jest zwrócić tę odpowiedź bezpośrednio niż mieć zmienną do przechowywania wyniku , a następnie cały blok z innym kodem, i wreszcie
return
stwierdzenie.źródło
while (true)
AFAIK nic, naprawdę. Nauczyciele są po prostu uczuleni
goto
, ponieważ słyszeli, że gdzieś jest naprawdę źle. W przeciwnym razie po prostu napiszesz:Co jest prawie takie samo.
Może to jest czystsze (ponieważ wszystkie informacje o zapętleniu znajdują się na górze bloku):
źródło
Douglas Crockford miał uwagę na temat tego, jak chciał, aby JavaScript zawierał
loop
strukturę:I nie sądzę, że Java byłaby gorsza z powodu posiadania
loop
struktury.Nie ma nic złego w
while(true)
pętli, ale jest tendencja do nauczycieli, aby ich zniechęcić. Z punktu widzenia nauczania bardzo łatwo jest sprawić, aby uczniowie tworzyli niekończące się pętle i nie rozumieli, dlaczego pętla nigdy nie ucieka.Ale rzadko wspominają o tym wszystkie mechanizmy zapętlania można powielać za pomocą
while(true)
pętli.jest taki sam jak
i
jest taki sam jak:
i
jest taki sam jak:
Tak długo, jak możesz skonfigurować swoje pętle w sposób, który działa, konstrukcja, którą wybierzesz, jest nieistotna. Jeśli zdarzy się, że zmieści się w
for
pętli, użyjfor
pętli.Ostatnia część: zachowaj prostotę pętli. Jeśli na każdej iteracji musi się wydarzyć wiele funkcji, umieść ją w funkcji. Zawsze możesz go zoptymalizować po uruchomieniu.
źródło
for
pętlami, gdycontinue
zaangażowane są instrukcje, ale nie są one poważnym rozszerzeniem.for (;;) {
? (Wymawiane „na zawsze”). To było bardzo popularne.W 1967 roku Edgar Dijkstra napisał artykuł w czasopiśmie branżowym o tym, dlaczego goto należy wyeliminować z języków wysokiego poziomu, aby poprawić jakość kodu. Wyszedł z tego cały paradygmat programowania zwany „programowaniem strukturalnym”, choć z pewnością nie wszyscy są zgodni, że goto automatycznie oznacza zły kod.
Sedno programowania strukturalnego polega zasadniczo na tym, że struktura kodu powinna określać jego przepływ, a nie mieć gotów, przerw lub kontynuować określanie przepływu, tam gdzie to możliwe. Podobnie, posiadanie wielu punktów wejścia i wyjścia do pętli lub funkcji jest również odradzane w tym paradygmacie.
Oczywiście nie jest to jedyny paradygmat programowania, ale często można go łatwo zastosować do innych paradygmatów, takich jak programowanie obiektowe (ala Java).
Twoi nauczyciele prawdopodobnie zostali nauczeni i starają się nauczyć twoją klasę, że powinniśmy unikać „kodu spaghetti”, upewniając się, że nasz kod jest ustrukturyzowany i przestrzegając dorozumianych zasad programowania strukturalnego.
Chociaż w implementacji wykorzystującej break nie ma nic „zła”, niektórzy uważają, że znacznie łatwiej jest odczytać kod, w którym warunek dla pętli jest wyraźnie określony w ramach while (), i eliminuje pewne możliwości bycia zbyt trudnym. Zdecydowanie występują pułapki związane z używaniem warunku chwilowego (prawdziwego), który wydaje się często pojawiać w kodzie przez początkujących programistów, na przykład ryzyko przypadkowego utworzenia nieskończonej pętli lub uczynienia kodu trudnym do odczytania lub niepotrzebnie mylącym.
Jak na ironię, obsługa wyjątków jest obszarem, w którym z pewnością pojawią się odstępstwa od programowania strukturalnego, których należy oczekiwać w miarę dalszego programowania w Javie.
Możliwe jest również, że instruktor spodziewał się, że zademonstrujesz swoją umiejętność korzystania z konkretnej struktury pętli lub składni nauczanej w tym rozdziale lub lekcji tekstu, a chociaż napisany kod jest funkcjonalnie równoważny, być może nie demonstrowałeś szczególne umiejętności, których miałeś się nauczyć podczas tej lekcji.
źródło
Zwykła konwencja Java do odczytu danych wejściowych to:
A typowa konwencja C ++ do odczytu danych wejściowych to:
A w C to jest
lub jeśli jesteś przekonany, że wiesz, jak długa jest najdłuższa linia tekstu w pliku, możesz to zrobić
Jeśli testujesz, czy użytkownik wprowadził
quit
polecenie, łatwo rozszerzyć dowolną z 3 struktur pętli. Zrobię to dla Ciebie w Javie:Tak więc, choć z pewnością istnieją przypadki, w których jest
break
lubgoto
jest uzasadnione, jeśli wszystko, co robisz, to czytanie z pliku lub konsoli wiersz po wierszu, nie powinieneś potrzebowaćwhile (true)
pętli, aby to zrobić - Twój język programowania już ci zapewnił z odpowiednim idiomem dla używania polecenia wejściowego jako warunku pętli.źródło
while (true)
pętli zamiast jednej z tych konwencjonalnych pętli wejściowych, możesz zapomnieć o sprawdzeniu końca pliku.while
warunkowe. W końcowym stanie Java robi się już dość mocny, a jeśli musiałbyś przeprowadzić rozległe manipulacje, aby zdecydować, czy kontynuować, czy nie, może to potrwać dość długo. Możesz podzielić go na osobną funkcję, i może być najlepiej. Ale jeśli chcesz to w jednej funkcji, a przed podjęciem decyzji o kontynuowaniu nie jest łatwa praca,while(true)
być może najlepiej.gets()
nie jest powszechną konwencją. Bardzo sprzyja przepełnieniu bufora.fgets(buffer, BUFFER_SIZE, file)
jest znacznie bardziej jak standardowa praktyka.fgets
.To nie jest takie okropne, ale musisz wziąć pod uwagę innych programistów podczas kodowania. Nawet w szkole.
Twoi inni programiści powinni być w stanie zobaczyć klauzulę wyjścia dla pętli w deklaracji pętli. Nie zrobiłeś tego Ukryłeś klauzulę wyjścia w środku pętli, dzięki czemu więcej pracy dla kogoś, kto przychodzi i próbuje zrozumieć Twój kod. Z tego samego powodu unika się takich rzeczy jak „przerwa”.
To powiedziawszy, nadal zobaczysz takie rzeczy w wielu kodach w prawdziwym świecie.
źródło
while (true)
, jest całkiem oczywiste, że będzie w niejbreak
lub wreturn
środku, albo że będzie działać na zawsze. Bycie bezpośrednim jest ważne, alewhile(true)
samo w sobie nie jest szczególnie złe. Zmienne, które mają złożone niezmienniki w iteracjach pętli, byłyby przykładem czegoś, co powoduje znacznie więcej niepokoju.To twoja broń, twoja kula i twoja stopa ...
Jest źle, ponieważ prosisz o kłopoty. To nie ty ani żaden inny plakat na tej stronie będzie miał przykłady krótkich / prostych pętli while.
Problemy zaczną się w przyszłości w bardzo przypadkowym momencie. Może to być spowodowane przez innego programistę. Może to być osoba instalująca oprogramowanie. Może to być użytkownik końcowy.
Czemu? Musiałem dowiedzieć się, dlaczego aplikacja 700K LOC stopniowo zaczyna spalać 100% czasu procesora, aż każdy procesor zostanie nasycony. To była niesamowita pętla while (prawdziwa). Był duży i nieprzyjemny, ale sprowadzał się do:
Nie było jeszcze żadnej innej gałęzi. Jeśli wartość nie była zgodna z warunkiem if, pętla działała do końca czasu.
Oczywiście, programista obwinił użytkowników końcowych, że nie wybrali wartości, której oczekiwał. (Następnie usunąłem wszystkie wystąpienia while (true) w kodzie).
IMHO nie jest dobrym programowaniem defensywnym do używania konstrukcji takich jak while (prawda). Wróci, by cię prześladować.
(Ale przypominam sobie, że profesorowie obniżali stopnie, jeśli nie komentowaliśmy każdej linii, nawet dla i ++;)
źródło
Jest to złe w tym sensie, że konstrukcje programowania strukturalnego są lepsze niż (nieco nieustrukturyzowane) instrukcje break i continu. Dla porównania, zgodnie z tą zasadą preferowane są „goto”.
Zawsze zalecałbym, aby twój kod był jak najbardziej ustrukturyzowany ... chociaż, jak zauważa Jon Skeet, nie rób go bardziej strukturalnym!
źródło
Zgodnie z moim doświadczeniem w większości przypadków pętle mają warunek „główny”, aby kontynuować. Jest to warunek, w który należy zapisać sam operator while (). Wszystkie pozostałe warunki, które mogą przerwać pętlę, są drugorzędne, nie tak ważne itp. Mogą być zapisane jako dodatkowe
if() {break}
instrukcje.while(true)
jest często mylące i mniej czytelne.Myślę, że zasady te nie obejmują 100% spraw, ale prawdopodobnie tylko 98% z nich.
źródło
Chociaż niekoniecznie jest to odpowiedź na pytanie, dlaczego nie używać
while (true)
, zawsze uważałem to komiczne i towarzyszące oświadczenie autora za zwięzłe wyjaśnienie, dlaczego robić to zamiast robić.Jeśli chodzi o twoje pytanie: nie ma z tym żadnego problemu
... jeśli wiesz, co robisz i upewniasz się, że
exit_time
w pewnym momencie to ocenitrue
.Nauczyciele zniechęcają cię do używania,
while(true)
ponieważ dopóki nie wiesz dokładnie, co robisz, jest to łatwy sposób na popełnienie krytycznego błędu.źródło
exit_time = false; while(!exit_time) { execute_stuff(); }
ido { execute_stuff(); } while(! exit_time );
oba są znacznie wyraźniejsze niż posiadanieif( condition ) { break; }
na końcu pętli za pomocąwhile(true)
. Przerwy są zwarciem do pętli - idealnie w porządku, gdy są używane jako zwarcie w środku pętli, ale powinieneś po prostu ocenić stan w instrukcji while i mieć przerwę na końcu pętli.Możesz po prostu użyć flagi boolowskiej, aby wskazać, kiedy zakończyć pętlę while.
Break
igo to
były powody, dla których oprogramowanie jest trudne w utrzymaniu - kryzys oprogramowania (tm) - i należy go unikać, i łatwo może być również.To pytanie, czy jesteś pragmatyczny, czy nie. Pragmatyczni koderzy mogą po prostu użyć przerwy w tej prostej sytuacji.
Ale dobrze jest przyzwyczaić się do ich nieużywania, w przeciwnym razie możesz użyć ich z przyzwyczajenia w nieodpowiednich sytuacjach, na przykład w skomplikowanych pętlach zagnieżdżonych, w których korzystanie z kodu staje się trudniejsze do odczytania i utrzymania
break
.źródło
if (running)
pętli, wcięcia całej reszty kodu, kiedy wszystko, czego chcę, to wyjście z pętli, jest dla mnie zdecydowanie mniej zrozumiałe niż prosta instrukcja break, która mówi dokładnie, co chcę zrobić. Wydaje ci się, że rozważasz używanie przerwy jako złego nawyku aksjomatycznego - nie uważam tego za takie.Może mam pecha. A może po prostu brakuje mi doświadczenia. Ale za każdym razem Pamiętam czynienia z
while(true)
koniecznościbreak
w środku, można było poprawić kod stosowania Extract Method do while-bloku , który zachowałwhile(true)
jednak (przez przypadek?) Przekształca wszystkiebreak
s językreturn
s.Z mojego doświadczenia
while(true)
wynika, że bez przerw (tj. Ze zwrotami lub rzutami) są dość wygodne i łatwe do zrozumienia.źródło
Myślę, że tak, to jest całkiem złe ... a przynajmniej dla wielu programistów. Jest to symptomatyczne dla programistów, którzy nie myślą o swoich warunkach pętli. W konsekwencji występuje podatność na błędy.
źródło
Nie ma poważny problem
while(true)
zbreak
sprawozdaniem, jednak niektórzy mogą pomyśleć jego nieznacznie zmniejsza czytelność kodu. Staraj się nadawać zmiennym znaczące nazwy, oceniaj wyrażenia we właściwym miejscu.Na przykład, wydaje się o wiele łatwiej zrobić coś takiego:
Jest to szczególnie ważne, jeśli pętla do while jest długa - dokładnie wiesz, gdzie sprawdza się, czy występuje dodatkowa iteracja. Wszystkie zmienne / funkcje mają odpowiednie nazwy na poziomie abstrakcji. The
while(true)
Oświadczenie nie jest powiedzieć, że przetwarzanie nie jest na miejscu, można myśleć.Być może za drugim razem chcesz uzyskać inne wyjście. Coś jak
wydaje mi się wtedy bardziej czytelny
Ponownie, w trywialnym przykładzie oba są dość czytelne; ale jeśli pętla stała się bardzo duża lub głęboko zagnieżdżona (co oznacza, że prawdopodobnie powinieneś już była zrestrukturyzowana), pierwszy styl może być nieco wyraźniejszy.
źródło
Używam czegoś podobnego, ale z przeciwną logiką, w wielu moich funkcjach.
źródło
Jest to bardziej kwestia estetyki, dużo łatwiejszy do odczytania kod, w którym wyraźnie wiesz, dlaczego pętla zatrzyma się w deklaracji pętli.
źródło
Powiedziałbym, że ogólnie powodem, dla którego nie jest uważany za dobry pomysł, jest to, że nie używasz konstruktu do pełnego potencjału. Poza tym myślę, że wielu instruktorom programowania nie podoba się to, gdy ich uczniowie przychodzą z „bagażem”. Rozumiem przez to, że uważam, że lubią oni mieć główny wpływ na styl programowania swoich uczniów. Więc może to tylko zwierzę domowe wkurza instruktora.
źródło
Dla mnie problemem jest czytelność.
Instrukcja while z prawdziwym warunkiem nie mówi nic o pętli. To znacznie utrudnia zrozumienie go.
Co byłoby łatwiejsze do zrozumienia z tych dwóch fragmentów?
źródło
Myślę, że użycie przerwy dla nauczyciela jest jak złamanie gałęzi drzewa, aby zdobyć owoc, użyj innych sztuczek (pochyl gałąź), aby uzyskać owoc, a gałąź wciąż żyje :)
źródło
1) Nic nie jest nie tak z
do -while(true)
2) Twój nauczyciel się myli.
NSFS !!:
3) Większość nauczycieli to nauczyciele, a nie programiści.
źródło
Może być źle, jeśli pętla działa w wątku w tle, więc po zamknięciu aplikacji przez zakończenie wątku interfejsu użytkownika ten fragment kodu będzie nadal wykonywany. Jak już powiedzieli inni, zawsze powinieneś użyć pewnego rodzaju czeku, aby zapewnić sposób na anulowanie.
źródło