Aplikacja Todo
Ze względu, że w pierwszym tygodniu poznałeś wszystkie podstawowe zagadnienia związane z programowaniem w Javie. Nadszedł czas na sprawdzenie się – stworzymy wspólnie krótką aplikację do zarządzania zadaniami i projektami. W tej lekcji pokażę jak stworzyć część do zarządzania zadaniami, zaś Twoim zadaniem będzie stworzenie części projektowej. Oczywiście będziesz mógł zobaczyć moje rozwiązanie w kolejnym wpisie.
Założenia
Tak jak wspomniałem aplikacja będzie miała przechowywać zadania oraz projekty. Czyli będzie mogli tworzyć nowe zadania i projekty, usuwać je oraz wyświetlać je wszystkie. Do stworzenia aplikacji wykorzystamy wiedzę zdobytą w pierwszym tygodniu. Zaczynajmy!
Szablon
Klasycznie ruszmy od czystego szablonu klasy wraz z metodą main:
public class Main { public static void main(String[] args) { } }
Ruszajmy z tworzeniem aplikacji.
Potrzebne pola…
Będziemy potrzebowali oczywiście dwóch tablic – jedną do przechowywania projektów, drugą do przechowywania zadań. Obie zainicjalizujemy sobie wstępnie na 100 zadań i 100 projektów.
static String [] tasks = new String[100]; static String [] projects = new String[100];
Dodatkowo stworzymy sobie tablicę do przechowywania logów – czyli spisu wszystkich operacji, które były wykonane w obrębie aplikacji.
static String [] changeLog = new String[100];
Następnie będziemy potrzebowali jakiś zmiennych gdzie będziemy przechowywać index tablicy, który nie jest jeszcze zarezerwowany przez zadanie/projekt/log. Za każdym dodaniem jednej z tych rzeczy będziemy inkrementować konkretną zmienną – wkrótce wszystko się wyjaśni. Teraz zainicjalizujmy je.
static int tasksCount = 0; static int projectsCount = 0; static int changeLogCount = 0;
Będą to pola, które wykorzystamy do naszej aplikacji – przejdźmy dalej, do tworzenia metod do obsługi wszystkich funkcjonalności.
Póki co wszystkie zmienne i metody będą statyczne – później pokażę Ci o co chodzi ze słowem static i jak można się go “pozbyć”.
Nasz kod aktualnie wygląda tak:
public class Main { static String [] tasks = new String[100]; static String [] projects = new String[100]; static String [] changeLog = new String[100]; static int tasksCount = 0; static int projectsCount = 0; static int changeLogCount = 0; public static void main(String[] args) { } }
Menu
Pierwszą rzeczą jaką musimy zrobić to stworzyć metodę do wyświetlania menu użytkownikowi. Zwykła, prosta funkcja void.
public static void displayMenu() { System.out.println("1 - Create new task"); System.out.println("2 - Remove task"); System.out.println("3 - Create new project"); System.out.println("4 - Remove project"); System.out.println("5 - Display all tasks"); System.out.println("6 - Display all projects"); System.out.println("7 - Display change log"); System.out.println("0 - Exit app"); }
I to tyle, będziemy jej używać do pokazania użytkownikowi pod jaką liczbą jaka jest ukryta funkcjonalność.
Dodawanie zadania
Zacznijmy od dodawania nowego zadania do naszej tablicy.
Sygnatura metody będzie wyglądać tak:
public static void addTask(String task) { }
Jest to metoda typu void, która jako argument przyjmuję nazwę zadania. Czas z nim coś zrobić – czas go dodać do tablicy.
Przed dodaniem do tablicy, jednak musimy sprawdzić czy task zmieści się jeszcze w naszej tablicy. Czyli musimy sprawdzić czy wartość zmiennej tasksCount jest mniejsza od długości tablicy zadań – aby nie wyjść poza zakres tablicy! Krótko mówiąc nasz index nie może przekroczyć 99 – bo nasza tablica jest indeksowana od 0 do 99.
boolean hasCapacityForNewTask = tasksCount < tasks.length;
Jeżeli otrzymamy prawdę to czas na dodanie zmiennej do tablicy:
if (hasCapacityForNewTask) { tasks[tasksCount] = task; }
Do odpowiedniego miejsca w tablicy przypisujemy nasze zadanie podane przez argument do funkcji.
Jeszcze musimy tylko zwiększyć nasz taskCount – aby podczas następnego dodawania zadania trafić na puste miejsce w tablicy.
tasksCount++;
Operator ++ zwiększa wartość zmiennej o 1.
Czyli nasza metoda wygląda tak:
public static void addTask(String task) { boolean hasCapacityForNewTask = tasksCount < tasks.length; if (hasCapacityForNewTask) { tasks[tasksCount] = task; tasksCount++; } }
Dodawanie zadań mamy za sobą, czas przejść dalej.
Usuwanie zadania
Trochę trudniejszą funkcjonalnością jest usuwanie zadania – szczególnie, gdzie tak jak my przechowujemy nasze zadania w tablicy. Musimy zadbać o to, aby między zadaniami nie było żadnych luk – czyli usuwanie zadań będzie polegało na przesuwaniu zadań “w dół” o jeden index, które są “nad” usuwanym zadaniem. Trochę zagmatwane, przejdźmy jednak do przykładu.
public static void removeTask(int indexTask) { }
Tak wygląda sygnatura naszej metody – jako argument przekazujemy index elementu, który ma zostać usunięty.
Przed samym usunięciem musimy sprawdzić czy w ogóle podany indexTask wskazuje na istniejące zadanie – czyli indexTask będzie musiał być mniejszy od tasksCount. Taka zależność musi być spełniona, ponieważ tasksCount wskazuje na pierwsze puste miejsce w tablicy – czyli stosujemy operator <, aby nasz index był o jeden mniejszy od tasksCount – czyli ostatni task w tablicy.
boolean isTaskExist = indexTask < tasksCount;
Jeżeli ten warunek jest spełniony to możemy brać się za usuwanie – czyli przesuwanie tablicy.
if (isTaskExist) { for(int i=indexTask; i<tasksCount-1;i++) { tasks[i] = tasks[i+1]; } }
Już tłumaczę co tu się dzieje.
Naszym punktem startowym pętli jest i = indexTask – czyli startujemy od indexu, który jest podany jako argument. To właśnie to miejsce w tablicy chcemy “przycisnąć” innymi zadaniami.
Następnym warunkiem jest i < tasksCount – czyli dzięki temu warunkowi przejdziemy po wszystkich zadaniach, które występują – nie do końca tablicy, tylko do miejsca, gdzie znajduję się ostatnie zadanie! W warunku występuje – 1, ponieważ w pętli mamy i + 1 – gdybyśmy nie mieli -1 to wyszlibyśmy poza zakres zadań w tablicy.
tasks[i] = tasks[i+1] odpowiada za przesuwanie wartości w tablicy – czli np. do tasks[0] przypisujemy wartość tasks[1] itd. – przesuwamy nasze zadania ” w dół”.
Po przesunięciu wszystkich zadań nie możemy oczywiście zapomnieć o zmniejszeniu indeksu ostatniego zadania – w końcu, wszystkie zadania zostały przesuniętę w dół.
tasksCount--;
I teraz cała nasza funkcja odpowiedzialna za usuwanie zadania wygląda tak:
public static void removeTask(int indexTask) { boolean isTaskExist = indexTask < tasksCount; if (isTaskExist) { for(int i=indexTask; i<tasksCount-1;i++) { tasks[i] = tasks[i+1]; } tasksCount--; } }
Wyświetlanie zadań
Na sam koniec musimy wyświetlić tą naszą całą listę zadań użytkownikowi – w końcu musi wiedzieć jakie zadania ma do wykonania.
Będzie to po prostu metoda, zawierająca pętle, w której wyświetlimy istniejące zadania.
public static void displayTasks() { }
W niej dajmy informację o tym co się dzieje:
System.out.println("List of tasks: ");
A w pętli wyświetlmy zadania:
for (int i=0; i<tasksCount;i++) { System.out.println(tasks[i]); }
Spójrz na warunek graniczny – wyświetlamy do końca zakresu występowania zadań w tablicy – a nie do samego końca tablicy. Nie wyświetlamy całej tablicy, ponieważ od tasks[tasksCount] znajdują się puste wartości – a dokładnie null.
Czyli cała nasza metoda wyświetlająca wygląda tak:
public static void displayTasks() { System.out.println("List of tasks: "); for (int i=0; i<tasksCount;i++) { System.out.println(tasks[i]); } }
Mamy już trzy podstawe metody naszej aplikacji – czas je sprawdzić w działaniu.
Uruchamiamy
Zanim jeszcze uruchomimy musimy wszystko ładnie zgrać w metodzie main, skąd startuje aplikacja.
Na początek będziemy potrzebowali Scannera do odczytu wartości od użytkownika oraz pętli while, która ma za zadanie utrzymywać naszą aplikację “przy życiu” – czyli będzie pętlą (prawie) nieskończoną – dzięki za każdym razem będziemy dostawać wyświetlone menu oraz będziemy mogli skorzystać z aplikacji.
Scanner scanner = new Scanner(System.in); while(true) { }
Aby faktycznie pętla była prawie nieskończona, dodajmy w warunku zmienną boolean, która pozwoli na wyjście z pętli – czyli zakończenie działania aplikacji.
Scanner scanner = new Scanner(System.in); boolean isApplicationRun = true; while(isApplicationRun) { }
Wystarczy tylko teraz zmienić isApplicationRun na false i aplikacja zakończy swoje działanie – ponieważ pętla while wykonuje się dopóki warunek jest prawdziwy!
Dodajmy jeszcze zmienną radix, do której będziemy wczytywać numer opcji wybranej przez użytkownika.
Scanner scanner = new Scanner(System.in); int radix; boolean isApplicationRun = true; while(isApplicationRun) { }
Czas przejść do “wrzucenia” naszej aplikacji do pętli while. Wyświetlmy użytkownikowi menu oraz poprośmy o to jaką opcję chce wybrać.
while(isApplicationRun) { displayMenu(); System.out.print("Type number to choose option: "); radix = scanner.nextInt(); }
Skoro mamy już opcję jaką użytkownik wybrał to czas na sterowanie działania programu – możemy do tego użyć if lub switch. My wybierzemy switch.
while(isApplicationRun) { displayMenu(); System.out.print("Type number to choose option: "); radix = scanner.nextInt(); switch(radix) { default: System.out.println("Nie ma takiej opcji."); break; } } }
Od razu dodałęm do niej default, który wyświetli się, gdy żadna z wymienionych opcji nie zostanie wybrana.
Dodajmy teraz nasze funkcjonalności do switcha.
Na początku dodawanie zadania – będzie to case 1, ponieważ nasze menu mówi, że po naciśnięciu 1 można dodać zadanie.
case 1: System.out.println("Podaj nazwę zadania do dodania: "); String task = scanner.next(); addTask(task); break;
Czyli prosimy o podanie nazwy zadania, wczytujemy go oraz wywołujemy naszą napisaną metodę addTask. I mamy już opanowane dodawanie zadań.
Dodajmy jeszcze możliwość usuwania zadań – czyli case 2:
case 2: System.out.println("Podaj index zadania do usunięcia: "); int index = scanner.nextInt(); removeTask(index); break;
Działa to analogicznie do case 1 – prosimy o index do usunięcia, wczytujemy go i wywołujemy wcześniej napisaną metodę removeTask.
Musimy jeszcze zapewnić case 5 – wyświetlanie listy zadań.
case 5: displayTasks(); break;
Jest to tylko wywołanie metody displayTasks() – ona już odpowiada za wyświetlanie zadań.
Zakończenie aplikacji
Nie mamy jeszcze obsłużonego zamknięcia aplikacji – czyli case 0.
Co musimy zmienić, aby zakończyć naszą aplikację? Musimy wyjść z pętli while – która jest sterowana warunkiem isApplicationRun – aktualnie jest ustawiona na true. Wystarczy ją zmienić na false i nasza pętla już się nie wykona.
case 0: isApplicationRun=false; break;
Czyli ostatecznie nasza funkcja main wygląda tak:
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int radix; boolean isApplicationRun = true; while(isApplicationRun) { displayMenu(); System.out.print("Type number to choose option: "); radix = scanner.nextInt(); switch(radix) { case 1: System.out.println("Podaj nazwę zadania do dodania: "); String task = scanner.next(); addTask(task); break; case 2: System.out.println("Podaj index zadania do usunięcia: "); int index = scanner.nextInt(); removeTask(index); break; case 5: displayTasks(); break; case 0: isApplicationRun=false; break; default: System.out.println("Nie ma takiej opcji."); break; } } }
Testowanie
Nasza cała aplikacja aktualnie powinna wyglądać tak:
import java.util.Scanner; public class Main { static String [] tasks = new String[100]; static String [] projects = new String[100]; static String [] changeLog = new String[100]; static int tasksCount = 0; static int projectsCount = 0; static int changeLogCount = 0; public static void displayMenu() { System.out.println("1 - Create new task"); System.out.println("2 - Remove task"); System.out.println("3 - Create new project"); System.out.println("4 - Remove project"); System.out.println("5 - Display all tasks"); System.out.println("6 - Display all projects"); System.out.println("7 - Display change log"); System.out.println("0 - Exit app"); } public static void addTask(String task) { boolean hasCapacityForNewTask = tasksCount < tasks.length; if (hasCapacityForNewTask) { tasks[tasksCount] = task; tasksCount++; } } public static void removeTask(int indexTask) { boolean isTaskExist = indexTask < tasksCount; if (isTaskExist) { for(int i=indexTask; i<tasksCount-1;i++) { tasks[i] = tasks[i+1]; } tasksCount--; } } public static void displayTasks() { System.out.println("List of tasks: "); for (int i=0; i<tasksCount;i++) { System.out.println(tasks[i]); } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int radix; boolean isApplicationRun = true; while(isApplicationRun) { displayMenu(); System.out.print("Type number to choose option: "); radix = scanner.nextInt(); switch(radix) { case 1: System.out.println("Podaj nazwę zadania do dodania: "); String task = scanner.next(); addTask(task); break; case 2: System.out.println("Podaj index zadania do usunięcia: "); int index = scanner.nextInt(); removeTask(index); break; case 5: displayTasks(); break; case 0: isApplicationRun=false; break; default: System.out.println("Nie ma takiej opcji."); break; } } } }
Uruchommy ją w celu jej przetestowania – dodajmy 5 zadań, wyświetlmy je oraz usuńmy dwa ze środka i na koniec zobaczmy stan listy zadań.
Stan zadań po dodaniu zadań:
List of tasks: Zakupy Pranie Prasowanie Bieganie Taniec
*Usuń 2 – Pranie i prasowanie i sprawdźmy stan listy.
List of tasks: Zakupy Bieganie Taniec
Wszystko śmiga jak powinno – podstawowa wersja aplikacji działa.
Podsumowanie
Wspólnie przygotowaliśmy pierwszą część aplikacji – zarządzanie zadaniami – teraz czas na Ciebie. Twoim zadaniem jest obsługa projektów – ma to wyglądać w taki sam sposób jak w przypadku zadań. Dodatkowo musisz obsłużyć change log – czyli w tablicy musimy przechowywać listę wykonanych operacji np. Dodano zadanie X. Usunięto zadanie Y.
Pamiętaj, aby dodawanie wartości do change log napisać oddzielną metodę, która będzie wywoływana podczas wykonywania operacji – jako argument przekazuj wiadomość jaka ma być zapisana.
Przykładowe rozwiązanie aplikacji możesz znaleźć tutaj.
Jeżeli jest coś dla Ciebie niezrozumiałe lub masz z czymś problemy to proszę Cię o pisanie na grupie Facebook, ponieważ wtedy szybciej otrzymasz pomoc – nie tylko ode mnie, ale również od innych kursantów!
Witam, materiał jak zwykle świetny, odświeżenie tego czego się uczyliśmy w ciekawszej wersji ;)! Jedyne czego nie zrozumiałem to samej pracy do wykonania. Nie rozumiałem o co chodzi z Projektem itd ale po przeanalizowaniu przykładowego rozwiązania wszelkie wątpliwości się rozwiały :)!
Cześć, próbowałem właśnie wymyśleć praktyczne zadanie, aby zawierały się w nim poznane już zagadnienia, dlatego z każdym następnym tygodniem będzie do wykonania kolejna praca. 😉