Java fundamentals through coding exercises
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
10 KiB

  1. # Yhteystiedot ja osoitekirja 3/3 - Yhteystietojen järjestäminen aakkosjärjestykseen
  2. Tässä tehtävässä sinun tehtäväsi on järjestää yhteystiedot nimien mukaiseen aakkosjärjestykseen. Tämä tehtävä on ohjelmointi 1 -kurssin näkökulmasta edistynyttä lisäsisältöä, minkä vuoksi se on julkaistu bonustehtävänä.
  3. ## Taustatietoa
  4. Jos yritämme järjestää oman Contact-luokan oliot Collections.sort-metodin avulla, saamme seuraavan virheilmoituksen:
  5. ```
  6. "The method sort(List) in the type Collections is not applicable for the arguments (List)"
  7. ```
  8. Tämä johtuu siitä, että luokkamme ei ole yhteensopiva `Comparable`-tyypin kanssa. `Collections.sort`-metodi ei siis pysty vertailemaan olioitamme keskenään ilman, että määrittelemme sille lisäksi käytettävän vertailuoperaation.
  9. Tutustu Javan `Comparator.comparing`-metodiin, jonka avulla voit määritellä vertailijan kutsumaan mitä tahansa oman luokkasi metodia olioiden järjestämiseksi: [https://www.baeldung.com/java-8-comparator-comparing](https://www.baeldung.com/java-8-comparator-comparing). Tällä kurssilla sinun kannattaa lukea artikkelista kohta [3.1. Key Selector Variant](https://www.baeldung.com/java-8-comparator-comparing#1-key-selector-variant) ja sitä aikaisemmat kappaleet, mutta ei välttämättä tätä kappaletta pidemmälle.
  10. Kuten artikkelissa kerrotaan, `Comparator.comparing`-metodille voidaan antaa metodiviittaus mihin tahansa metodiin. `Collections.sort` käyttää tällöin vertailussa juuri haluamasi metodin palauttamia arvoja, joita vertaillaan keskenään. Voisimme siis esimerkiksi järjestää merkkijonot pituusjärjestykseen vertailemalla merkkijonojen pituuksia, jotka selviävät `length()`-metodin avulla: `Comparator.comparing(String::length)`.
  11. `Collections.sort` käyttää tässä esimerkissä järjestelemiseen `Comparator`-oliota, joka vertaa merkkijonojen pituuksia toisiinsa:
  12. ```
  13. List nesteet = Arrays.asList("maito", "Vesi", "ketsuppi", "bensa", "Limu");
  14. // tehdään järjestely merkkijonojen length-metodin mukaan:
  15. Collections.sort(nesteet, Comparator.comparing(String::length));
  16. System.out.println(nesteet); // lyhimmästä merkkijonosta pisimpään: [Limu, Vesi, bensa, maito, ketsuppi]
  17. ```
  18. ## Tehtävä
  19. Jatkokehitä nyt edellisissä tehtävissä käyttämiäsi kolmea osoitekirja- ja yhteystietoluokkaa siten, että osoitekirjan sisältöä listattaessa "list"-komennolla yhteystiedot esitetään aakkosjärjestyksessä nimen mukaan.
  20. Sinun kannattaa hyödyntää edellä käsiteltyä `Collections.sort`-metodia sekä `Comparator.comparing`-metodia siten, että annat comparing-metodille metodiviittauksen `Contact`-luokkasi `getName`-metodiin.
  21. ## ESIMERKKI
  22. ```
  23. This is an address book application. Available commands:
  24. list
  25. help
  26. add <name>, <email>, <phone>
  27. search <name>
  28. exit
  29. > add Maija Meikäläinen, maija@example.com, +35850555556
  30. Added Maija Meikäläinen (email: maija@example.com, phone: +35850555556)
  31. > add Matti Meikäläinen, matti@example.com, +35850555555
  32. Added Matti Meikäläinen (email: matti@example.com, phone: +35850555555)
  33. > add Benjamin Meikäläinen, benjamin@example.com, +35850555557
  34. Added Benjamin Meikäläinen (email: benjamin@example.com, phone: +35850555557)
  35. > add Abraham Meikäläinen, abraham@example.com, +35850555558
  36. Added Abraham Meikäläinen (email: abraham@example.com, phone: +35850555558)
  37. > add Wolverine Meikäläinen, wolverine@example.com, +35850555559
  38. Added Wolverine Meikäläinen (email: wolverine@example.com, phone: +35850555559)
  39. > list
  40. Abraham Meikäläinen (email: abraham@example.com, phone: +35850555558)
  41. Benjamin Meikäläinen (email: benjamin@example.com, phone: +35850555557)
  42. Maija Meikäläinen (email: maija@example.com, phone: +35850555556)
  43. Matti Meikäläinen (email: matti@example.com, phone: +35850555555)
  44. Wolverine Meikäläinen (email: wolverine@example.com, phone: +35850555559)
  45. > exit
  46. Bye!
  47. ```
  48. **AddressBookApp.java**
  49. ```
  50. import java.util.ArrayList;
  51. import java.util.List;
  52. import java.util.Scanner;
  53. public class AddressBookApp {
  54. private static String welcomeText = "This is an address book application. Available commands:\n";
  55. private static String commandMenu = " list\n" +
  56. " help\n" +
  57. " add <name>, <email>, <phone>\n" +
  58. " search <name>\n" +
  59. " exit\n";
  60. // Keep here instead of translating to a local variable
  61. private static String inputCLIPrefix = "> ";
  62. // Keep added addressBook values during application runtime
  63. private static AddressBook addressBook = new AddressBook();
  64. public static void main(String[] args) {
  65. System.out.print(welcomeText + commandMenu);
  66. while (true) {
  67. runApp();
  68. }
  69. }
  70. private static void runApp() {
  71. Scanner inputPrompt = new Scanner(System.in);
  72. Object[] getInput = parseInput(inputCLIPrefix, inputPrompt);
  73. String inputCmd = String.valueOf(getInput[0]);
  74. // TODO Avoid risk of ClassCastException
  75. List<String> inputArgs = (ArrayList<String>)getInput[1];
  76. int argsCount = 3;
  77. switch(inputCmd) {
  78. case "list":
  79. System.out.println(addressBook.toString());
  80. break;
  81. case "help":
  82. System.out.print(welcomeText + commandMenu);
  83. break;
  84. case "add":
  85. // TODO Should this be checked in AddressBook.add method instead?
  86. if (inputArgs.size() != argsCount) {
  87. System.err.printf("Invalid count of input arguments (expected %d).\n", argsCount);
  88. break;
  89. }
  90. String name = String.valueOf(inputArgs.get(0));
  91. String email = String.valueOf(inputArgs.get(1));
  92. String phone = String.valueOf(inputArgs.get(2));
  93. Contact contact = new Contact(name, email, phone);
  94. // NOTE: Else condition not needed as 3 arguments is always passed to this object method call
  95. if(addressBook.add(contact)) {
  96. System.out.printf("Added %s\n", contact.toString());
  97. }
  98. break;
  99. case "search":
  100. String searchTerm = String.valueOf(inputArgs.get(0));
  101. Contact match = addressBook.search(searchTerm);
  102. if (match == null) {
  103. System.out.printf("%s does not match any contact.\n", searchTerm);
  104. } else {
  105. System.out.println(match.toString());
  106. }
  107. break;
  108. case "exit":
  109. System.out.print("Bye!\n");
  110. System.exit(0);
  111. default:
  112. System.err.println("Command not found.");
  113. //break;
  114. }
  115. }
  116. private static Object[] parseInput(String prefix, Scanner inputRaw) {
  117. System.out.print(prefix);
  118. String inputR = inputRaw.nextLine();
  119. String command = inputR.split(" ")[0];
  120. String[] theRest = inputR.split(",");
  121. theRest[0] = theRest[0].replaceAll("^\\s*" + command + "\\s*","");
  122. List<String> arguments = new ArrayList<String>();
  123. for (int i = 0; i < theRest.length; i++) {
  124. arguments.add(theRest[i].trim());
  125. }
  126. Object[] parsedOutput = new Object[2];
  127. parsedOutput[0] = command;
  128. parsedOutput[1] = arguments;
  129. return parsedOutput;
  130. }
  131. }
  132. ```
  133. **AddressBook.java**
  134. ```
  135. import java.util.ArrayList;
  136. import java.util.Collections;
  137. import java.util.Comparator;
  138. import java.util.List;
  139. public class AddressBook {
  140. private List<Contact> contacts;
  141. public AddressBook() {
  142. this.contacts = new ArrayList<>();
  143. }
  144. public boolean add(Contact newContact) {
  145. // Create a temporary ArrayList, if we have contacts already
  146. // Get list of all contacts, put them into the new ArrayList contactsTemp
  147. // Loop through all contacts in contactsTemp
  148. // Check the current contact in contactsTemp against newContact
  149. if (this.contacts.size() > 0) {
  150. List<Contact> contactsTemp = new ArrayList<>(this.contacts);
  151. for (Contact tempContact : contactsTemp) {
  152. if (tempContact.equals(newContact)) {
  153. System.out.println("That contact already exists.");
  154. return false;
  155. }
  156. }
  157. }
  158. this.contacts.add(newContact);
  159. return true;
  160. }
  161. public Contact search(String keyword) {
  162. for (Contact current : this.contacts) {
  163. String name = current.getName();
  164. if (name != null && name.toLowerCase().contains(keyword.toLowerCase())) {
  165. return current; // palautetaan löytynyt arvo heti
  166. }
  167. }
  168. return null; // palautetaan null, jos ei löytynyt
  169. }
  170. @Override
  171. public String toString() {
  172. String returnString = "";
  173. // Sort by contact names. Define new Comparator object
  174. Collections.sort(this.contacts, new Comparator<Contact>() {
  175. public int compare(Contact contact1, Contact contact2) {
  176. return contact1.getName().compareTo(contact2.getName());
  177. }
  178. });
  179. for (Contact contact : this.contacts) {
  180. returnString += contact + "\n";
  181. }
  182. return returnString;
  183. }
  184. }
  185. ```
  186. **Contact.java**
  187. ```
  188. public class Contact {
  189. private String name;
  190. private String email;
  191. private String phone;
  192. // NOTE: This does not validate or check input String values
  193. // (Is name actually a name, email a valid email, and phone number an actual phone number?)
  194. public Contact(String name, String email, String phone) {
  195. this.name = name;
  196. this.email = email;
  197. this.phone = phone;
  198. }
  199. public String getName() {
  200. return this.name;
  201. }
  202. @Override
  203. public boolean equals(Object contact) {
  204. if (this == contact) { return true; }
  205. if (!(this instanceof Contact)) { return false; }
  206. Contact contactT = (Contact) contact;
  207. if (this.name.equals(contactT.name) && this.email.equals(contactT.email) && this.phone.equals(contactT.phone)) {
  208. return true;
  209. }
  210. return false;
  211. }
  212. public String toString() {
  213. // Haluttu muoto: "Maija Meikäläinen (email: foo@bar.fi, phone: 5555)"
  214. return this.name + " (email: " + this.email + ", phone: " + this.phone + ")";
  215. }
  216. }
  217. ```