Referat nr. 1 „Style kodowania” Łukasz Kozień 1 Spis treści • • • • • • 2 Formatowanie kodu i nazewnictwo Struktura katalogów w projekcie JAR - Archiwa Javy Pakiety Logowanie - java.util.logging LOG4J Formatowanie kodu i nazewnictwo • • Pliki źródłowe nie powinny być dłuższe niż 2000 linii Linie programu nie powinny być dłuższe niż 80 znaków (długie linie powinny być łamane) // Łamanie linii po przecinku public void zrobCos(String slowo1, String slowo2, String slowo3, String slowo4) throws Exeption { } // Łamanie linii przed operatorem zmienna = zmienna1 * ( zmienna2 + zmienna3 - zmienna4) + zmienna5 * zmienna6; Złamane linie należy wcinać o kilka tabulacji aby kod stał się przejrzysty (tabulacje o rozmiarze 4 znaków) 3 Formatowanie kodu i nazewnictwo • • 4 Miejsca w których należy stosować spację: – Po słowie kluczowym po którym występuje nawias if (warunek) { } – Po przecinkach w liście parametrów funkcji – Spacja powinna oddzielać operatory od operandów zmienna += zmienna1 + zmienna2; Wyjątek: zmienna3++; – Spacja powinna oddzielać kolejne elementy w wyrażeniu for for (init; war; krok) { } – W celu oddzielenia operatora rzutowania od rzutowanego wyrażenia (int) zmienna Nie umieszczaj odstępu pomiędzy nawiasami początkowym i końcowym funkcji czy wyrażeń public void zrobCos(String zmienna) { } Formatowanie kodu i nazewnictwo • • • • • 5 Każdą zmienną należy deklarować w osobnej linii String zmienna1; String zmienna2; Parametry metod z przerwą po przecinku public void zrobCos(String zmienna1, String zmienna2) {} Nawias otwierający listę parametrów metody nie powinien być oddzielony żadną przerwą od nazwy metody (Oraz od pierwszego i ostatniego parametru) Nazwy klas i interfejsów mogą być złożone z jednego lub wielu słów, przy czym każde ze słów składowych musi się zaczynać od dużej litery class JakasNazwaKlasy { } Nazwy metod oraz pól (zmiennych składowych klasy) mogą być złożone z jednego lub wielu słów, każde ze słów za wyjątkiem pierwszego musi rozpoczynać się od duże litery void nazwaMetody(int zmienna) { } Formatowanie kodu i nazewnictwo • 6 Nazwy pakietów – Pisane jest małymi literami – Jeśli składa się z wielu słów, to wówczas nie wprowadza się żadnego separatora package jakas.nazwa.pakietu – Nazwa pakietu powinna odpowiadać następującemu szablonowi <high level domain name>.<company name>.<project name>.<module name> <high level domain name> - nazwa domeny najwyższego poziomu com, edu, net, org lub dwuliterowy kod kraju (ISO) <company name> - nazwa firmy lub organizacji realizującej projekt <project name> - nazwa projektu <module name> - nazwa modułu projektu Kolejne elementy są dowolne – Jeśli nie posiadamy własnej domeny, zmuszeni jesteśmy do wymyślenia mało prawdopodobnej kombinacji (własne imię i nazwisko) Formatowanie kodu i nazewnictwo • • • 7 Stałe pisane są dużymi literami, poszczególne słowa oddzielane są od siebie znakiem podkreślenia public static final NEW_LINE = ”\n”; Edytor Eclipse sam koloruje nasz kod oraz formatuje zgodnie z przyjętą konwencją Dokładne informacje można znaleźć w dokumencie Code Conventions for the Java Programming Language, który znajduje się na stronie http://java.sun.com/docs/codeconv/index.html Struktura katalogów w projekcie • 8 Strukturę katalogów w projekcie przedstawia tabela: opt Oprogramowanie niezbędne w procesie kompilowania i instalowania oprogramowania (jdk, ant, jikes) src Katalog z plikami źródłowymi projektu build.bat Plik przygotowujący środowisko projektu (ustawienie odpowiednich zmiennych środowiskowych, ant) build.xml Plik konfiguracyjny ant-a src/config Pliki konfiguracyjne projektu src/database Sktypty bazodanowe projektu src/docs Dokumentacja projektowa i inne dokumenty związane z projektem src/etc Pliki deployment descriptor src/resources Pliki resource deployment descriptor dla iAS src/tlds Pliki tag lib descriptors src/java Pliki źródłowe Javy src/test Pliki źródłowe Javy dla testów src/web Pliki html, jsp, gif, jpeg lib Dodatkowe biblioteki jar i zip build Katalog tymczasowy dla skompilowanych źródeł Javy oraz dokumentacji Javadoc assembly Katalog tymczasowy dla plików war, jar, ear dist Katalog tymczasowy z dystrybucją projektu JAR – Archiwa Javy • • • • • • • 9 JAR (Java ARchive) – własny format Javy, w którym wykorzystywany jest format ZIP Służy do zbierania grupy plików do pojedynczego, skompresowanego pliku Format JAR jest niezależny od platformy, nie trzeba się martwić o reprezentację danych Kompresować do formatu JAR można także pliki graficzne jak i audio Korzystanie z formatu JAR jest szczególnie istotne przy zastosowaniach internetowych Przy połączeniu wszystkich klas niezbędnych do działania apletu w jeden plik JAR, konieczne jest tylko jedno zapytanie serwera, a transfer jest szybszy z powodu kompresji. Przed wprowadzeniem tego formatu przeglądarka sieciowa musiała ponawiać żądania ściągnięcia z serwera wszystkich nie skompresowanych plików klas składających się na aplet. Każdy wpis w pliku JAR może być zaopatrzony w podpis cyfrowy w celu zachowania bezpieczeństwa Archiwum JAR składa się z pojedynczego pliku zawierającego zbiór plików skompresowanych oraz wykaz (ang. manifest) JAR – Archiwa Javy • • • 10 Narzędzie jar rozprowadzane jest razem z JDK (Java Developers Kit) Suna, automatycznie kompresuje pliki wskazane przez użytkownika Wywołuje się z wiersza poleceń jar [opcje] plik_docelowy [wykaz] plik[i] Wykaz opcji: – – – – – c t x x plik f – – – m v 0 – m Tworzy nowe lub puste archiwum Wypisuje zawartość archiwum Wydobywa wszystkie pliki Wydobywa wskazany plik Wymusza podanie nazwy pliku. Brak tej opcji, jar zinterpretuje że dane będą pochodziły ze standardowego wejścia, lub że ma wysyłać dane na standardowe wyjście (gdy będzie tworzył plik) Pierwszy argument będzie nazwą wykazu stworzonego przez użytkownika Zwiększa liczbę prezentowanych informacji – jar będzie wypisywał co robi Jedynie przechowuje pliki, bez kompresji. (np. można stworzyć plik JAR i dołączyć go do zmiennej środowiskowej CLASSPATH Zapobiega automatycznemu utworzeniu wykazu JAR – Archiwa Javy • • Jeśli wśród plików danych do kompresji programowi jar znajduje się podkatalog wszystkie zawarte w nim pliki i podkatalogi również zostaną automatycznie dołączone do archiwum a informacja o ścieżce zostanie zapamiętana Przykłady wywołań programu jar jar cf mojPlikJar.jar *.class Stworzone zostanie archiwum mojPlikJar.jar, zawierające wszystkie pliki klas z katalogu bieżącego, razem z automatycznie wygenerowanym wykazem jar cmf mojPlikJar.jar mojWykaz.mf *.class To samo, ale z włączonym wykazem stworzonym przez użytkownika jar tf mojPlikJar.jar Wypisanie listy plików zawartych w mojPlikJar.jar jar tvf mojPlikJar.jar Bardziej szczegółowe informacje o plikach (opcja v) jar cvf mojAplet.jar audio klasy obrazy Zakładając że audio, klasy i obrazy to podkatalogi, pliki w nich zawarte zostaną włączone do pliku mojAplet.jar • 11 Wady programu jar – Nie można dodać ani usunąć plików z istniejącego pliku JAR, trzeba go stworzyć od zera (jeżeli się używa polecenia jar, gdyż można dodać pliki np. WinZipem) JAR – Archiwa Javy • Aby sobie uprościć zadanie do tworzenia plików JAR możemy użyć zwykłego ZIP’a a następnie zmienić rozszerzenie *.zip na *.jar, należy jednak pamiętać iż należy dodać wtedy do archiwum własny plik manifestu. Plik manifestu • – Przykładowy plik: Manifest.mf Manifest-Version: 1.0 Created-By: 1.4.2_01 (Sun Microsystems Inc.) – Plik ten może zawierać również inne pola np. Signature-Version, Class-Path , Extension-List, Main-Class Możemy uruchomić program spakowany do archiwum JAR poprzez polecenie: java –jar nazwa_pliku.jar jednak aby program się uruchomił należy dodać do pliku manifestu linijkę: Main-Class: nazwa klasy z metodą main (klasa jaka ma być wywołana) – • 12 Można np. pod Windowsem skojarzyć pliki *.jar z wykonywalnymi i uruchamiać jak zwykłego programy JAR – Archiwa Javy • Przykład Projekt.java import java.io.File; public class Projekt { public static void main(String[] s) { File path = new File("."); String[] list; list=path.list(); for(int i=0; i<list.length; i++) System.out.println(list[i]); } } Manifest.mf Manifest-Version: 1.0 Created-By: 1.4.2_01 (Sun Microsystems Inc.) Main-Class: Projekt 13 Pakiety • • • • • 14 Pakiety (Package) w Javie są to podzbiory bibliotek, które mają podobne funkcje Pakiety mogą zwierać interfejsy Ważniejsze pakiety w Javie to – java.lang.* - Pakiet zawierający wszystkie podstawowe klasy Javy. Nie musi być jawnie importowany, gdyż kompilator czyni to w sposób automatyczny – java.util.* - Pomocnicze klasy użytkowe (np. generacja liczb losowych, operacje na ciągach znaków, ...) – java.io.* - obsługa wejścia/wyjścia – java.net.* - Zawiera klasy konieczne do tworzenia oprogramowania wykorzystującego sieć – java.awt.* - Klasy służące do tworzenia graficznego interfejsu użytkownika(GUI) – java.applet.* - Pakiet zawierający klasy używane podczas tworzenia appletów Użycie słowa kluczowego import, służy do włączenia całej biblioteki np. import java.util.*; Powoduje wprowadzenie do programu całej biblioteki util Użycie gwiazdki może wydłużyć czas kompilacji, szczególnie gdy importujemy kilka dużych pakietów, dlatego dobrym zwyczajem jest raczej wskazanie konkretnej klasy niż importowanie całego pakietu. Użycie gwiazdki nie ma wpływu na czas działania ani na wielkość kodu wynikowego, powoduje jednak duże zamieszanie Pakiety • • • • • • 15 Jeżeli chcemy importować pojedynczą klasę, możemy wymienić jej nazwę w instrukcji import import java.util.ArrayList; Można teraz używać ArrayList, natomiast inne klasy pakietu java.util nie będą dostępne Możemy również używać pełnej nazwy java.util.ArrayList (można to robić bez instrukcji import) Gdy tworzymy bibliotekę z której będą korzystały inne programy Javy trzeba zapobiec konfliktom nazw klas (patrz. „Formatowanie kodu i nazewnictwo”) Każdy plik źródłowy definiujący pakiet rozpoczyna się następującą linią: package <nazwa.pakietu> Instrukcja package musi stanowić w pliku pierwszy element nie będący komentarzem Podczas kompilacji wszystkie pliki pakietu umieszczone zostaną we wspólnym katalogu (katalogu o nazwie pakietu. Np. Pliki źródłowe (*.java) pakietu AWT zawierają wiersze „package java.awt;” Po ich skompilowaniu pliki (*.class) znajdować się będą w katalogu JAVA/AWT (lub JAVA\AWT w zależności od systemu operacyjnego) Edytor Eclipse posiada tzw. asystenta importów, który automatycznie tworzy i organizuje deklaracje importów Pakiety • Przykład ../edu/agh/hss/Kwadrat.java ../edu/agh/hss/Punkt.java package edu.agh.hss; public class Kwadrat { ... } package edu.agh.hss; public class Punkt { ... } Program.java import edu.agh.hss.Punkt; public class Program { Punkt p = Punkt(); public static void main(String[] s) { ... } } 16 Pakiety • • 17 Kolizje Jeśli program importuje z użyciem znaku * dwie biblioteki zawierające te same nazwy np. import com.firma.* import java.util.* Załóżmy że com.firma zawiera klasę Vector, którą również zawiera java.util, co powoduje potencjalną kolizję Jednak kolizja będzie miała miejsce dopiero wtedy, gdy użyjemy kodu który ją wywoła np. Vector v = new Vector(); Dlatego iż kompilator nie wie do której klasy Vector ma się odnieść. Jest jednak rozwiązanie, jeśli chcemy stworzyć Vector z biblioteki java.util należy dokładnie określić położenie tej klasy java.util.Vector v = new java.util.Vector(); Uwaga Zawsze gdy tworzymy pakiet, niejawnie określamy strukturę katalogów przez nadanie mu nazwy. Pakiet musi znajdować się w katalogu wskazywanym przez jego nazwę i powinien być dostępny przy przeszukiwaniu katalogów za pomocą zmiennej CLASSPATH Logowanie – java.util.logging • • • 18 Logowanie – proces polegający na generacji i gromadzeniu informacji dotyczących działającego programu W działającym i przetestowanym programie informacje te mogą opisywać postępy działania programu (rejestrować poszczególne czynności wykonywane podczas program) Logowanie (rejestracja) jest też bardzo użyteczna podczas testowania i uruchamiania programów Obsługa logowania jest możliwa dzięki bibliotece java.util.logging Istnieją również inne biblioteki, za pomocą których możliwa jest rejestracja jak np.. LOG4J Logowanie – java.util.logging • Prosty program generujący logi Projekt.java import java.util.logging.Logger; public class Projekt { private static Logger logger = Logger.getLogger("InfoLogging"); public static void main(String[] s) { logger.info("Rejestracja komunikatu"); } } – Wynik działania programu (konsola) 2003-10-22 01:12:19 Projekt main INFO: Rejestracja komunikatu 19 nazwa klasy nazwa metody Logowanie – java.util.logging • Poprzedni przykład nie daje gwarancji na to, iż nazwa klasy oraz metody będą poprawne, aby to zrobić możemy użyć metody logp() Projekt.java import java.util.logging.Level; import java.util.logging.Logger; public class Projekt { private static Logger logger = Logger.getLogger("InfoLogging"); public static void main(String[] s) { logger.logp(Level.INFO, "Projekt", "main", "Rejestracja komunikatu"); } } poziom rejestracji 20 nazwa klasy nazwa metody rejestrowany komunikat Logowanie – java.util.logging • Poziomy rejestracji Istnieje wiele poziomów raportowania, jest możliwość zmiany używanego poziomu podczas działania programu. (domyślny jest poziom INFO) – Poziomy rejestracji przedstawia tabela Poziom 21 Rezultat OFF Żadne komunikaty nie są prezentowane SEVERE Prezentowane są wyłącznie komunikaty na poziomie SEVERE WARNING Prezentowane są wyłącznie komunikaty na poziomie WARNING i > INFO Prezentowane są wyłącznie komunikaty na poziomie INFO i > CONFIG Prezentowane są wyłącznie komunikaty na poziomie CONFIG i > FINE Prezentowane są wyłącznie komunikaty na poziomie FINE i > FINER Prezentowane są wyłącznie komunikaty na poziomie FINER i > FINEST Prezentowane są wyłącznie komunikaty na poziomie FINEST i > ALL Prezentowane są wszystkie rejestrowane komunikaty Logowanie – java.util.logging • LogRecord – Jest to klasa, która zawiera wszystkie informacje dotyczące logów. Wszystkie metody tej klasy zostały utworzone zgodnie z konwencją „get” i „set” (wszystkie metody zaczynają się od „set” lub „get”) – Aby pobrać informacje z obiektu LogRecord posługujemy się metodami pobierającymi, niektóre z nich to: • • • • • • • getLoggerName() getMessage() getMillis() getSourceClassName() getSourceMethodName() getThreadID() getThrown() Nazwa rejestratora Komunikat Czas w milisekundach Nazwa klasy źródłowej Nazwa metody źródłowej Id wyjątku Wyjątek – Aby wprowadzić informacje do obiektu LogRecord korzystamy z metod zaczynających się od „set” – Dokładny spis metod wraz z objaśnieniami znajduje się w dokumentacji 22 Logowanie – java.util.logging • Handler W bardzo łatwy sposób można stworzyć własny obiekt obsługi, wystarczy stworzy klasę dziedziczącą z Handler i zdefiniować metodę publish() (oraz metody flush() i close(), zapewniające poprawną obsługę strumienia używanego do publikowani komunikatów) Istnieją jednak, już gotowe, predefiniowane klasy obsługi: – StreamHandler Zapisuje sformatowane rekordy w strumieniu wyjściowym (OutputStream) – ConsoleHandler Zapisuje sformatowane rekordy w standardowym strumieniu błędów (System.err) – FileHandler Zapisuje sformatowane rekordy rejestracyjne do wybranego pliku lub do grupy zmienianych plików dziennika – SocketHandler Wykorzystuje protokół TCP, przesyła sformatowane rekordy na port o podanym numerze – MemoryHandler Gromadzi rekordy rejestracyjne w pamięci 23 Logowanie – java.util.logging • Zapisywanie logów do pliku ( i również wyświetlanie ich na konsoli ) Projekt.java import java.util.logging.FileHandler; import java.util.logging.Logger; public class Projekt { private static Logger logger = Logger.getLogger("LogToFile"); public static void main(String[] s) throws Exception { logger.addHandler(new FileHandler("LogToFile.xml")); logger.info("Komunikat ktory znajdzie sie w pliku"); } } logger.setUseParentHandlers(false); // logi tylko do pliku 24 Logowanie – java.util.logging • Domyślnym formatem wyjściowym obiektów FileHandler jest XML. Aby zapisywać logi do pliku tekstowego należy skorzystać z obiektu SimpleFormatter Projekt.java import java.util.logging.FileHandler; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; public class Projekt { private static Logger logger = Logger.getLogger("LogToFile"); public static void main(String[] s) throws Exception { FileHandler logFile = new FileHandler("LogToFile.txt"); logFile.setFormatter(new SimpleFormatter()); logger.addHandler(logFile); logger.info("Komunikat ktory znajdzie sie w pliku"); } } 25 Logowanie – java.util.logging • Dodatek - Rotacyjne zmienianie pliku dziennika -zapobiega tworzeniu się za dużych plików z logami String pattern = "my%g.log"; int limit = 100000; // 100000 bajtow int numLogFiles = 3; FileHandler fh = new FileHandler(pattern, limit, numLogFiles); // Add to logger Logger logger = Logger.getLogger("com.mycompany"); logger.addHandler(fh); użycie powyższego kody, spowoduję użycie trzech plików z logami. Kiedy wszystkie trzy pliki zostaną całkowicie wypełnione, ponownie zacznie być używany pierwszy z nich a jego zawartość zostanie nadpisana 26 Logowanie – java.util.logging • 27 Filtry – Obiekt Logger pozwala na podanie poziomu, na podstawie którego będzie decydować, jakie komunikaty będą akceptowane a jakie nie Jest to prosty sposób filtrowania, który zupełnie wystarcza, czasami jednak potrzebne będą bardziej zaawansowane narzędzia filtrujące, które będą decydowały o odrzuceniu komunikatu na podstawie innych czynników niż poziom – W tym celu należy stworzyć własny obiekt Filter, który jest interfejsem posiadającym jedną metodę isLoggable(LogRecord rekord) zwracającą wartość boolean – Po stworzeniu obiektu Filter należy go zarejestrować w obiekcie Logger lub Handler przy użyciu metody setFilter() – Można np. rejestrować wyłącznie komunikaty o obiektach Kwadrat, mimo iż przed zastosowaniem filtra rejestrowane są komunikaty również o innych obiektach np. Trojkat Logowanie – java.util.logging • 28 Formatter – Jest to obiekt formatujący LogRecord, który zwraca w postaci łańcucha znaków – Aby stworzyć własny obiekt Formatter, należy stworzyć klasę dziedziczącą z Formatter a następnie przesłonić metodę format(LogRecord rekord) – Trzeba zarejestrować obiekt formatujący w obiekcie obsługi, posługując się metodą setFormatter() – Każdy rejestrator posiada domyślny obiekt obsługi LOG4J • • • • LOG4J – jest to biblioteka służąca do logowania i debugowania w projekcie Nacisk przy projektowaniu biblioteki został położony na szybkość działania Rozpowszechniana jest na podstawie licencji open-source przez Apache Software Fundation Trzy podstawowe komponenty systemu logowania udostępnianego przez LOG4J – kategorie (categories) Pozwalają na podzielenie przestrzeni logowania na kategorie i skonfigurowanie każdej z kategorii w osobny sposób. Kategorie te zorganizowane są w strukturę hierarchiczną Z kategorią związany jest jej priorytet Biblioteka LOG4J pozwala na włączenie lub wyłączenie komunikatów o odpowiednich priorytetach dla odpowiednich kategorii. – przeznaczenia (appenders) Pozwalają na określenie przeznaczenia logów związanych z daną kategorią. Przeznaczeniem logów może być np., konsola lub plik Logi wysyłane do pliku mogą być zawijane (rolling), co chroni nas przed logami o zbyt dużej wielkości. Dla zawijanego pliku z logami może być tworzona jego kopia bezpieczeństwa (backup) – formaty (layouts) Pozwalają na określenie formatu logów powiązanych z danym przeznaczeniem. • 29 Najnowsza wersja biblioteki wraz z dokumentacją może zostać pobrana pod adresem: http://jakarta.apache.org/log4j LOG4J • Środowisko LOG4J jest w pełni konfigurowalne programowo, jednak lepiej jest używać plików konfiguracyjnych, które mogą być napisane w XML lub w formacie key=value MyApp.java import org.apache.log4j.Logger; import org.apache.log4j.BasicConfigurator; public class MyApp { static Logger logger = Logger.getLogger(MyApp.class); public static void main(String[] args) { // Set up a simple configuration that logs on the console. BasicConfigurator.configure(); logger.info("Entering application."); logger.info("Exiting application."); } } 30 LOG4J • Plik java wykorzystujący plik konfiguracyjny MyApp.java import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; public class MyApp { static Logger logger = Logger.getLogger(MyApp.class.getName()); public static void main(String[] args) { // BasicConfigurator replaced with PropertyConfigurator. PropertyConfigurator.configure(args[0]); logger.info("Entering application."); logger.info("Exiting application."); } } 31 LOG4J • Plik konfiguracyjny # Set root logger level to DEBUG and its only appender to A1. log4j.rootLogger=DEBUG, A1 # A1 is set to be a ConsoleAppender. log4j.appender.A1=org.apache.log4j.ConsoleAppender # A1 uses PatternLayout. log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n • Wyniki działania programu 0 [main] INFO MyApp - Entering application. 51 [main] INFO MyApp - Exiting application. 32 LOG4J • Przykładowy plik konfiguracyjny zapisujący logi na konsole i do pliku log4j.rootLogger=debug, stdout, R log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # Pattern to output the caller's file name and line number. log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=example.log log4j.appender.R.MaxFileSize=100KB # Keep one backup file log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n 33 LOG4J • 34 Uwaga ! – Klasy dotyczące logowania powinno się przykrywać własnymi klasami, w celu łatwiejszej późniejszej modyfikacji KONIEC 35