JavaRush /Blog Java /Random-PL /Typowe błędy w kodzie Java.
Sdu
Poziom 17

Typowe błędy w kodzie Java.

Opublikowano w grupie Random-PL
Materiał ten zawiera najbardziej typowe błędy jakie widziałem w kodzie Java osób pracujących ze mną. Analiza statyczna (używamy qulice ) z oczywistych względów nie jest w stanie wykryć wszystkich tego typu błędów, dlatego zdecydowałem się je tutaj wymienić. Wszystkie te błędy są ogólnie związane z programowaniem obiektowym, a w szczególności z Javą.
Nazwy klas
Twoja klasa powinna być abstrakcją prawdziwego obiektu bez „ walidatorów , „ kontrolerów , menedżerów itp . Jeśli nazwa twojej klasy kończy się na „-er”, jest to zły projekt. I oczywiście klasy pomocnicze antywzorców, takie jak StringUtils , FileUtils i IOUtils Apache'a, są świetnymi przykładami okropnych wzorców projektowych. Nigdy nie dodawaj przyrostków ani przedrostków w celu rozróżnienia interfejsów i klas. Na przykład wszystkie te nazwy są okropne: IRecord , IfaceEmployee lub RecordInterface . Zazwyczaj nazwa interfejsu jest nazwą rzeczywistego obiektu, natomiast nazwa klasy powinna wyjaśniać szczegóły implementacji. Jeśli nie można powiedzieć nic konkretnego na temat implementacji, wystarczą nazwy „ Domyślne ”, „ Proste ” lub coś podobnego. Na przykład: class SimpleUser implements User {}; class DefaultRecord implements Record {}; class Suffixed implements Name {}; class Validated implements Content {};
Nazwy metod
Metody mogą zwracać „ coś ” lub zwracać „ void ”. Jeśli metoda coś zwraca, to jej nazwa powinna wyjaśniać, co zostanie zwrócone. Na przykład (nie używaj przedrostka „ get ”): boolean isValid(String name); String content(); int ageOf(File file); Jeśli zwrócone zostanie „ void ”, nazwa powinna wyjaśniać, co robi dana metoda. Na przykład: void save(File file); void process(Work work); void append(File file, String line); Jest tylko jeden wyjątek od tej reguły – metody testowe JUnit . Zostały one opisane poniżej.
Nazwy metod testowych
Nazwy metod w testach JUnit muszą być skonstruowane jako zdanie w języku angielskim bez spacji. Łatwiej to wyjaśnić na przykładzie: /** * HttpRequest can return its content in Unicode. * @throws Exception If test fails */ public void returnsItsContentInUnicode() throws Exception { } ważne jest, aby pierwsze zdanie JavaDoc rozpocząć od nazwy testowanej klasy, po której następuje „ can ”. Zatem pierwsze zdanie powinno zawsze brzmieć jak wyrażenie „ ktoś może coś zrobić ”. Nazwa metody będzie zawierać to samo, ale bez przedmiotu testowania. Jeśli dodam go na początku nazwy metody, otrzymam pełne zdanie w języku angielskim, jak w powyższym przykładzie: „ HttpRequest zwraca swoją zawartość w formacie Unicode ”. Należy pamiętać, że nazwa metody testowej nie zaczyna się od „ can ”. Tylko komentarze JavaDoc zaczynają się od „ can ”. Ponadto nazwy metod nie powinny zaczynać się od czasownika ( Od tłumacza: najwyraźniej autor ma na myśli tryb rozkazujący czasownika ). Dobrą praktyką jest wskazanie, że podczas deklarowania metody testowej zgłaszany jest wyjątek.
Nazwy zmiennych
Unikaj nazw zmiennych złożonych, takich jak timeOfDay , FirstItem lub httpRequest . Mam na myśli zarówno zmienne klasowe, jak i zmienne metod. Nazwa zmiennej powinna być wystarczająco długa, aby uniknąć niejednoznaczności co do jej zakresu, ale w miarę możliwości nie powinna być zbyt długa. Imię musi być rzeczownikiem w liczbie pojedynczej lub mnogiej. Na przykład: Czasami mogą wystąpić kolizje pomiędzy parametrami konstruktora i polami klas, jeśli konstruktor przechowuje dane wejściowe w utworzonym obiekcie. W takim przypadku zalecam utworzenie skrótu poprzez usunięcie samogłosek. Przykład: W większości przypadków najlepszą nazwą zmiennej będzie nazwa odpowiedniej klasy. Po prostu pisz wielką literą i wszystko będzie dobrze: jednak nigdy nie rób tego samego dla typów pierwotnych, takich jak lub . Przymiotników możesz także używać, gdy istnieje kilka zmiennych o różnych cechach. Na przykład: List names; void sendThroughProxy(File file, Protocol proto); private File content; public HttpRequest request; public class Message { private String recipient; public Message(String rcpt) { this.recipient = rcpt; } } File file; User user; Branch branch; Integer number String string String contact(String left, String right);
Konstruktorzy
Bez wyjątku powinien istnieć tylko jeden konstruktor przechowujący dane w zmiennych obiektowych. Wszyscy pozostali konstruktorzy muszą wywołać ten z innymi parametrami: public class Server { private String address; public Server(String uri) { this.address = uri; } public Server(URI uri) { this(uri.toString()); } }
Zmienne jednorazowe
Za wszelką cenę unikaj zmiennych jednorazowych. Przez „jednorazowe” mam na myśli zmienne, które są używane jednorazowo. Tak jak w tym przykładzie: String name = "data.txt"; return new File(name); Zmienna jest używana tylko raz, a kod można uprościć do: return new File("data.txt"); Czasami, w bardzo rzadkich przypadkach - głównie ze względu na lepsze formatowanie - można użyć zmiennych jednorazowych. Staraj się jednak unikać takich sytuacji.
Wyjątki.
Oczywiście nigdy nie należy „połykać” wyjątków; należy je rzucać jak najwyżej. Wyjątki od metod prywatnych muszą być obsługiwane zewnętrznie. Nigdy nie używaj wyjątków do kontrolowania przepływu. Kod w przykładzie jest niepoprawny: int size; try { size = this.fileSize(); } catch (IOException ex) { size = 0; } Poważnie, co jeśli wyjątek IOException powie „dysk jest pełny”, czy założysz, że rozmiar pliku wynosi zero i będziesz kontynuować?
Wcięcie.
W przypadku wcięć ogólną zasadą jest, że nawias musi kończyć wiersz lub zamykać się w tym samym wierszu (odwrotna zasada obowiązuje w przypadku nawiasu zamykającego). W poniższym przykładzie kod jest błędny, ponieważ pierwszy nawias nie jest zamknięty w tej samej linii i występują po nim znaki. Drugi nawias ma ten sam problem, ponieważ znajdują się przed nim znaki, a w bieżącym wierszu nie ma nawiasu otwierającego. final File file = new File(directory, "file.txt"); Prawidłowe wcięcie powinno wyglądać tak: StringUtils.join( Arrays.asList( "first line", "second line", StringUtils.join( Arrays.asList("a", "b") ) ), "separator" ); Drugą ważną zasadą wcięcia jest to, że należy umieścić jak najwięcej w jednym wierszu – maksymalnie do 80 znaków. Powyższy przykład nie jest prawidłowy, ponieważ można go skompresować: StringUtils.join( Arrays.asList( "first line", "second line", StringUtils.join(Arrays.asList("a", "b")) ), "separator" );
Nadmiarowe stałe.
Stałych klas należy używać, gdy chcesz dzielić dostęp do informacji pomiędzy metodami klas, a informacja ta jest cechą charakterystyczną ( ! ) Twojej klasy. Nie używaj stałych jako zamienników ciągów znaków lub literałów numerycznych — bardzo zła praktyka, prowadzi do zanieczyszczenia kodu. Stałe (podobnie jak inne obiekty OOP) muszą mieć znaczenie w świecie rzeczywistym. Jakie jest znaczenie tych stałych w prawdziwym świecie? class Document { private static final String D_LETTER = "D"; // bad practice private static final String EXTENSION = ".doc"; // good practice } Innym częstym błędem jest używanie stałych w testach jednostkowych, aby uniknąć powielania literałów łańcuchowych/numerycznych w metodach testowych. Nie rób tego! Każda metoda testowa musi działać na własnym zestawie wartości wejściowych. W każdej nowej metodzie testowej używaj nowych tekstów i liczb. Testy są niezależne. Dlaczego więc miałyby mieć te same stałe wejściowe?
Testowanie łączenia danych.
Oto przykład zaczepienia metody testowej: User user = new User("Jeff"); // maybe some other code here MatcherAssert.assertThat(user.name(), Matchers.equalTo("Jeff")); W ostatniej linii łączymy „ Jeff ” z tym samym literałem ciągu znaków, który określono w pierwszej linii. Jeśli kilka miesięcy później ktoś będzie chciał zmienić wartość w trzeciej linii, będzie musiał poświęcić dodatkowy czas na szukanie, gdzie jeszcze w tej metodzie użyto słowa „ Jeff ”. Aby uniknąć zadzierania danych, należy wprowadzić zmienną.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION