Dlaczego używanie System.out.println () jest tak złe? [Zamknięte]
18
Oczywiście bardzo przydatne jest użycie struktury rejestrowania komunikatów o błędach lub ostrzeżeń. Ale czasami używam System.out.println (), jeśli chcę wypróbować coś nowego w krótkim czasie.
Czy naprawdę źle jest używać System.out.println () do szybkiego testu?
Narzędzia do sprawdzania kodu statycznego @Kayser są nieodpowiednie do szybkich testów - są bardziej przeznaczone do kodu, który zamierzasz opracowywać wspólnie z innymi (lub inni będą musieli zrozumieć). Lekcja, której uczę się w tym roku, polega na tym, że istnieją bardzo różne obszary problemów, nawet w ciągu dnia pracy, które wymagają bardzo różnych zestawów narzędzi i praktyk. Więc na szybki test, rzuć to wszystko i użyj Groovy :)
Bill K
1
Spróbuj użyć System.err.println()i zobacz, co się stanie. Zgaduję, że narzędzie uważa, że używasz System.outw niewłaściwym celu.
Izkata
2
Podstawowym problemem jest skalowalność i kontrola. Jeśli masz miliony takich stwierdzeń, jak możesz zobaczyć to, co musisz zobaczyć. Jeśli musisz zareagować na jeden z nich, jak możesz to zrobić programowo. Ramy rejestrowania to zwykle dwie myśli stosowane w System.out.
Odpowiedzi:
18
Jak ujawniono w komentarzach, prawdziwym pytaniem jest, dlaczego narzędzia do analizy kodu statycznego używają System.out.println?
Powodem jest to, że wysyłanie wiadomości na standardowe wyjście jest zwykle nieodpowiednie w środowisku produkcyjnym. Jeśli kodujesz bibliotekę, biblioteka powinna zwrócić informacje do swojego obiektu wywołującego, a nie drukować na standardowe wyjście. Jeśli kodujesz aplikację GUI, informacje powinny być przedstawione użytkownikowi, a nie temu, na co wskazuje stdout (co może być nigdzie). Jeśli kodujesz serwer (lub coś, co działa w kontenerze po stronie serwera), powinieneś korzystać z dowolnej funkcji rejestrowania udostępnionej przez platformę. I tak dalej.
Ale jeśli używasz println do debugowania lub programowania, lub piszesz program i czyta stdin i pisze na stdout, println jest w porządku. Nie ma w tym nic złego w tego rodzaju przypadkach.
Niezła odpowiedź. Dzięki .. +1 za „Jeśli kodujesz aplikację GUI, informacje powinny być przedstawione użytkownikowi, a nie miejscu, w którym zdarza się wskazywać (co może być nigdzie)”
Kayser
10
Wszystko stdoutjest buforowane, dlatego możliwe jest , że Twój program zawiesi się po twoim wywołaniu println(), ale zanim dotrze do ekranu.
Biorąc to pod uwagę, ten scenariusz jest naprawdę mało prawdopodobny. Śmiało i używaj go, ale zachowaj to niewielkie ograniczenie w głębi duszy.
Co najmniej dwa główne interpretery Pythona bardzo mocno starają się opróżnić wszystkie otwarte pliki przed wyjściem, nawet jeśli wyjście jest spowodowane nieokreślonym wyjątkiem. Czy maszyny JVM nie robią czegoś podobnego?
1
@delnan, Być może, ale wszystko może się zdarzyć. (Kod, który opróżnia standardowe wyjście, może znajdować się tam, gdzie pojawia się problem. Wątek, w którym działasz, może zostać mocno zamknięty. Bieżący proces może zostać zrzucony z pamięci przez system operacyjny.) Nie żyj życiem wokół mojego stwierdzenia, ale po prostu bądź tego świadomy.
riwalk
1
Kod, który opróżnia standardowe wyjście, znajduje się w samej maszynie wirtualnej, a zatem nie ma na nią wpływu błędy w języku implementowanym przez maszynę wirtualną. Dobra uwaga na temat wymuszonego zakończenia procesu. Należy jednak pamiętać, że np. SIGTERM Unixa i większość innych sygnałów może zostać przechwyconych w celu przeprowadzenia takiego czyszczenia - nie działa jednak z bardziej ekstremalnym SIGKILL.
2
Wydaje mi się, że nigdy tego nie widziałem ani nie słyszałem, chociaż widziałem inne problemy. Ten problem również nie poprawi się w przypadku narzędzi takich jak rejestratory, ponieważ prawdopodobnie używają System.out jako podstawowego narzędzia.
System.outjest tylko opakowaniem BufferedOutputStream. Jest to prawdopodobnie podobne do każdego używanego frameworka rejestrowania, frameworki zapewniają po prostu więcej funkcji w postaci konfiguracji i miejsca docelowego danych wyjściowych dziennika
Większość IDE powinna mieć klawisze skrótów do autouzupełniania System.out.println, komentowania / odkomentowania linii i usuwania linii. Zasadniczo masz rację, starając się unikać jego nadmiernego wykorzystania, ale w ten sposób możesz przynajmniej zaoszczędzić czas.
Steven,
7
Jest kilka ostrzeżeń dotyczących używania System.out, nawet w wyrzucanym kodzie.
Jednym z głównych problemów jest to, że zwykle jest powolny . Na przykład, jeśli próbujesz uzyskać ogólne pojęcie o szybkości jakiegoś kodu (pamiętaj, że mikrodrukowanie jest trudne ), to dodanie jednego w System.out.println()dowolnym miejscu może naprawdę zepsuć twój czas (ponieważ synchronizuje się i często czeka na faktyczne wyjście być widoczne dla użytkownika przed powrotem).
Poza tym nie przejmowałbym się tym zbytnio w wyrzucanym kodzie. Jeśli zamierzasz go zatwierdzić (czy to jako kod produkcyjny, czy jako kod testowy), powinieneś się go pozbyć i zastąpić wywołaniem rejestrującym propper (tak, nawet w kodzie testowym).
Jak to często bywa, odpowiedź brzmi „to zależy”. Jeśli Twoja aplikacja ma już strukturę rejestrowania, równie dobrze możesz jej użyć. Nie może być mniej zdolny println()i możesz skorzystać z innych funkcji, które zapewnia - śladów stosu, dodatkowego kontekstu, lepszego formatowania i tak dalej. Istnieje również wyraźna możliwość, że struktury rejestrowania oferują lepsze odzyskiwanie po błędzie, zapewniając, że dzienniki są zapisywane z powodzeniem nawet w przypadku katastrofalnej awarii.
Powstaje więc pytanie, kiedy należy dodać system rejestrowania. Jest to wezwanie do osądu: nie chcesz dodawać go zbyt wcześnie, tylko po to, aby dowiedzieć się, że naprawdę nie potrzebujesz go. Nie chcesz też dodawać go zbyt późno i nadmiernie pracujesz nad konwersją z rozwiązania ad-hoc.
Jeśli odkryjesz, że dużo się logujesz println(), twoja baza kodów próbuje ci powiedzieć, że odczuwa coraz większy ból. W tym momencie warto zainwestować w prawidłowe logowanie.
Często mam problem z tym, że System.out.print używa „domyślnej systemowej” strony kodowej, którą często jest UTF-8 pod Linuksem, ale niektóre zepsute pliki MS pod Windows.
Może to prowadzić do znaków Unicode, które są lub nie są poprawnie drukowane na ekranie, w zależności od miejsca działania programu.
Dlatego wolę niestandardowy PrintWriter niż System.out
Przez gówniane stwardnienie rozsiane Masz na myśli CP1352 lub UTF16?
Cole Johnson
@ColeJohnson: Okno konsoli Windows nadal niestety utknęło w erze sprzed UTF16. Jednak użycie rozsądnego IDE z wbudowaną konsolą może zmniejszyć ten problem.
Joachim Sauer,
@Cole Johnson - Mógłbym żyć z CP 65001 (tj. Utf8), ale wydaje się, że nie ma sposobu, aby uzyskać to jako „domyślną systemową” stronę kodową, kiedy, na przykład, masz niemiecką klawiaturę, dostajesz CP 850 lub coś takiego.
Ingo
1
To wcale nie jest takie złe. Pomysł może wynikać z faktu, że jest bardzo prosty i nie tak wyrafinowany, jak użycie dedykowanej struktury rejestrowania w aplikacji.
Nie oznacza to jednak, że jest to nieprawidłowe podejście. Używałem go wiele razy, aby sprawdzić przepływ aplikacji po kilku hijinkach do programowania czarnej magii voodoo .
Największym problemem z okazyjnym System.out.println, jak widzę, jest to, że jest to „zapach złego nawyku (tm)”. Jeśli to robisz, prawdopodobnie możesz poprawić swoją efektywność, poprawiając komfort korzystania z ulubionego debuggera.
Również dzięki debuggerowi masz pewność, że punkt przerwania nie wpadnie do twojego kodu produkcyjnego, podczas gdy System.out.println może.
Na marginesie, jeśli faktycznie przeprowadzasz szybki test i nadal nie używasz debugera, myślę, że System.out.println jest lepszy niż struktura rejestrowania, ponieważ jeśli przypadkowo zostawisz instrukcję log.debug podczas gotowe, trudniej jest wykorzenić.
Zbudowanie całej strategii testowania w oparciu o echo zawartości stanu wewnętrznego nie jest najmądrzejszym posunięciem, ale w przypadku szybkich i brudnych testów kodu w trakcie projektowania dziwne println tutaj i nie będzie bolało tak długo, jak pamiętasz o ich usunięciu!
Niebezpieczeństwo zapomnienia o ich usunięciu jest prawdopodobnie powodem, dla którego jest odradzane.
System.err.println()
i zobacz, co się stanie. Zgaduję, że narzędzie uważa, że używaszSystem.out
w niewłaściwym celu.Odpowiedzi:
Jak ujawniono w komentarzach, prawdziwym pytaniem jest, dlaczego narzędzia do analizy kodu statycznego używają System.out.println?
Powodem jest to, że wysyłanie wiadomości na standardowe wyjście jest zwykle nieodpowiednie w środowisku produkcyjnym. Jeśli kodujesz bibliotekę, biblioteka powinna zwrócić informacje do swojego obiektu wywołującego, a nie drukować na standardowe wyjście. Jeśli kodujesz aplikację GUI, informacje powinny być przedstawione użytkownikowi, a nie temu, na co wskazuje stdout (co może być nigdzie). Jeśli kodujesz serwer (lub coś, co działa w kontenerze po stronie serwera), powinieneś korzystać z dowolnej funkcji rejestrowania udostępnionej przez platformę. I tak dalej.
Ale jeśli używasz println do debugowania lub programowania, lub piszesz program i czyta stdin i pisze na stdout, println jest w porządku. Nie ma w tym nic złego w tego rodzaju przypadkach.
źródło
Wszystko
stdout
jest buforowane, dlatego możliwe jest , że Twój program zawiesi się po twoim wywołaniuprintln()
, ale zanim dotrze do ekranu.Biorąc to pod uwagę, ten scenariusz jest naprawdę mało prawdopodobny. Śmiało i używaj go, ale zachowaj to niewielkie ograniczenie w głębi duszy.
źródło
System.out
jest tylko opakowaniemBufferedOutputStream
. Jest to prawdopodobnie podobne do każdego używanego frameworka rejestrowania, frameworki zapewniają po prostu więcej funkcji w postaci konfiguracji i miejsca docelowego danych wyjściowych dziennikaźródło
Źle jest, jeśli pracujesz nad nietrywialnym programem
źródło
Jest kilka ostrzeżeń dotyczących używania
System.out
, nawet w wyrzucanym kodzie.Jednym z głównych problemów jest to, że zwykle jest powolny . Na przykład, jeśli próbujesz uzyskać ogólne pojęcie o szybkości jakiegoś kodu (pamiętaj, że mikrodrukowanie jest trudne ), to dodanie jednego w
System.out.println()
dowolnym miejscu może naprawdę zepsuć twój czas (ponieważ synchronizuje się i często czeka na faktyczne wyjście być widoczne dla użytkownika przed powrotem).Poza tym nie przejmowałbym się tym zbytnio w wyrzucanym kodzie. Jeśli zamierzasz go zatwierdzić (czy to jako kod produkcyjny, czy jako kod testowy), powinieneś się go pozbyć i zastąpić wywołaniem rejestrującym propper (tak, nawet w kodzie testowym).
źródło
Jak to często bywa, odpowiedź brzmi „to zależy”. Jeśli Twoja aplikacja ma już strukturę rejestrowania, równie dobrze możesz jej użyć. Nie może być mniej zdolny
println()
i możesz skorzystać z innych funkcji, które zapewnia - śladów stosu, dodatkowego kontekstu, lepszego formatowania i tak dalej. Istnieje również wyraźna możliwość, że struktury rejestrowania oferują lepsze odzyskiwanie po błędzie, zapewniając, że dzienniki są zapisywane z powodzeniem nawet w przypadku katastrofalnej awarii.Powstaje więc pytanie, kiedy należy dodać system rejestrowania. Jest to wezwanie do osądu: nie chcesz dodawać go zbyt wcześnie, tylko po to, aby dowiedzieć się, że naprawdę nie potrzebujesz go. Nie chcesz też dodawać go zbyt późno i nadmiernie pracujesz nad konwersją z rozwiązania ad-hoc.
Jeśli odkryjesz, że dużo się logujesz
println()
, twoja baza kodów próbuje ci powiedzieć, że odczuwa coraz większy ból. W tym momencie warto zainwestować w prawidłowe logowanie.źródło
Często mam problem z tym, że System.out.print używa „domyślnej systemowej” strony kodowej, którą często jest UTF-8 pod Linuksem, ale niektóre zepsute pliki MS pod Windows.
Może to prowadzić do znaków Unicode, które są lub nie są poprawnie drukowane na ekranie, w zależności od miejsca działania programu.
Dlatego wolę niestandardowy PrintWriter niż System.out
źródło
To wcale nie jest takie złe. Pomysł może wynikać z faktu, że jest bardzo prosty i nie tak wyrafinowany, jak użycie dedykowanej struktury rejestrowania w aplikacji.
Nie oznacza to jednak, że jest to nieprawidłowe podejście. Używałem go wiele razy, aby sprawdzić przepływ aplikacji po kilku hijinkach do programowania czarnej magii voodoo .
źródło
Nie ma nic złego w korzystaniu z niego, pomaga dowiedzieć się „co do diabła się dzieje”.
Ale jeśli twoi rówieśnicy / inni deweloperzy / wyśmiewają cię, zawsze możesz użyć Loggera lub rozpocząć testy Junita !
źródło
Największym problemem z okazyjnym System.out.println, jak widzę, jest to, że jest to „zapach złego nawyku (tm)”. Jeśli to robisz, prawdopodobnie możesz poprawić swoją efektywność, poprawiając komfort korzystania z ulubionego debuggera.
Również dzięki debuggerowi masz pewność, że punkt przerwania nie wpadnie do twojego kodu produkcyjnego, podczas gdy System.out.println może.
Na marginesie, jeśli faktycznie przeprowadzasz szybki test i nadal nie używasz debugera, myślę, że System.out.println jest lepszy niż struktura rejestrowania, ponieważ jeśli przypadkowo zostawisz instrukcję log.debug podczas gotowe, trudniej jest wykorzenić.
źródło
Zbudowanie całej strategii testowania w oparciu o echo zawartości stanu wewnętrznego nie jest najmądrzejszym posunięciem, ale w przypadku szybkich i brudnych testów kodu w trakcie projektowania dziwne println tutaj i nie będzie bolało tak długo, jak pamiętasz o ich usunięciu!
Niebezpieczeństwo zapomnienia o ich usunięciu jest prawdopodobnie powodem, dla którego jest odradzane.
źródło