diff --git a/data/part-1/1-starting-programming.md b/data/part-1/1-starting-programming.md index 4523dc8b3..9117c80c1 100644 --- a/data/part-1/1-starting-programming.md +++ b/data/part-1/1-starting-programming.md @@ -6,11 +6,11 @@ hidden: false - + - Become familiar with the 'NetBeans with TMC' development environment used in this course. - + - Learn to download and submit programming exercises. @@ -18,33 +18,33 @@ hidden: false - + Modern programming is practically always done in an IDE (integrated development environment). An IDE contains a set of useful tools for the programmer. It does not create the program by itself, but it can give hints about common mistakes in the code, and help the programmer understand the structure of the program. - + The IDE we use on this course is called [NetBeans](https://netbeans.apache.org), and we use it with Test My Code plugin. - + To start the course you need (1) a MOOC.fi account, which you can create at the top of this course material, (2) Java (Java JDK), and (3) Netbeans with TMC development environment (in the future TMC). All of these can be installed with the following instructions. **When following the instructions, select "MOOC" as your organization and "Java Programming I" as your course.** Installation instructions for Java and NetBeans can be found here: [Java and NetBeans installation guide](https://www.mooc.fi/en/installation/netbeans) - + Once you have created the user account and installed Java and TMC, watch the video below. The video demonstrates what happens when 'Netbeans with TMC' is opened for the first time. We select the organization and course, and do the first programming exercise. In the video, the user selects the 2019 course, but you should remember to **select Java Programming I as your course**! - + This is the first programming exercise of this course. In this exercise, you'll familiarize yourself with the development environment. - + The exercise template already contains the following template of code: @@ -57,19 +57,19 @@ public class Sandbox { } ``` - + The line "// Write your program here" is a _line comment_, and the computer will ignore it when executing the program. - + First, submit the exercise template to be checked on the server without changing anything. In this way, you practice submitting an exercise. You can submit an exercise by selecting the TMC menu within TMC, and then "Submit". - + Once you have submitted the exercise, try following the video above to add a print command to the program and to execute the program (by pressing the play - button). When you've been able to get your program to print some text (this text can be anything), submit the exercise to the server once more. - + You should use this sandbox exercise to try out different things later on. When you encounter something new in the material, try it out in the sandbox first, and then solve the exercises on the topic. @@ -77,19 +77,19 @@ You should use this sandbox exercise to try out different things later on. When ## Programmers Write Source Code - + Programming is designing and implementing software. The functionality is implemented based on the wishes and requirements of the users and the customers. Programs are typically implemented (i.e., written or "coded") in a programming language meant to be written and read by humans. - + There are hundreds of programming languages out there, and this course focuses one of them. The language used in this course is [Java](), which is one of the most commonly-used programming languages in the world. Learning Java also makes it easier to pick up other programming languages. - + Programming languages, such as Java, have many commands built-in that a programmer uses when developing software. This makes programming easier as you don't need to implement everything from scratch. For example, programming languages typically have built-in options available for different menus and views used for making graphical user interfaces. Indeed, a large part of programming is making use of available functions and tools in solving problems -- this, however, requires programming experience, which you only gain by programming. - + The "code" you write is called **source code**. Source code consists of statements and expressions, which are read line by line from top to bottom, and from left to right. For example, to print "Hello world", you can use the pre-defined Java command `System.out.println()`, to which you need to provide the text inside the parentheses that you'd like to be printed: @@ -97,16 +97,16 @@ The "code" you write is called **source code**. Source code consists of statemen System.out.println("Hello World"); ``` - + The above statement is pre-built into Java, and it's used for printing a string. The statement tells the computer to output the string that's been provided to it, placed between the quotation marks. The statement ends with a semicolon `;`. - + Java programs require a certain frame around the code to work. Don't worry if it appears intimidating, it'll become very familiar over this course. Although you might not be able to make sense of the surrounding frame of code, you could probably guess what this following program does based on the print statement described above. - + You'll find the first quiz of the course below. You can answer the quizzes right here in the course material. diff --git a/data/part-1/2-printing.md b/data/part-1/2-printing.md index c4d19ec1c..4d0f313c6 100644 --- a/data/part-1/2-printing.md +++ b/data/part-1/2-printing.md @@ -4,19 +4,9 @@ title: "Printing" hidden: false --- - - @@ -28,19 +18,7 @@ hidden: true - The print command `System.out.println("Hello world");` prints the text "Hello world". @@ -54,23 +32,13 @@ Hello world! - In this material, text boxes like the one above demonstrate an output produced by the example code. Accordingly, the above program would produce the print output "Hello World!". You can try any of these examples in the exercise template named "Sandbox", which you will find in the programming environment. You can print any text you want with the command, as long as the command `System.out.println("arbitrary text");` -- i.e., `System` dot `out` dot `println` open parenthesis `(` "the text" close parenthesis `)` and semicolon `;` remains unchanged. The command below will print the text "Hello there!". - ```java System.out.println("Hello there!"); @@ -82,19 +50,7 @@ Hello there! - ## Program Boilerplate @@ -110,15 +66,7 @@ public class Example { } ``` - Execution of the program starts from the line that follows `public static void main(string[] args) {`, and ends at the closing curly bracket `}`. Commands are executed one line at a time. We'll learn what the terms `public class` and `public static void` mean later on. In the above example, `System.out.println("Text to be printed")` is the only command to be executed. Its output is: @@ -128,26 +76,7 @@ Text to be printed - @@ -170,34 +99,7 @@ public class Example { - Here's the second programming exercise of this course. If you'd like, you can watch this video on how to solve the exercise first: @@ -228,19 +130,7 @@ Once you've finished the exercise and see that it prints the correct string, ret - @@ -254,27 +144,7 @@ The IDE both compiles and executes the program with just one press of a button. - ## Printing Multiple Lines @@ -298,19 +168,8 @@ Hello world! - - The programming exercises will be checked by TMC Henrik, who is meticulous. The guidelines in the assignments regarding the print format are very precise. If the assignment expects you to print a parenthesis, you must print the parenthesis. @@ -321,31 +180,7 @@ Learning programming is, in fact, a path full of mistakes -- and every error mes - @@ -372,15 +207,7 @@ a program - @@ -392,29 +219,7 @@ The animation below illustrates the use of the sout command. The user first writ - @@ -440,31 +245,7 @@ a dinosaur - ## Terminology and Code Comments @@ -490,35 +271,9 @@ world Although the previous example works, it's important to be considerate of other programmers (and your future self!) and to use line breaks. That way, anyone reading the program knows that each line does only a single concrete thing. - - - ### Comments diff --git a/data/part-1/3-reading-input.md b/data/part-1/3-reading-input.md index 1b4c5ed39..fee81951c 100644 --- a/data/part-1/3-reading-input.md +++ b/data/part-1/3-reading-input.md @@ -7,9 +7,9 @@ hidden: false - - - + + + - Learn to write a program that reads text written by a user. - Know what a "string" refers to in programming. @@ -18,7 +18,7 @@ hidden: false - + Input refers to text written by the user read by the program. Input is always read as a string. For reading input, we use the `Scanner` tool that comes with Java. The tool can be imported for use in a program by adding the command `import java.util.Scanner;` before the beginning of the main program's frame (`public class` ...). The tool itself is created with `Scanner scanner = new Scanner(System.in);`. ```java @@ -35,7 +35,7 @@ public class Program { } ``` - + Below is an example of a program which asks for user input, reads the string entered by the user, and then prints it. ```java @@ -61,10 +61,10 @@ public class Program { } ``` - + More precisely, input is read with the `scanner` tool's `nextLine()` method. The call `scanner.nextLine()` is left waiting for the user to write something. When user writes something and presses enter, the provided string is assigned to a __string variable__ (in this instance `message`). The program is then able to reference the variable `message` later on -- in the example above, the variable `message` is referenced in the print command. - + When the program is run, its output can look like the example below. In this example, the user has written the text "Hello world" -- user input is marked with red in the sample examples. @@ -75,17 +75,17 @@ Hello world - + The video below shows the process of making a program that reads user input. Watch the video before doing the next programming exercise. Take special notice of how the user input is provided to the Output window located at the bottom of TMC as the program is running. - + Write a program that asks the user to write a string. When the user has provided a string (i.e., written some text and pressed the enter key), the program should print the string that was provided by the user. - + The exercise template comes with a program template that includes the creation of a Scanner tool. ```java @@ -102,7 +102,7 @@ public class Message { } ``` - + Example output for when the user writes "Bye". @@ -113,7 +113,7 @@ Bye - + Example output for when the user writes "Once upon a time...". @@ -126,7 +126,7 @@ Once upon a time... - + Next up, let's take a step back, and examine what on earth `String message = ...` even means. @@ -134,20 +134,20 @@ Next up, let's take a step back, and examine what on earth `String message = ... As you might have noticed, in programming we refer to "strings" rather than "text". The term "string" is shorthand for "string of characters" which describes how the computer sees text on a more fundamental level: as a sequence of individual characters. - + We've so far used strings in two ways. When practicing the print command, we passed the string to be printed to the print command in quotation marks, and when practicing reading input, we saved the string we read to a variable. - + In practice, variables are named containers that contain information of some specified type and have a name. A string variable is declared in a program by stating the type of the variable (`String`) and its name (`myString`, for instance). Typically a variable is also assigned a value during its declaration. You can assign a value by following the declaration with an equals sign followed by the value and a semicolon. - + A string variable called `message` that is assigned the value "Hello world!" is declared like this: ```java String message = "Hello world!"; ``` - + When a variable is created, a specific container is made available within the program, the contents of which can later be referenced. Variables are referenced by their name. For instance, creating and printing a string variable is done as shown below: ```java @@ -161,7 +161,7 @@ Hello world! - + A string enclosed in a programming language's quotation marks is called a "string literal", i.e., a string with a specified value. A common programming mistake is trying to put quotation marks around variable names. If there were quotation marks around the string variable `message`, the program would print the text "message" instead of the "Hello world!" text held by the `message` variable. ```java @@ -177,7 +177,7 @@ message ### Concatenation - Joining Strings Together - + The string to be printed can be formed from multiple strings using the `+` operator. For example, the program below prints "Hello world!" on one line. ```java @@ -189,7 +189,7 @@ public class Program { } ``` - + The same method can be used to join a string literal and the value of a string variable. ```java @@ -203,11 +203,7 @@ public class Program { } ``` - @@ -215,7 +211,7 @@ Hello world! ... and the universe! - + We can do the same with any number of strings. ```java @@ -239,7 +235,7 @@ My name is Bond, James Bond - + The exercise template contains the following program. ```java @@ -252,7 +248,7 @@ public class HiAdaLovelace { } ``` - + Modify the program so that it prints the contents of the variable `name`, and the printed text is the following in its full form: @@ -261,7 +257,7 @@ Hi Ada Lovelace! - + NB! When using the `System.out.println` command, do not pass in the string "Ada Lovelace" as a parameter. Instead, use the existing variable `name`: `System.out.println("Hi " + ...)` @@ -269,7 +265,7 @@ NB! When using the `System.out.println` command, do not pass in the string "Ada ## Reading Strings - + The `reader.nextLine();` command reads the user's input and *returns* a string. If we then want to use the string in the program, it must be saved to a string variable -- `String message = scanner.nextLine();`. A value saved to a variable can be used repeatedly. In the example below, the user input is printed twice. ```java @@ -309,10 +305,10 @@ This will be printed twice... - + Write a program that asks the user to write a string. When the user has given a string (that is, written some text and pressed enter), the program must print the user's string three times (you can use the `System.out.println` command multiple times). - + The exercise template already includes the code that creates the `Scanner` tool. ```java @@ -329,7 +325,7 @@ public class MessageThreeTimes { } ``` - + Example output for when the user writes the string "Hi". @@ -342,7 +338,7 @@ Hi - + Example output when the user writes "Once upon a time...". @@ -360,7 +356,7 @@ Once upon a time... ## Input String as a Part of Output - + We noticed in the "Hi Ava Lovelace!" exercise that string literals and string variables can be joined using the `+` -operator. The example below demonstrates a program that takes user input and prints it concatenated with a string literal. ```java @@ -393,10 +389,10 @@ You wrote this - + Write a program that prompts the user for their name with the message "What's your name?". When the user has written their name, the program has to print "Hi " followed by the user's name. - + The exercise template already includes the code that creates the `Scanner` tool. ```java @@ -412,7 +408,7 @@ public class Greeting { } ``` - + Example output when user gives the name Ada. @@ -423,7 +419,7 @@ Hi Ada - + Example output when user gives the name Lily. @@ -439,10 +435,10 @@ Hi Lily ## Program Execution Waits for Input - + When the program's execution comes a statement that attempts to read input from the user (the command `reader.nextLine()`), the execution stops and waits. The execution continues only after the user has written some input and pressed enter. - + In the example below, the program prompts the user for three strings. First, the program prints `Write the first string: `, and then waits for user input. When the user writes some text, the program prints `Write the second string: `, and then waits for user input again. This continues for a third time, after which the program prints all three strings. ```java @@ -486,7 +482,7 @@ third - + Write a program that works as follows: @@ -509,7 +505,7 @@ Thanks for sharing! - + The exercise template already includes the code that creates the `Scanner` tool. ```java @@ -528,7 +524,7 @@ public class Conversation { - + In the previous example, we saved the user input to three different string variables. This can be done as long as the variables all have different names (in the example, the names are `first`, `second` and `third`) @@ -555,7 +551,7 @@ public class Program { } ``` - + We can form more complicated texts whose content changes depending on the user's input by using more strings. In the example below, the user is told a bit more about the texts they wrote -- notice that the order in which the strings are printed can be changed. In the example below, the third input string is printed first. ```java @@ -602,13 +598,13 @@ All together: onetwothree - + **NB!** The example output might align wrong on narrow displays. If you're using only a limited portion of the browser window, or your display is otherwise very narrow, try to stretch the display horizontally to see if the text aligns differently. The exercise expects the text to align as it does on wider displays. - + Write a program that asks the user for a character's name and their job. The program then prints a short story. - + The output must be as shown below -- note, the name and job depend on the user's input. @@ -625,7 +621,7 @@ Perhaps Bob will not be a builder forever. - + The exercise template already includes the code that creates the `Scanner` tool. ```java diff --git a/data/part-1/4-variables.md b/data/part-1/4-variables.md index bdd2d17b3..7b37ecdad 100644 --- a/data/part-1/4-variables.md +++ b/data/part-1/4-variables.md @@ -8,8 +8,7 @@ hidden: false - + - Understand the concept of a variable. You know what variable types, names, and values are. - Know how to create and use string, integer, floating-point, and boolean variables. @@ -47,40 +46,27 @@ Open the questionnaire by following the link - + We've already familiarized ourselvese with strings to a degree while dealing with user inputs. Let's turn our attention to learning about other variable *types* commonly used in Java. - + A variable can be thought of as a container in which information of a given type can be stored. Examples of these different types include text (`String`), whole numbers (`int`), floating-point numbers (`double`), and whether something is true or false (`boolean`). A value is assigned to a variable using the equals sign (`=`). - + ```java int months = 12; ``` - In the statement above, the value of 12 is assigned to an integer variable called months. The statement could be read as: "the variable months is assigned the value 12". A variable's value can be joined to a string using the + sign, as seen in the following example. - ```java String text = "contains text"; @@ -94,18 +80,11 @@ System.out.println("Floating-point variable: " + floatingPoint); System.out.println("Boolean: " + trueOrFalse); ``` - -Output: +Output: - @@ -116,27 +95,17 @@ Booolean: true - + - + The exercise template contains a program that prints the following: - Chicken: 3 @@ -153,25 +122,11 @@ None! - + Modify the program in the given places so that it outputs the following: - @@ -193,20 +148,11 @@ Zetor - + Variable names are unique - no two variables can have the same name. The program in the following example is faulty as it attempts to create the variable `pi` twice. The variable is created the first time its declared. - ```java public class Example { @@ -220,16 +166,11 @@ public class Example { ``` - + The variable type is stated when the variable is first declared. When a new value is assigned to the variable, the type is no longer declared. - + ```java int value = 10; System.out.println(value); @@ -244,22 +185,16 @@ System.out.println(value); - + ## Changing a Value Assigned to a Variable - + A variable exists from the moment of its declaration, and its initial value is preserved until another value is assigned to it. You can change a variable's value using a statement that comprises the variable name, an equals sign, and the new value to be assigned. Remember to keep in mind that the variable type is only stated during the initial variable declaration. - ```java int number = 123; System.out.println("The value of the variable is " + number); @@ -268,16 +203,11 @@ number = 42; System.out.println("The value of the variable is " + number); ``` - -Output: +Output: - @@ -286,49 +216,43 @@ The value of the variable is 42 - + Let's look at the preceding program's execution step-by-step. When a variable appears in the program for the first time, i.e., the computer is told both its type (in this case `int`) and its name (in this case `number`), the computer creates a 'named container' for the variable. Then, the value on the right side of the equals sign is copied into this named container. ![](../img/drawings/part1.4-variable-change-1.png) - + Whenever a variable is referenced by its name in a program -- here, we want to print the string "The value of the variable is " followed by the value of the `number` variable -- its value is retrieved from a container that has the corresponding name. ![](../img/drawings/part1.4-variable-change-2.png) - + Whenever a value is assigned to a variable (here `number = 42`), a check is run to see whether a container with the given name already exists. If one does, a new value is copied in the place of the old value, and the old value disappears. If a container of the variable name is not found, the program execution ends in an error message, or it fails to run. ![](../img/drawings/part1.4-variable-change-3.png) - + The variable is then referenced again by its name in the program -- we again want to print the string "The value of the variable is " followed by the value of the `number` variable. We proceed as normal, retrieving the value of `number` from a container having its name. ![](../img/drawings/part1.4-variable-change-4.png) - + At the end of the program, you'll notice that the original value of the variable has vanished. A variable can hold only one value at a time. - + ## Variable's Type Persists - + Once a variable's type has been declared, it can no longer be changed. For example, a boolean value cannot be assigned to a variable of the integer type, nor can an integer be assigned to a variable of the boolean tpe. - ```java boolean integerAssignmentWillWork = false; @@ -337,18 +261,11 @@ integerAssignmentWillWork = 42; // Does not work int value = 10; integerAssignmentWillWork = value; // Neither does this ``` - -However, exceptions do exist: an integer can be assigned to a variable of the double type, since Java knows how to convert an integer to a double during assignment. - ```java double floatingPoint = 0.42; @@ -359,15 +276,10 @@ floatingPoint = value; // Also works ``` - + A floating-point value cannot, however, be assigned to an integer variable. The reason for this is that those who develop the language aim to prevent developers from making errors that lead to a loss of information. - ```java int value = 4.2; // Does not work @@ -376,19 +288,13 @@ double floatingPoint = 0.42; value = floatingPoint; // Neither does this ``` - + ## Naming Variables - + Naming variables is a fundamental aspect of describing a program. Let's look at two examples. - ```java double a = 3.14; double b = 22.0; @@ -402,13 +308,7 @@ System.out.println(c); - ```java double pi = 3.14; double radius = 22.0; @@ -423,34 +323,28 @@ System.out.println(surfaceArea); - + Both of the preceding examples function the same way and output the same result. One of them is, however, much more understandable. The objective here is to compute the surface area of a circle. The value of pi is defined in the first row, the circle's radius in the second, and the surface area calculated in the third. - + - + Programming is a problem-solving tool. The aim is to create solutions for any given problem, such as the automation of control in cars. As a problem is approached, the developer decides on the terms used to describe the problem domain. The terminology that is chosen, such as variable names, will serve to describe the problem for anyone who is to work with it in the future. - + As you're wording the problem that you're solving, think about the concepts related to that problem and appropriate terms that could be used to describe them. If you find it hard to come up with relevant names, think of the ones that definitely do not describe it. After this, settle on some terminology that you're going to use -- the good thing is that you can usually improve on it later on. - Variable naming is limited by certain constraints. Variable names cannot contain certain special symbols, such as exclamation marks (!). Spaces are also not allowed, since they're used to separate parts of commands. Instead of spaces, the convention in Java is to use a style known as [camelCase](https://en.wikipedia.org/wiki/Camel_case "Camel case – Wikipedia"). **Note!** The first letter of a variable name is always lower-cased: - + ```java int camelCaseVariable = 7; @@ -458,35 +352,23 @@ int camelCaseVariable = 7; - + Numbers can be used within a variable name as long as the name does not begin with a number. Also, a name cannot consists of numbers only. - + ```java int 7variable = 4; // Not allowed! int variable7 = 4; // Allowed, but is not a descriptive variable name ``` - + A variable's name cannot already be in use. These names include, for instance, variables previously defined in the program and commands provided by Java, such as `System.out.print` and `System.out.println`. --> - ```java int System.out.print = 4; // Not Allowed! @@ -498,27 +380,20 @@ int camelCase = 2; int camelCase = 5; // Not allowed -- camelCase variable is already in use! ``` - + Letters containing diacritics (e.g. the letters ä and ö used in Finnish) should also not be used in variable names. You can replace these letters with their non-diacritic equivalents. For example, you should convert ä -> a and ö -> o. - - + + ### Permissible Variable Names * lastDayOfMonth = 20 * firstYear = 1952 * name = "Essi" - ### Impermissible Variable Names @@ -528,31 +403,21 @@ Letters containing diacritics (e.g. the letters ä and ö used in Finnish) shoul * 1920 = 1 - + ## The Type of the Variable Informs of Possible Values - + A variable's type is specified when it's initally declared. For example, a variable containing the string "text" is declared with the statement `String string = "text";`, and an integer having the value 42 is declared with the statement `int value = 42;`. --> - + A variable's type determines the types of values that can be assigned to it. `String` types hold text, `int` types whole numbers, `double` floating-point numbers, and `boolean` types are either true or false. - -As such, the possible values of a given variable type are limited. For example, a string cannot contain an integer, **nor** can a double contain a boolean value. - @@ -564,28 +429,15 @@ As such, the possible values of a given variable type are limited. For example, | True or false value, i.e., `boolean` | `boolean right = true;` | A boolean contains either the value `true` or `false`. | - + ## Reading Different Variable Types from User - -In the text-based user interfaces that we've used in our programs, the user's input is always read as a string, since the user writes their input as text. Reading strings from the user has become familiar by this point - we do it using the `nextLine`-command of the Scanner helper method. +In the text-based user interfaces that we've used in our programs, the user's input is always read as a string, since the user writes their input as text. Reading strings from the user has become familiar by this point - we do it using the `nextLine`-command of the Scanner helper method. - ```java import java.util.Scanner; @@ -602,13 +454,7 @@ public class Program { } ``` - @@ -619,22 +465,17 @@ You wrote text - + Other input types, such as integers, doubles, and booleans are also read as text. However, they need to be converted to the target variable's type with the help of some tools provided by Java. - + ## Reading Integers - + The `Integer.valueOf` command converts a string to an integer. It takes the string containing the value to be converted as a parameter. - ```java String valueAsString = "42"; int value = Integer.valueOf(valueAsString); @@ -647,24 +488,11 @@ System.out.println(value); - -When using a Scanner object, the reading of the value is usually inserted directly into the type conversion. This happens like so: - ```java import java.util.Scanner; @@ -680,13 +508,7 @@ public class Program { } ``` - @@ -698,24 +520,16 @@ You wrote 42 - + - Write a program that asks the user for a value. The program should then print the value provided by the user. Here's a couple of examples: - @@ -727,13 +541,7 @@ You gave the number 3 - @@ -745,21 +553,17 @@ You gave the number 42 - + Test the functionality of your program with non-numerical inputs. The program should break as it doesn't know how to convert these inputs into numbers. We'll learn how to deal with exceptional cases like these in the advanced programming course. - + ### Reading Doubles - + The `Double.valueOf` command converts a string to a double. It takes the string containing the value to be converted as a parameter. - + ```java String valueAsString = "42.42"; double value = Double.valueOf(valueAsString); @@ -771,23 +575,12 @@ System.out.println(value); - + As with integers, the reading is nested within the conversion. This is done as follows: - ```java import java.util.Scanner; @@ -802,13 +595,7 @@ public class Program { } ``` - @@ -818,18 +605,11 @@ You wrote 1234.2 - + It's possible to also read an integer variable into a double, in which case the value is converted automatically to type double. The example below demonstrates how the previous program functions when the user inputs an integer. - @@ -840,24 +620,17 @@ You wrote 18.0 - + - + Write a program that asks the user for a floating-point number. The program then prints the user's input value. Example prints for the program can be seen below: - @@ -867,13 +640,7 @@ You gave the number 3.14 - @@ -887,30 +654,18 @@ You gave the number 2.718 - + ### Reading Booleans - + The `Integer.valueOf` command converts a string to an integer and the `Double.valueOf` converts it to a floating-point. The `valueOf` command also appears when converting a string to a boolean -- this is done with the command `Boolean.valueOf`. - + Boolean variables can either have the value `true` or `false`. When converting a string to a boolean, the string must be "true" if we want the boolean value to be `true`. The case is insensitive here: both "true" and "TRue" turn into the boolean value of `true`. All other strings turn into the boolean `false`. - ```java import java.util.Scanner; @@ -925,13 +680,7 @@ public class program { } ``` - @@ -941,13 +690,7 @@ You wrote false - @@ -957,13 +700,7 @@ You wrote true - @@ -973,26 +710,17 @@ You wrote true - + - Write a program that asks the user for a boolean value. The program should then print the value provided by the user. Example prints for the program can be seen below. - @@ -1002,13 +730,7 @@ True or false? false - @@ -1021,28 +743,14 @@ True or false? true - + ### Summary - + Finally, a summary: - ```java import java.util.Scanner; @@ -1058,34 +766,17 @@ public class Program { } } ``` - + - Write a program that asks the user for a string, an integer, a floating-point number, and a boolean. The program should then print the values given by the user. Example prints for the program can be seen below. - @@ -1106,22 +797,7 @@ You gave the boolean true - diff --git a/data/part-1/5-calculating.md b/data/part-1/5-calculating.md index f5aecad29..73fb56dd0 100644 --- a/data/part-1/5-calculating.md +++ b/data/part-1/5-calculating.md @@ -7,28 +7,20 @@ hidden: false - + - Learn to perform calculations with the help of variables. - + - Know how to form printable statements including both calculations (expressions) and strings. - + The basic mathematical operations are both familiar and straightforward: addition `+`, subtraction `-`, multiplication `*`, and division `/`. The precedence is also familiar: operations are performed from left to right with the parentheses taken into account. Expressions involving `*` and `/` are calculated before those involving `+` and `-`, as is customary in elementary school mathematics. - ```java int first = 2; @@ -40,20 +32,14 @@ int sum = first + second; // The sum of the values of the variables first and se System.out.println(sum); // prints 6 ``` - + ## Precedence and Parentheses - + You can affect the order of operations by using parentheses. Operations within parentheses are performed before those outside them. - ```java int calculationWithParentheses = (1 + 1) + 3 * (2 + 5); @@ -64,21 +50,11 @@ System.out.println(calculationWithoutParentheses); // prints 13 ``` - + The example above can also be divided into steps. - ```java int calculationWithParentheses = (1 + 1); @@ -92,27 +68,21 @@ calculationWithoutParentheses = calculationWithoutParentheses + 5; System.out.println(calculationWithoutParentheses); // prints 13 ``` - + - + In the exercise template, implement a program that asks the user for the number of days. After that, the program prints the number of seconds in the given number of days. - + Earlier we learned to read an integer in the following manner: - ```java Scanner scanner = new Scanner(System.in); @@ -122,17 +92,11 @@ int number = Integer.valueOf(scanner.nextLine()); System.out.println("You gave " + number); ``` - + Examples of expected output: - @@ -142,13 +106,7 @@ How many days would you like to convert to seconds? - @@ -158,13 +116,7 @@ How many days would you like to convert to seconds? - @@ -179,18 +131,7 @@ How many days would you like to convert to seconds? - @@ -205,18 +146,12 @@ The evaluation of an expression is always performed before its value is assigned - + An expression is evaluated where it occurs in the program's source code. As such, the evaluation can occur within a print statement, if the expression is used in calculating the value of the print statement's parameter. - ```java int first = 2; @@ -226,19 +161,11 @@ System.out.println(first + second); // prints 6 System.out.println(2 + second - first - second); // prints 0 ``` - + An expression does not change the value stored in a variable unless the expression's result is assigned to a variable or used as a parameter, for instance, in printing. - ```java int first = 2; @@ -253,28 +180,21 @@ first + second; - + ## Calculating and Printing - + The command `System.out.println` prints the value of a variable. The string literal to be printed, which is marked by quotation marks, can be appended with other content by using the operation `+`. - + ```java int length = 42; System.out.println("Length " + length); ``` - @@ -282,11 +202,7 @@ Length 42 - + ```java System.out.println("here is an integer --> " + 2); @@ -294,12 +210,7 @@ System.out.println(2 + " <-- here is an integer"); ``` - @@ -308,30 +219,22 @@ here is an integer --> 2 - + If one of the operands of the operation `+` is a string, the other operand will be changed into a string too during program execution. In the example below, the integer `2` is turned into the string "2", and a string has been appended to it. - + The precedence introduced earlier also apply here: - + ```java System.out.println("Four: " + (2 + 2)); System.out.println("But! Twenty-two: " + 2 + 2); ``` - @@ -340,33 +243,24 @@ But! Twenty-two: 22 - + - + - + Write a program that asks the user for two numbers. After this, the program prints the sum of the numbers given by the user. - -When you ask for multiple numbers, create a separate variable for each: - ```java Scanner scanner = new Scanner(System.in); @@ -379,19 +273,11 @@ int second = Integer.valueOf(scanner.nextLine()); // do something with the numbers ``` - -Here's how the program is expected to work: - @@ -403,15 +289,7 @@ The sum of the numbers is 11 - @@ -426,29 +304,19 @@ The sum of the numbers is 2 - + - + Write a program that asks the user for three numbers. After this the program prints the sum of the numbers given by the user. - -The program should work like this: - @@ -462,17 +330,7 @@ The sum of the numbers is 14 - @@ -491,20 +349,11 @@ The sum of the numbers is 4 - - -Applying this knowledge, we can create an expression consisting of some text and a variable, which is evaluated in connection with the printing: - ```java int x = 10; @@ -517,14 +366,9 @@ int z = 6; System.out.println("y is " + y + " and z is " + z); ``` - - @@ -535,7 +379,7 @@ y is 5 and z is 6 - + @@ -544,18 +388,10 @@ y is 5 and z is 6 Create a program that can be used to add two integers together. In the beginning, the user is asked to give two integers that are to be summed. The program then prints the formula that describes the addition of the numbers. - -Example output: - @@ -567,15 +403,7 @@ Give the second number: - @@ -590,28 +418,20 @@ Give the second number: - + - + Similar to the previous exercise, create a program that multiplies the values stored in two integer variables. - -For instance, if the entered numbers are 2 and 8, the program should print the following: - @@ -623,19 +443,11 @@ Give the second number: - + Likewise, if the entered numbers are 277 and 111, the print should be the following: - @@ -649,25 +461,22 @@ Give the second number: - - + + Once you have completed the previous exercise, try finding out the greatest possible multiplication that you can calculate. The reason behind the phenomenon you'll observe is that the value of an integer value is capped at the maximum of 231-1 (i.e. 2147483647). This is because integer variables are represented with 32 bits in the computer's memory. Variable representation is covered in more detail on the Computer Organization course. - + ## Division - + Division of integers is a slightly trickier operation. The types of the variables that are part of the division determine the type of result achieved by executing the command. If all of the variables in the division expression are integers, the resulting value is an integer as well. - + ```java int result = 3 / 2; @@ -680,16 +489,11 @@ System.out.println(result); - + The previous example prints 1: both 3 and 2 are integers, and the division of two integers always produces an integer. - + ```java int first = 3; @@ -704,21 +508,15 @@ System.out.println(result); - + The output 1 again, since first and second are (still) integers. - + If the dividend or divisor (or both!) of the division is a floating point number, the result is a floating point number as well. - ```java double whenDividendIsFloat = 3.0 / 2; @@ -736,23 +534,11 @@ System.out.println(whenDivisorIsFloat); // prints 1.5 - - -An integer can be converted into a floating point number by placing a type-casting operation `(double)` before it: - ```java int first = 3; @@ -777,18 +563,15 @@ System.out.println(result3); // prints 1.0 - + The last example produces an incorrectly rounded result, because the integer division is executed before the type casting. - + If the result of a division is assigned to an integer-type variable, the result is automatically an integer. - + ```java int integer = 3.0 / 2; @@ -801,17 +584,11 @@ System.out.println(integer); - + The next example prints "1.5"; the dividend is converted into a floating-point number by multiplying it with a floating-point number prior to executing the division. - ```java int dividend = 3; @@ -828,44 +605,36 @@ System.out.println(result); - + - + The next exercises task you with calculating the average of the entered numbers. Let's briefly review the concept of *average*. - + An average refers to the sum of numbers divided by their count. For instance, the average of the numbers 5 and 3 can be calculated with the formula (5+3)/2. Similarly, the average of the numbers 1, 2, and 4 is produced by the formula (1+2+4)/3. - + In the context of programming, there are a few things to keep in mind. Firstly, dividing by zero is typically not permitted. This implies that calculating the average of zero numbers is impossible. Secondly, if the program handles both the sum of the numbers and their total count as integers, one (or both) of the variables should be casted to a floating-point number by multiplying it by 1.0 before the division. - + - -Write a program that asks the user for two integers and prints their average. - @@ -880,26 +649,16 @@ The average is 5.0 - + - -Write a program that asks the user for three integers and prints their average. - @@ -913,17 +672,7 @@ The average is 4.333333333333333 - @@ -943,27 +692,16 @@ The average is 4.333333333333333 - + - -Write a program that asks the user for two numbers and prints their sum, difference, product, and quotient. Two examples of the execution of the program are given below. - @@ -997,49 +735,39 @@ Give the second number: - + ## Misunderstandings Related to the Value of a Variable - + When a computer executes program code, it does it one command at a time, always advancing exactly as specified by the code. When a value is assigned to a variable, the same chain of events always occurs: the value on the right-hand side of the equality sign is copied and assigned to the variable on the left-hand side (i.e., copied to the location specified by that variable). - + It's crucial for a programmer to understand that assigning a value to a variable always does the same thing. - + Here's three common misunderstandings related to assigning a value to a variable: - + * Viewing value assignment as a transfer instead of a copy operation: once `first = second` has been executed, it's often assumed that the value of the variable `second` has been moved to the value of the variable `first`, and that the variable `second` no longer holds a value, or that its value is 0, for instance. This is incorrect, as executing `first = second` means that the value in the position specified by `second` is merely copied to the place specified by the variable `first`. Hence, the variable `second` is not modified. - + * Viewing value assignment as creating a dependency instead of being a copy operation: once `first = second` has been executed, it's often assumed that any change in the value of the variable `second` is automatically also reflected in the value of the variable `first`. This is incorrect; assignment -- i.e., copying -- is a one-off event. It only occurs when the program code `first = second` is executed. - + * The third misunderstanding concerns the direction of copying: it's often thought that in executing `first = second` the value of the variable `first` is set as the value of the variable `second`. The confusion also manifests itself in situations where the programmer accidentally writes e.g. `42 = value` -- fortunately, IDEs provide support on this issue too. - + Perhaps the best way to understand a program's execution flow is through the use of pen and paper. As you're reading the program, write down the names of any new variables, while making a note of how the values of the variables in the code change line by line. Let's demonstrate the execution with the following program code: - + ```java line 1: int first = (1 + 1); @@ -1053,46 +781,11 @@ line 8: System.out.println(second); line 9: System.out.println(third); ``` - + The execution flow of the program above has been broken down below. - + @@ -1131,7 +824,7 @@ line 9: we print the value 28 - + You'll find a step-by-step visualization of the previous program below, which goes through the program line by line -- on each step, reflect on how the program ends up with the result that it prints. diff --git a/data/part-1/6-conditional-statements.md b/data/part-1/6-conditional-statements.md index 635822425..3a4c6b679 100644 --- a/data/part-1/6-conditional-statements.md +++ b/data/part-1/6-conditional-statements.md @@ -8,10 +8,10 @@ hidden: false - - - - + + + + - Become familiar with the idea of a conditional statement and know how to create a program containing optional operations through the use of conditional statements. @@ -23,20 +23,15 @@ hidden: false - + Our programs have so far been linear. In other words, the programs have executed from top to bottom without major surprises or conditional behavior. However, we usually want to add conditional logic to our programs. By this we mean functionality that's in one way or another dependent on the state of the program's variables. - + To branch the execution of a program based on user input, for example, we need to use something known as a **conditional statement**. The simplest conditional statement looks something like this. - + ```java System.out.println("Hello, world!"); @@ -52,26 +47,21 @@ This code is unavoidable! - + A conditional statement begins with the keyword `if` followed by parentheses. An expression is placed inside the parentheses, which is evaluated when the conditional statement is reached. The result of the evaluation is a boolean value. No evaluation occurred above. Instead, a boolean value was explicitly used in the conditional statement. - - + + The parentheses are followed by a block, which is defined inside opening- `{` and closing `}` curly brackets. The source code inside the block is executed if the expression inside the parentheses evaluates to _true_. - + Let's look at an example where we compare numbers in the conditional statement. - + ```java int number = 11; @@ -80,19 +70,19 @@ if (number > 10) { } ``` - + If the expression in the conditional statement evaluates to true, the execution of the program progresses to the block defined by the conditional statement. In the example above, the conditional is "if the number in the variable is greater than 10". On the other hand, if the expression evaluates to false, the execution moves on to the statement after the closing curly bracket of the current conditional statement. - + NB! An `if` -statement is not followed by a semicolon since the statement doesn't end after the conditional. - + - + Write a program that asks the user for an integer and prints the string "Speeding ticket!" if the input is greater than 120. @@ -113,43 +103,39 @@ Speeding ticket! - + ## Code Indentation and Block Statements - + A code block refers to a section enclosed by a pair of curly brackets. The source file containing the program includes the string `public class`, which is followed by the name of the program and the opening curly bracket of the block. The block ends in a closing curly bracket. In the picture below, the program block is highlighted. ![An example of a block](../img/part1.6-block-example-1.png) - + The recurring snippet `public static void main(String[] args)` in the programs begins a block, and the source code within it is executed when the program is run -- this snippet is, in fact, the starting point of all programs. We actually have two blocks in the example above, as can be seen from the image below. ![](../img/part1.6-block-example-2.png) - + Blocks define a program's structure and its bounds. A curly bracket must always have a matching pair: any code that's missing a closing (or opening) curly bracket is erroneous. - + A conditional statement also marks the start of a new code block. - + In addition to the defining program structure and functionality, block statements also have an effect on the readability of a program. Code living inside a block is indented. For example, any source code inside the block of a conditional statement is indented four spaces deeper than the `if` command that started the conditional statement. Four spaces can also be added by pressing the tab key (the key to the left of 'q'). When the block ends, i.e., when we encounter a `}` character, the indentation also ends. The `}` character is at the same level of indentation as the `if`-command that started the conditional statement. - + The example below is incorrectly indented. - + ```java if (number > 10) { @@ -157,15 +143,11 @@ number = 9; } ``` - + The example below is correctly indented. - + ```java if (number > 10) { @@ -173,14 +155,14 @@ if (number > 10) { } ``` - + - + Code in Java is indented either by four spaces or a single tab for each block. Use either spaces or tabs for indentation, not both. The indentation might break in some cases if you use both at the same time. NetBeans will help you with this if you hit the "alt + shift + f" (macOS "control + shift + f") key combination. - + From now on the our program code needs to be indented correctly in the exercises as well. If the indentation is incorrect, the development environment will not accept the solution. You will see indentation errors highlighted in yellow in the test results. @@ -191,28 +173,28 @@ In this case, we can fix the indentation by adding 6 more spaces to the beginnin - + - + The exercise template contains a program demonstrating the use of conditional statements. It is, however, incorrectly indented. - + Try to run the tests before doing anything. TMC shows the indentation errors differently compared to errors in program logic. - + When you notice how indentation errors are shown, correct them. Now would be a good time to give the automatic code formatting a try. - + ## Comparison Operators - + - `>` greater than - `>=` greater than or equal to @@ -221,17 +203,7 @@ When you notice how indentation errors are shown, correct them. Now would be a g - `==` equal to - `!=` not equal to - ```java int number = 55; @@ -253,7 +225,7 @@ The number was not equal to 0 - + Write a program that prompts the user for an integer and prints the string "Orwell" if the number is exactly 1984. @@ -274,10 +246,10 @@ Orwell - + - + Write a program that prompts the user for a year. If the user inputs a number that is smaller than 2015, then the program prints the string "Ancient history!". @@ -298,27 +270,19 @@ Ancient history! - + ## Else - + If the expression inside the parentheses of the conditional statement evaluates to false, then the execution of the code moves to the statement following the closing curly bracket of the current conditional statement. This is not always desired, and usually we want to create an alternative option for when the conditional expression evaluates to false. - + This can be done with the help of the `else` command, which is used together with the `if` command. - ```java int number = 4; @@ -336,14 +300,14 @@ Your number is five or less! - + If an `else` branch has been specified for a conditional statement, the block defined by the else branch is run in the case that the condition of the conditional statement is false. The `else`-command is placed on the same line as the closing bracket of the block defined by the `if`-command. - + - + Write a program that prompts the user for an integer and informs the user whether or not it is positive (greater than zero). @@ -365,10 +329,10 @@ The number is not positive. - + - + Write a program that prompts the user for their age and tells them whether or not they are an adult (18 years old or older). @@ -390,28 +354,15 @@ You are an adult - + ## More Conditionals: else if - + In the case of multiple conditionals, we use the `else if`-command. The command `else if` is like `else`, but with an additional condition. `else if` follows the `if`-condition, and they may be multiple. - + ```java int number = 3; @@ -433,24 +384,24 @@ The number must be three! - + Let's read out the example above: 'If the number is one, then print "The number is one", else if the number is two, then print "The given number is two", else if the number is three, then print "The number must be three!". Otherwise, print "Something else!"' - + The step-by-step visualization of the code above: - + - + Write a program that prompts the user for two integers and prints the larger of the two. If the numbers are the same, then the program informs us about this as well. - + Sample outputs: @@ -484,27 +435,15 @@ The numbers are equal! - + ## Order of Execution for Comparisons - + The comparisons are executed top down. When execution reaches a conditional statement whose condition is true, its block is executed and the comparison stops. - ```java int number = 5; @@ -526,27 +465,27 @@ The number is greater than zero. - + The example above prints the string "The number is greater than zero." even if the condition `number > 2` is true. The comparison stops at the first condition that evaluates to true. - + - + The table below describes how the grade for a particular course is determined. Write a program that gives a course grade according to the provided table. - - - - - - - - - - + + + + + + + + + + | points | grade | | ------ | ----------- | @@ -559,7 +498,7 @@ The table below describes how the grade for a particular course is determined. W | 90-100 | 5 | | > 100 | incredible! | - + Sample outputs: @@ -597,18 +536,15 @@ Grade: impossible! - + ## Conditional Statement Expression and the Boolean Variable - + The value that goes between the parentheses of the conditional statement should be of type boolean after the evaluation. `boolean` type variables are either _true_ or _false_. - + ```java boolean isItTrue = true; @@ -623,12 +559,7 @@ The value of the boolean variable is true The conditional statement can also be done as follows: - + ```java boolean isItTrue = true; @@ -643,15 +574,11 @@ Pretty wild! - + Comparison operators can also be used outside of conditionals. In those cases, the boolean value resulting from the comparison is stored in a boolean variable for later use. - + ```java int first = 1; @@ -659,19 +586,11 @@ int second = 3; boolean isGreater = first > second; ``` - + In the example above, the boolean variable `isGreater` now contains the boolean value _false_. We can extend the previous example by adding a conditional statement to it. - ```java int first = 1; @@ -685,7 +604,7 @@ if (isLessThan) { ![](../img/drawings/part1.6-boolean-variable.png) - + The code in the image above has been executed to the point where the program's variables have been created and assigned values. The variable `isLessThan` has `true` as its value. Next in the execution is the comparison `if (isLessThan)` -- the value for the variable `isLessThan` is found in its container, and the program finally prints: @@ -695,21 +614,14 @@ The code in the image above has been executed to the point where the program's v - + - + The modulo operator is a slightly less-used operator, which is, however, very handy when we want to check the divisibility of a number, for example. The symbol for the modulo operator is `%`. - + ```java int remainder = 7 % 2; @@ -720,22 +632,11 @@ System.out.println(8 % 4); // prints 0 System.out.println(1 % 2); // prints 1 ``` - -If we want to know whether the number given by the user is divisible by four hundred, we check if the remainder is zero after taking the modulo of the number and four hundred. - ```java Scanner reader = new Scanner(System.in); @@ -750,21 +651,11 @@ if (remainder == 0) { } ``` - + Since the modulo is an operation just like other calculations, it can be a part of an expression in a conditional statement. - ```java Scanner reader = new Scanner(System.in); @@ -780,10 +671,10 @@ if (number % 400 == 0) { - + - + Write a program that prompts the user for a number and informs us whether it is even or odd. @@ -803,38 +694,25 @@ Number 7 is odd. - + Hint: The remainder when dividing by 2 tells us whether the number is even or not. We get the remainder using the `%`-operator. The exercise template contains additional instructions on how to do the checking using the remainder. - + ## Conditional Statements and Comparing Strings - + Even though we can compare integers, floating point numbers, and boolean values using two equals signs (`variable1 == variable2`), we cannot compare the equality of strings using two equals signs. - -You can try this with the following program: - ```java Scanner reader = new Scanner(System.in); @@ -871,28 +749,17 @@ The strings were different! - + This has to do with the internal workings of strings as well as how variable comparison is implemented in Java. In practice, the comparison is affected by how much information a variable can hold -- strings can hold a limitless amount of characters, whereas integers, floating-point numbers, and boolean values always contain a single number or value only. Variables that always contain only one number or value can be compared using an equals sign, whereas this doesn't work for variables containing more information. We will return to this topic later in this course. - + When comparing strings we use the `equals`-command, which is related to string variables. The command works in the following way: - - ```java Scanner reader = new Scanner(System.in); @@ -923,37 +790,17 @@ Great! You read the instructions correctly. - - -The equals command is written after a string by attaching it to the string to be compared with a dot. The command is given a parameter, which is the string that the variable will be compared against. If the string variable is being directly compared with a string, then the string can be placed inside the parentheses of the equals-command within quotation marks. Otherwise, the name of the string variable that holds the string to be compared is placed inside the parentheses. - -In the example below the user is prompted for two strings. We first check to see if the provided strings are the same, after which we'll check if the value of either one of the two strings is "two strings". +The equals command is written after a string by attaching it to the string to be compared with a dot. The command is given a parameter, which is the string that the variable will be compared against. If the string variable is being directly compared with a string, then the string can be placed inside the parentheses of the equals-command within quotation marks. Otherwise, the name of the string variable that holds the string to be compared is placed inside the parentheses. - ```java Scanner reader = new Scanner(System.in); @@ -1005,10 +852,10 @@ The strings were the same! - + - + Write a program that prompts the user for a password. If the password is "Caput Draconis" the program prints "Welcome!". Otherwise, the program prints "Off with you!" @@ -1030,14 +877,14 @@ Welcome! - + - + Write a program that prompts the user for two strings. If the strings are the same, then the program prints "Same". Otherwise, it prints "Different". - + @@ -1061,40 +908,31 @@ Different - + ## Logical Operators - + The expression of a conditional statement may consist of multiple parts, in which the logical operators **and** `&&`, **or** `||`, and **not** `!` are used. - + - An expression consisting of two expressions combined using the and-operator is true, if and only if both of the combined expressions evaluate to true. - + - An expression consisting of two expressions combined using the or-operator is true if either one, or both, of the combined expressions evaluate to true. - + - Logical operators are not used for changing the boolean value from true to false, or false to true. - + In the next example we combine two individual conditions using `&&`, i.e., the and-operator. The code is used to check if the number in the variable is greater than or equal to 5 and less than or equal to 10. In other words, whether it's within the range of 5-10: - ```java System.out.println("Is the number within the range 5-10: "); @@ -1114,20 +952,11 @@ It is! :) - + In the next one we provide two conditions using `||`, i.e., the or-operator: is the number less than zero or greater than 100. The condition is fulfilled if the number fulfills either one of the two conditions: - ```java System.out.println("Is the number less than 0 or greater than 100"); @@ -1147,19 +976,11 @@ It is! :) - + In this example we flip the result of the expression `number > 4` using `!`, i.e., the not-operator. The not-operator is written in such a way that the expression to be flipped is wrapped in parentheses, and the not-operator is placed before the parentheses. - ```java int number = 7; @@ -1177,7 +998,7 @@ The number is greater than or equal to 4. - + Below is a table showing the operation of expressions containing logical operators. @@ -1189,11 +1010,11 @@ Below is a table showing the operation of expressions containing logical operato | 9 | true | true | true | false | true | | 10 | true | false | false | true | true | - + - + Write a program that prompts the user to input their age and checks whether or not it is possible (at least 0 and at most 120). Only use a single `if`-command in your program. @@ -1227,57 +1048,43 @@ Impossible! - + ## Execution Order of Conditional Statements - + Let's familiarize ourselves with the execution order of conditional statements through a classic programming exercise. - + _'Write a program that prompts the user for a number between one and one hundred, and prints that number. If the number is divisible by three, then print "Fizz" instead of the number. If the number is divisible by five, then print "Buzz" instead of the number. If the number is divisible by both three and five, then print "FizzBuzz" instead of the number.'_ - + The programmer begins solving the exercise by reading the exercise description and by writing code according to the description. The conditions for execution are presented in a given order by the description, and the initial structure for the program is formed based on that order. The structure is formed based on the following steps: - + - Write a program that prompts the user for a number and prints that number. - + - If the number is divisible by three, then print "Fizz" instead of the number. - + - If the number is divisible by five, then print "Buzz" instead of the number. - + - If the number is divisible by both three and five, then print "FizzBuzz" instead of the number. - -If-type conditions are easy to implement using `if - else if - else` -conditional statements. The code below was written based on the steps above, but it does not work correctly, which we can see from the example. - ```java Scanner reader = new Scanner(System.in); @@ -1323,53 +1130,39 @@ Fizz - + The problem with the previous approach is that **the parsing of conditional statements stops at the first condition that is true**. E.g., with the value 15 the string "Fizz" is printed, since the number is divisible by three (15 % 3 == 0). - + One approach for developing this train of thought would be to first find the **most demanding condition**, and implement it. After that, we would implement the other conditions. In the example above, the condition "if the number is divisible by both three **and** five" requires two things to happen. Now the train of thought would be: - + 1. Write a program that reads input from the user. - + 2. If the number is divisible by both three and five, then print "FizzBuzz" instead of the number. - + 3. If the number is divisible by three, then print "Fizz" instead of the number. - + 4. If the number is divisible by five, then print "Buzz" instead of the number. - + 5. Otherwise the program prints the number given by the user. - -Now the problem seems to get solved. - ```java Scanner reader = new Scanner(System.in); @@ -1408,15 +1201,15 @@ FizzBuzz - + - + A year is a leap year if it is divisible by 4. However, if the year is divisible by 100, then it is a leap year only when it is also divisible by 400. - + Write a program that reads a year from the user, and checks whether or not it is a leap year. @@ -1448,21 +1241,11 @@ The year is a leap year. - -Hint 1: The divisibility by a particular number can be checked using the modulo operator, aka `%`, in the following way. - ```java int number = 5; @@ -1483,21 +1266,12 @@ The number is not divisible by six! - - + + Hint 2: Think of the problem as a chain of if, else if, else if, ... comparisons, and start building the program from a situation in which you can be certain that the year is not a leap year. - ```java Scanner reader = new Scanner(System.in); @@ -1512,15 +1286,15 @@ if (number % 4 != 0) { - + - + [https://www.vero.fi/en/individuals/property/gifts/](https://www.vero.fi/en/individuals/property/gifts/): _A gift is a transfer of property to another person against no compensation or payment. If the total value of the gifts you receive from the same donor in the course of 3 years is €5,000 or more, you must pay gift tax._ - + When a gift is given by a close relative or a family member, the amount of gift tax is determined by the following table (source [vero.fi](https://www.vero.fi/en/individuals/property/gifts/gift-tax-calculator/#gifttaxtables)): @@ -1532,11 +1306,11 @@ When a gift is given by a close relative or a family member, the amount of gift | 200 000 -- 1 000 000 | 22 100 | 15 | | 1 000 000 -- | 142 100 | 17 | - + For example 6000€ gift implies 180€ of gift tax (100 + (6000-5000)_0.08), and 75000€ gift implies 7100€ of gift tax (4700 + (75000-55000) _ 0.12). - + Write a program that calculates the gift tax for a gift from a close relative or a family member. This is how the program should work: diff --git a/data/part-1/7-programming-in-our-society.md b/data/part-1/7-programming-in-our-society.md index 5b784a6ee..998cbfa53 100644 --- a/data/part-1/7-programming-in-our-society.md +++ b/data/part-1/7-programming-in-our-society.md @@ -5,41 +5,41 @@ title: 'Programming in our society' hidden: false --- - + When you're just starting to learn programming, it's hard to realize how dependent our society actually is on the software produced by developers. Without software, everyday things such as communication, shopping, travel, and so on would all be more complicated. Mobile phones could not work -- or there would be very few of them, and we'd have no credit cards, let alone online banking. Travel reservations and the use of personal documents online would be impossible. Electronic health services such as e-prescriptions and the seamless transfer of patient data between wards and hospitals would be the stuff of dreams. There'd also be no Wikipedia or search engines, so any time you'd like to know something, you'd open a dictionary or an encyclopedia. - + As services become based on software, their inherent complexity becomes hidden from us. For instance, when you travel by air and check-in using an online form, the sending of the form sets off a series of communication between dozens of different systems. Information about your name, personal information, state of your passport, any possible visas, the state of your flight, and your previous flights are all checked. Your seat reservations pass through a seat-reservation management system, and your airline customer-loyalty status is reviewed. The amount of fuel the airplane needs to for refueling will also need to be updated, and the list goes on. All of this happens as a result of you clicking the send button on the online form. - + Software professionals are the architects of these kinds of digital services. It's the responsibility of those of us who study computer science and engineering to implement these systems in a way that ensures that they function as well as they can for their intended users -- and also for those not familiar with similar systems. At the same time, architects of digital services learn a lot about different business domains and the practicalities of everyday life. For instance, you already know more about gift taxation (the last part of the previous section) than most Finns do - someone has also implemented a gift-tax calculator for the tax service. - + The end-users of a given system are seldom aware of those who produced it. For example, few have heard of [Margaret Hamilton]() who, with her team, wrote the program that took man to the moon. - + ![Margaret Hamilton in action](./margeret-action.jpg) - + Programming can be considered the artisanship of our time, and the ever-increasing demand for understanding software and digital systems is evident everywhere. Fundamentals of programming are already taught in elementary school; and various fields, including modern science, make use of software and its latest innovations in data analysis. Meteorologists, physicists and chemists also use software and many write code at work. Pedagogy and teacher training are also increasingly benefitting from the possibilities created by digitalization. It's now more difficult to list professions that are not impacted by software and digitalization than those that are. - + You've now taken your first steps in the world of programming. During the course you will learn to write programs and understand how they work - you will categorize a program's sub-entities into small parts, and present the concepts that appear in the program as pieces working together in harmony. After the course, you may also begin to think about public services from a programmer's perspective and consider their functioning (or lack of it) in terms of the opportunities and limitations of software. - + After this course, simple instructions, such as "_Buy two cartons of milk. If the shop has oranges, buy four of them._", will be viewed in a different way. Although this message may be clear to a human, a computer might end up buying four cartons of milk. - + Great to have you on this journey! diff --git a/data/part-10/1-handling-collections-as-streams.md b/data/part-10/1-handling-collections-as-streams.md index 076593d3e..849eb00fc 100644 --- a/data/part-10/1-handling-collections-as-streams.md +++ b/data/part-10/1-handling-collections-as-streams.md @@ -5,25 +5,17 @@ hidden: false --- - + - + - You can handle collections using streams - You know what a lambda-statement means - You know the most common stream methods and are able to categorize them into intermediate and terminal operations. - Let's get to know collections, such as lists, as streams of values. Stream is a way of going through a collection of data such that the programmer determines the operation to be performed on each value. No record is kept of the index or the variable being processed at any given time. With streams, the programmer defines a sequence of events that is executed for each value in a collection. An event chain may include dumping some of the values, converting values ​​from one form to another, or calculations. A stream does not change the values ​​in the original data collection, but merely processes them. If you want to retain the transformations, they need to be compiled into another data collection. @@ -32,37 +24,7 @@ Let's begin to understand the usage of streams through a concrete example. Consi *Write a program that reads input from a user and prints statistics about those inputs. When the user enters the string "end", the reading is stopped. Other inputs are numbers in string format. When you stop reading inputs, the program prints the number of positive integers divisible by three, and the average of all values.* - ```java // We initialise the scanner and the list into which the input is read Scanner scanner = new Scanner(System.in); @@ -96,16 +58,10 @@ System.out.println("Average number: " + average); ``` - + Let's take a closer look at the part of the program above where the inputs are dealt as streams. - + ```java // counting the number of values divisible by three long numbersDivisibleByThree = inputs.stream() @@ -115,23 +71,14 @@ long numbersDivisibleByThree = inputs.stream() ``` - - A stream can be formed from any object that implements the Collection interface (e.g., ArrayList, HashSet, HashMap, ...) with the `stream()` method. The string values ​​are then converted ("mapped") to integer form using the stream's `mapToInt(value -> conversion)` method. The conversion is implemented by the `valueOf` method of the `Integer` class, which we've used in the past. We then use the `filter (value -> filter condition)` method to filter out only those numbers that are divisible by three for further processing. Finally, we call the stream's `count()` method, which counts the number of elements in the stream and returns it as a `long` type variable. Let's now look at the part of the program that calculates the average of the list elements. - + ```java // working out the average double average = inputs.stream() @@ -140,69 +87,12 @@ double average = inputs.stream() .getAsDouble(); ``` - Calculating the average is possible from a stream that has the `mapToInt` method called on it. A stream of integers has an `average` method that returns an OptionalDouble-type object. The object has `getAsDouble()` method that returns the average of the list values as a type `double` varaible. A brief summary of the stream methods we've encountered so far. - @@ -269,10 +159,10 @@ A brief summary of the stream methods we've encountered so far. - + Implement a program, which reads user input. If the user input is "end", the program stops reading input. The rest of the input is numbers. When the user input is "end", the program prints the average of all of the numbers. - + Implement calculating the average using a stream! @@ -304,13 +194,13 @@ average of the numbers: 0.6666666666666666 - + Implement a program, which reads user input. If the user input is "end", program stops reading input. The rest of the input is numbers. - + Then user is asked if the program should print the average of all the positive numbers, or the average of all the negative numbers (n or p). If the user selects "n", the average of all the negative numbers is printed. Otherwise the average of all the positive numbers is printed. - + Use streams to calculate the average and filter the numbers! @@ -345,14 +235,10 @@ Average of the positive numbers: 1.5 - -## Lambda Expressions - Stream values ​​are handled by methods related to streams. Methods that handle values ​​get a function as a parameter that determines what is done with each element. What the function does is specific to the method in question. For instance, the `filter` method used for filtering elements is provided a function which returns the a boolean `true` or `false`, depending on whether to keep the value in the stream or not. The `mapToInt` method used for transformation is, on the other hand, provided a function which converts the value to an integer, and so on. Why are the functions written in the form `value -> value > 5`? @@ -360,19 +246,7 @@ Why are the functions written in the form `value -> value > 5`? The expression above, i.e., a *lambda expression*, is shorthand provided by Java for anonymous methods that do not have an "owner", i.e., they are not part of a class or an interface. The function contains both the parameter definition and the function body. The same function can be written in several different ways. See below. - ```java // original *stream*.filter(value -> value > 5).*furtherAction* @@ -388,18 +262,12 @@ The expression above, i.e., a *lambda expression*, is shorthand provided by Java ``` - + The same can be written explicitly so that a static method is defined in the program, which gets used within the function passed to the stream as a parameter. - + ```java public class Screeners { public static boolean greaterThanFive(int value) { @@ -408,13 +276,7 @@ public class Screeners { } ``` - ```java // original *stream*.filter(value -> value > 5).*furtherAction* @@ -423,52 +285,21 @@ public class Screeners { *stream*.filter(value -> Screeners.greaterThanFive(value)).*furtherAction* ``` - + The function can also be passed directly as a parameter. The syntax found below `Screeners::greaterThanFive` is saying: "use the static `greaterThanFive` method that's in the `Screeners` class". - + ```java // is the same as *stream*.filter(Screeners::greaterThanFive).*furtherAction* ``` - Functions thats handle stream elements ​​cannot change values ​​of variables outside of the function. This has to do with how static methods behave - during a method call, there is no access to any variables outside of the method. With functions, the values ​​of variables outside the function can be read, assuming that those values of those variables do not change in the program. The program below demonstrates the situation in which a function attempts to make use of a variable outside the function. It doesn't work. - ```java // initializing a scanner and a list to which values are read Scanner scanner = new Scanner(System.in); @@ -497,38 +328,24 @@ long numbersDivisibleByThree = inputs.stream() ``` - + ## Stream Methods - Stream methods can be roughly divided into two categories: (1) intermediate operations intended for processing elements ​​and (2) terminal operations that end the processing of elements. Both of the `filter` and `mapToInt` methods shown in the previous example are intermediate operations. Intermediate operations return a value that can be further processed - you could, in practice, have an infinite number of intermediate operations chained sequentially (& separated by a dot). On the other hand, the `average` method seen in the previous example is a terminal operation. A terminal operation returns a value to be processed, which is formed from, for instance, stream elements. The figure below illustrates how a stream works. The starting point (1) is a list with values. When the `stream()` method is called on a list, (2) a stream of list values ​​is created. The values ​​are then dealt with individually. The stream values ​​can be (3) filtered by the `filter` method, which removes values ​​that fail to meet the condition from the stream. The stream's `map` method (4) can be used to map values ​​in a stream from one form to another. The `collect` method (5) collects the values ​​in a stream into a collection provided to it, such as a list. - + The written explanation above on how a stream works as an image.   - + Underneath is a program of the example depicted in the image above. In this example stream, a new ArrayList list is created to which values ​​are added. This is done in the last line `.collect(Collectors.toCollection(ArrayList::new));`. - ```java List list = new ArrayList<>(); list.add(3); @@ -546,9 +363,7 @@ ArrayList values = list.stream() - In the exercise template, implement the class method `public static List positive(List numbers)`, which receives an ArrayList of integers, and returns the positive integers from the list. @@ -557,27 +372,16 @@ Implement the method using stream! For collecting the numbers try the command `C - + ### Terminal Operations - Let's take a look at four terminal operations: the `count` method for counting the number of values on a list ​​using the, the `forEach` method for going a through list values, the `collect` method for gathering the list values ​​into a data structure, and the `reduce` method for combining the list items. The `count` method informs us of the number of values in the stream as a `long`-type variable. - ```java List values = new ArrayList<>(); values.add(3); @@ -589,33 +393,18 @@ values.add(8); System.out.println("Values: " + values.stream().count()); ``` - Values: 5 - + The `forEach` method defines what is done to each list value and terminated the stream processing. In the example below, we first create a list of numbers, after which we only print the numbers that are divisible by two. - ```java List values = new ArrayList<>(); values.add(3); @@ -638,24 +427,10 @@ values.stream() - -You can use the `collect` method to collect stream values into another collection. The example below creates a new list containing only positive values. The `collect` method is given as a parameter to the Collectors object to which the stream values ​​are collected - for example, calling `Collectors.toCollection(ArrayList::new)` creates a new ArrayList object that holds the collected values. - ```java List values = new ArrayList<>(); values.add(3); @@ -686,22 +461,10 @@ positiiviset.stream() - -The exercise template includes a template for the method `public static ArrayList divisible(ArrayList numbers)`. Implement a functionality there that gathers numbers divisible by two, three or five from the list it receives as a parameter, and returns them as a new list. The list received as a parameter must not be altered. - ```java public static void main(String[] args) { @@ -730,25 +493,13 @@ public static void main(String[] args) { - The `reduce` method is useful when you want to combine stream elements to some other form. The parameters accepted by the method have the following format: `reduce(*initialState*, (*previous*, *object*) -> *actions on the object*)`. As an example, you can calculate the sum of an integer list using the reduce method as follows. - + ```java ArrayList values = new ArrayList<>(); values.add(7); @@ -767,20 +518,10 @@ System.out.println(sum); - + In the same way, we can form a combined row-separated string from a list of strings. - + ```java ArrayList words = new ArrayList<>(); words.add("First"); @@ -793,14 +534,7 @@ String combined = words.stream() System.out.println(combined); ``` - First @@ -811,41 +545,15 @@ Fourth - + ### Intermediate Operations - Intermediate stream operations are methods that return a stream. Since the value returned is a stream, we can call intermediate operations sequentially. Typical intermediate operations include converting a value from one form to another using `map` and its more specific form `mapToInt` used for converting a stream to an integer stream. Other ones include filtering values with `filter`, identifying unique values with `distinct`, and arranging values with `sorted` (if possible). Let's look at these methods in action through a few problems. Say we have the following Person class. - ```java public class Person { private String firstName; @@ -872,10 +580,7 @@ public class Person { } ``` - *Problem 1: You'll receive a list of persons. Print the number of persons born before the year 1970.* @@ -892,24 +597,16 @@ long count = persons.stream() System.out.println("Count: " + count); ``` - + *Problem 2: You'll receive a list of persons. How many persons' first names start with the letter "A"?* - + Let's use the `filter`-method to narrow down the persons to those whose first name starts with the letter "A". Afterwards, we'll calculate the number of persons with the `count`-method. - ```java // suppose we have a list of persons @@ -921,26 +618,16 @@ long count = persons.stream() System.out.println("Count: " + count); ``` - + *Problem 3: You'll receive a list of persons. Print the number of unique first names in alphabetical order* - -First we'll use the `map` method to change a stream containing person objects into a stream containing first names. After that we'll call the `distinct`-method, that returns a stream that only contains unique values. Next, we call the method `sorted`, which sorts the strings. Finally, we call the method `forEach`, that is used to print the strings. +First we'll use the `map` method to change a stream containing person objects into a stream containing first names. After that we'll call the `distinct`-method, that returns a stream that only contains unique values. Next, we call the method `sorted`, which sorts the strings. Finally, we call the method `forEach`, that is used to print the strings. - ```java // suppose we have a list of persons @@ -953,31 +640,21 @@ persons.stream() .forEach(name -> System.out.println(name)); ``` - + The `distinct`-method described above uses the `equals`-method that is in all objects for comparing whether two strings are the same. The `sorted`-method on the other hand is able to sort objects that contain some kind of order -- examples of this kind of objects are for example numbers and strings. - - - + -Write a program that reads the user's input as strings. When the user inputs an empty string (only presses enter), the input reading will be stopped and the program will print all the user inputs. - @@ -994,11 +671,11 @@ war is peace: 1984 - + - + Write a program that reads user input. When the user gives a negative number as an input, the input reading will be stopped. After this, print all the numbers the user has given as input that are between 1 and 5. @@ -1019,33 +696,16 @@ Write a program that reads user input. When the user gives a negative number as - - - - -The exercise template contains a sketch of a program that reads user-provided information about people. Expand the program so that it will print all the unique last names of the user-provided people in alphabetical order. + - @@ -1080,36 +740,14 @@ Turing - -## Objects and Stream - - -Handling objects using stream methods is natural. Each stream method that deals with the stream's values ​​also enables you to call methods related to values. Let's look at an example where we have books with authors. The classes `Person` and `Book` are provided below. +## Objects and Stream - ```java public class Person { private String name; @@ -1134,31 +772,7 @@ public class Person { } ``` - ```java public class Book { private Person author; @@ -1185,28 +799,12 @@ public class Book { } ``` - - -Say we have a list of books. Calculating the average of the authors' birth years can be done using stream methods in a way that feels natural. First, we convert the stream of books to a stream of persons, and then we convert the stream of person to a stream of birth years. Finally, we ask the (integer) stream for an average. - ```java // let's assume that we have a list of books // List books = new ArrayList<>(); @@ -1225,19 +823,11 @@ System.out.println("Average of the authors' birth years: " + average); // ... ``` - + Similarly, the names of the authors of books with the word "Potter" in their titles are outputted the following way. - ```java // let's assume that we have a list of books // List books = new ArrayList<>(); @@ -1248,18 +838,10 @@ books.stream() .forEach(author -> System.out.println(author)); ``` - + Streams can also be used to build more complex string representations. In the example below, we print "Author Name: Book" pairs arranged in alphabetical order. - ```java // let's assume that we have a list of books at our disposal // ArrayList books = new ArrayList<>(); @@ -1271,38 +853,26 @@ books.stream() ``` - + - + The exercise template includes the probably familiar project "Cargo hold". However, in this exercise you need to make the for-loop using methods to use streams. The final product should not have any `while (...)` or `for (...)`-loops. - + ## Files and Streams -

Streams are also very handy in handling files. The file is read in stream form using Java's ready-made Files class. The `lines` method in the files class allows you to create an input stream from a file, allowing you to process the rows one by one. The `lines` method gets a path as its parameter, which is created using the `get` method in the Paths class. The `get` method is provided a string describing the file path.

The example below reads all the lines in "file.txt" and adds them to the list. - ```java List rows = new ArrayList<>(); @@ -1315,32 +885,28 @@ try { // do something with the read lines ``` - -If the file is both found and read successfully, the lines of the "file.txt" file will be in the `rows` list variable at the end of the program. However, if a file cannot be found or read, an error message will be displayed. Below is one possibility: - Error: file.txt (No such file or directory) - + - + Implement the static method `public static List read(String file)`, which reads the file with the filename of the parameter and returns the lines as a string list. - + Stream methods make the reading of files that are of predefined format relatively straightforward. Let's look at a scenario where a file contains some personal information. Details of each person is on their own line: first the person's name, then a semicolon, and finally the person's birth year. The file format is as follows: @@ -1362,29 +928,10 @@ Sauli Väinämö Niinistö; 1948 - + Let's assume that the file is named `presidents.txt`. Reading the details of the persons happens as follows: - ```java List presidents = new ArrayList<>(); try { @@ -1405,21 +952,19 @@ try { // now the presidents are on the list as person objects ``` - + - + Add the method `public static List readBooks(String file)` for the class `BooksFromFile`. It should read the file given as the parameter and forms book data from it. - + The exercise template contains the class `Book`, which is used for describing a book. You should presume that the book files are in the following format: - +
 
@@ -1427,7 +972,7 @@ name,publishing year,page count,author
 
 
- + The name and the author of the book are processed as strings, and the publishing year and the page count are processed as integers. Example of contents of a book file: diff --git a/data/part-10/2-interface-comparable.md b/data/part-10/2-interface-comparable.md index 34b938c4c..b7e498201 100644 --- a/data/part-10/2-interface-comparable.md +++ b/data/part-10/2-interface-comparable.md @@ -7,9 +7,7 @@ hidden: false - + - You're aware of Java's Comparable class and now how to implement it in your own classes - You know how to use Java's tools for sorting lists and stream elements. @@ -18,52 +16,14 @@ hidden: false -

In the previous section, we looked at interfaces in more general terms - let's now familiarize ourselves with one of Java's ready-made interfaces. The Comparable interface defines the `compareTo` method used to compare objects. If a class implements the Comparable interface, objects created from that class can be sorted using Java's sorting algorithms.

The `compareTo` method required by the Comparable interface receives as its parameter the object to which the "this" object is compared. If the "this" object comes before the object received as a parameter in terms of sorting order, the method should return a negative number. If, on the other hand, the "this" object comes after the object received as a parameter, the method should return a positive number. Otherwise, 0 is returned. The sorting resulting from the `compareTo` method is called *natural ordering*. Let's take a look at this with the help of a Member class that represents a child or youth who belongs to a club. Each club member has a name and height. The club members should go to eat in order of height, so the Member class should implement the `Comparable` interface. The Comparable interface takes as its type parameter the class that is the subject of the comparison. We'll use the same `Member` class as the type parameter. - ```java public class Member implements Comparable { private String name; @@ -100,22 +60,13 @@ public class Member implements Comparable { } ``` - The `compareTo` method required by the interface returns an integer that informs us of the order of comparison. As returning a negative number from `compareTo()` is enough if the `this` object is smaller than the parameter object, and returning zero is sufficient when the lengths are the same, the `compareTo` method described above can also be implemented as follows. - + ```java @Override @@ -124,11 +75,7 @@ public int compareTo(Member member) { } ``` - Since the Member class implements the Comparable interface, it is possible to sort the list by using the `sorted` method. In fact, objects of any class that implement the `Comparable` interface can be sorted using the `sorted` method. Be aware, however, that a stream does not sort the original list - *only the items in the stream are sorted*. @@ -137,22 +84,7 @@ If a programmer wants to organize the original list, the `sort` method of the `C Sorting club members is straightforward now. - ```java List member = new ArrayList<>(); member.add(new Member("mikael", 182)); @@ -193,86 +125,52 @@ matti (187) - + - + You are provided with the class Human. A human has a name and wage information. Implement the interface `Comparable` in a way, such that the overridden `compareTo` method sorts the humans according to wage from largest to smallest salary. - + - + The exercise template includes the class `Student`, which has a name. Implement the `Comparable` interface in the Student class in a way, such that the `compareTo` method sorts the students in alphabetical order based on their names. - + The name of the `Student` is a String, which implements `Comparable` itself. You may use its `compareTo` method when implementing the method for the `Student` class. Note that `String.compareTo()` also treats letters according to their size, while the `compareToIgnoreCase` method of the same class ignores the capitalization completely. You may either of these methods in the exercise. - + - A class can implement multiple interfaces. Multiple interfaces are implemented by separating the implemented interfaces with commas (`public class ... implements *FirstInterface*, *SecondInterface* ...`). Implementing multiple interfaces requires us to implement all of the methods for which implementations are required by the interfaces. Say we have the following `Identifiable` interface. - + ```java public interface Identifiable { String getId(); } ``` - -We want to create a Person who is both identifiable and sortable. This can be achieved by implementing both of the interfaces. An example is provided below. - - ```java public class Person implements Identifiable, Comparable { private String name; @@ -306,34 +204,15 @@ public class Person implements Identifiable, Comparable { - -## Sorting Method as a Lambda Expression - -Let's assume that we have the following Person class for use. +## Sorting Method as a Lambda Expression +Let's assume that we have the following Person class for use. - ```java public class Person { @@ -356,16 +235,10 @@ public class Person { ``` - + And person objects on a list. - + ```java ArrayList person = new ArrayList<>(); person.add(new Person("Ada Lovelace", 1815)); @@ -374,35 +247,13 @@ person.add(new Person("Grace Hopper", 1906)); person.add(new Person("Mary Coombs", 1929)); ``` - We want to sort the list without having to implement the `Comparable` interface.

Both the `sort` method of the `Collections` class and the stream's `sorted` method accept a lambda expression as a parameter that defines the sorting criteria. More specifically, both methods can be provided with an object that implements the Comparator interface, which defines the desired order - the lambda expression is used to create this object.

- ```java ArrayList persons = new ArrayList<>(); persons.add(new Person("Ada Lovelace", 1815)); @@ -444,22 +295,10 @@ Mary Coombs - -When comparing strings, we can use the `compareTo` method provided by the String class. The method returns an integer that describes the order of both the string given to it as a parameter and the string that's calling it. - ```java @@ -484,10 +323,10 @@ Mary Coombs - + - + This exercise uses open data about literacy levels, provided by UNESCO. The data includes statistics of estimated or reported levels of literacy for various countries for the past two years. File `literacy.csv`, included with the exercise template, includes the literacy estimates for women and men over 15 years of age. Each line in the file `literacy.csv` is as follows: @@ -502,7 +341,7 @@ Adult literacy rate, population 15+ years, male (%),Angola,2014,82.15105 - + Create a program that first reads the file `literacy.csv` and then prints the contents from the lowest to the highest ranked on the literacy rate. The output must be exactly as in the following example. The example shows the first five of the expected rows. @@ -516,23 +355,14 @@ Central African Republic (2015), female, 24.35549 - + This exercise is worth two points. - + Tip! Here's how to split a string into an array by each comma. - ```java String string = "Adult literacy rate, population 15+ years, female (%),Zimbabwe,2015,85.28513"; @@ -548,37 +378,13 @@ pieces[1] = pieces[1].trim(); - -## Sorting By Multiple Criteria - - -

We sometimes want to sort items based on a number of things. Let's look at an example in which films are listed in order of their name and year of release. We'll make use of Java's Comparator class here, which offers us the functionality required for sorting. Let's assume that we have the class `Film` at our disposal.

- ```java public class Film { @@ -604,33 +410,12 @@ public class Film { } ``` - The `Comparator` class provides two essential methods for sorting: `comparing` and `thenComparing`. The `comparing` method is passed the value to be compared first, and the `thenComparing` method is the next value to be compared. The `thenComparing` method can be used many times by chaining methods, which allows virtually unlimited values ​​to be used for comparison. When we sort objects, the `comparing` and `thenComparing` methods are given a reference to the object's type - the method is called in order and the values ​​returned by the method are compared. The method reference is given as `Class::method`. In the example below, we print movies by year and title in order. - ```java List films = new ArrayList<>(); films.add(new Film("A", 2000)); @@ -668,52 +453,28 @@ C (2001) - - - - - -Write a program that reads user input for books and their age recommendations. - + -The program asks for new books until the user gives an empty String (only presses enter). After this, the program will print the number of books, their names, and their recommended ages. - +Write a program that reads user input for books and their age recommendations. -

Reading and printing the books

- -Implement the reading and printing the books first, the ordering of them doesn't matter yet. +The program asks for new books until the user gives an empty String (only presses enter). After this, the program will print the number of books, their names, and their recommended ages. - @@ -742,41 +503,17 @@ Litmanen 10 (recommended for 10 year-olds or older) - - -

Ordering books based on their age recommendation

- - - - -Expand your program so, that the books are sorted based on their age recommendations when they are printed. If two (or more) books share the same age recommendations the order between them does not matter. - - @@ -805,40 +542,16 @@ The Snowy Forest Calls (recommended for 12 year-olds or older) - - -

Ordering books based on their age recommendation and name

- - -Expand your program, so that it sorts the books with the same age recommendation based on their name alphabetically. - - diff --git a/data/part-10/3-other-useful-techniques.md b/data/part-10/3-other-useful-techniques.md index 62aea0924..689d8a0a3 100644 --- a/data/part-10/3-other-useful-techniques.md +++ b/data/part-10/3-other-useful-techniques.md @@ -7,11 +7,7 @@ hidden: false - + - You understand the traditional for-loop. - You understand the issues related to string concatenation and know how to avoid them with the StringBuilder class. - You understand regular expressions and can write your own ones. @@ -20,22 +16,16 @@ hidden: false - + We'll now take a look at some useful programming techniques and classes. ## StringBuilder - + Let's look at the following program. - + ```java String numbers = ""; for (int i = 1; i < 5; i++) { @@ -50,28 +40,13 @@ System.out.println(numbers); - The program structure is straightforward. A string containing the number 1234 is created, and the string is then outputted. The program works, but there is a small problem invisible to the user. Calling `numbers + i` creates a *new* string. Let's inspect the program line-by-line with the repetition block unpacked. - ```java String numbers = ""; // creating a new string: "" int i = 1; @@ -87,22 +62,13 @@ i++; System.out.println(numbers); // printing the string ``` - In the previous example, five strings are created in total. Let's look at the same program where a new line is added after each number. - + ```java String numbers = ""; @@ -121,27 +87,10 @@ System.out.println(numbers); - + Each `+`-operation forms a new string. On the line `numbers + i + "\n";` a string is first created, after which another string is created joining a new line onto the previous string. Let's write this out as well. - ```java String numbers = ""; // creating a new string: "" int i = 1; @@ -161,13 +110,7 @@ i++; System.out.println(numbers); // outputting the string ``` - In the previous example, a total of nine strings is created. @@ -177,13 +120,7 @@ Java's ready-made StringBuilder class provides a way to concatenate strings with In the example below, only one string is created. - + ```java StringBuilder numbers = new StringBuilder(); @@ -193,7 +130,7 @@ for (int i = 1; i < 5; i++) { System.out.println(numbers.toString()); ``` - + Using StringBuilder is more efficient than creating strings with the `+` operator. @@ -201,16 +138,10 @@ Using StringBuilder is more efficient than creating strings with the `+` operato - -## Regular Expressions - - A regular expression defines a set of strings in a compact form. Regular expressions are used, among other things, to verify the correctness of strings. We can assess whether or not a string is in the desired form by using a regular expression that defines the strings considered correct. @@ -221,16 +152,7 @@ You could verify the format of the student number, for instance, by going throug Checking correctness with the help of regular expressions is done by first defining a suitable regular expression. We can then use the `matches` method of the `String` class, which checks whether the string matches the regular expression given as a parameter. For the student number, the appropriate regular expression is `"01[0-9]{7}"`, and checking the student number entered by a user is done as follows: - ```java System.out.print("Provide a student number: "); String number = scanner.nextLine(); @@ -242,26 +164,18 @@ if (number.matches("01[0-9]{7}")) { } ``` - + Let's go through the most common characters used in regular expressions. - + ### Alternation (Vertical Line) - + A vertical line indicates that parts of a regular expressions are optional. For example, `00|111|0000` defines the strings `00`, `111` and `0000`. The `respond` method returns` true` if the string matches any one of the specified group of alternatives. - ```java String string = "00"; @@ -272,29 +186,17 @@ if (string.matches("00|111|0000")) { } ``` - The string contained one of the three alternatives - + The regular expression `00|111|0000` demands that the string is exactly it specifies it to be - there is no *"contains"* functionality. - ```java String string = "1111"; @@ -305,11 +207,7 @@ if (string.matches("00|111|0000")) { } ``` - The string contained none of the three alternatives @@ -317,48 +215,26 @@ The string contained none of the three alternatives - -### Affecting Part of a String (Parentheses) - You can use parentheses to determine which part of a regular expression is affected by the rules inside the parentheses. Say we want to allow the strings `00000` and `00001`. We can do that by placing a vertical bar in between them this way `00000|00001`. Parentheses allow us to limit the option to a specific part of the string. The expression `0000(0|1)` specifies the strings `00000` and `00001`. Similarly, the regular expression `car(|s|)` defines the singular (car) and plural (cars) forms of the word car. - - + ### Quantifiers - What is often desired is that a particular sub-string is repeated in a string. The following expressions are available in regular expressions: - The quantifier `*` repeats 0 ... times, for example; - ```java String string = "trolololololo"; @@ -368,12 +244,7 @@ if (string.matches("trolo(lo)*")) { System.out.println("Incorrect form."); } ``` - @@ -381,18 +252,10 @@ Correct form. - + - The quantifier `+` repeats 1 ... times, for example; - ```java String string = "trolololololo"; @@ -403,26 +266,14 @@ if (string.matches("tro(lo)+")) { } ``` - Correct form. - ```java String string = "nananananananana Batmaan!"; @@ -433,11 +284,7 @@ if (string.matches("(na)+ Batmaan!")) { } ``` - Correct form. @@ -445,18 +292,10 @@ Correct form. - + - The quantifier `?` repeats 0 or 1 times, for example: - ```java String string = "You have to accidentally the whole meme"; @@ -467,31 +306,18 @@ if (string.matches("You have to accidentally (delete )?the whole meme")) { } ``` - Correct form. - + - The quantifier `{a}` repeats `a` times, for example: - ```java String string = "1010"; @@ -502,11 +328,7 @@ if (string.matches("(10){2}")) { } ``` - Correct form. @@ -516,15 +338,7 @@ Correct form. - The quantifier `{a,b}` repeats `a` ... `b` times, for example: - ```java String string = "1"; @@ -535,11 +349,7 @@ if (string.matches("1{2,4}")) { } ``` - Incorrect form. @@ -547,18 +357,10 @@ Incorrect form. - + - The quantifier `{a,}` repeats `a` ... times, for example: - ```java String string = "11111"; @@ -568,12 +370,7 @@ if (string.matches("1{2,}")) { System.out.println("Incorrect form."); } ``` - @@ -581,14 +378,14 @@ Correct form. - + You can use more than one quantifier in a single regular expression. For example, the regular expression `5{3}(1|0)*5{3}` defines strings that begin and end with three fives. An unlimited number of ones and zeros are allowed in between. - + ### Character Classes (Square Brackets) - + A character class can be used to specify a set of characters in a compact way. Characters are enclosed in square brackets, and a range is indicated with a dash. For example, `[145]` means `(1|4|5)` and `[2-36-9]` means `(2|3|6|7|8|9)`. Similarly, the entry `[a-c]*` defines a regular expression that requires the string to contain only `a`, `b` and `c`. @@ -597,29 +394,24 @@ A character class can be used to specify a set of characters in a compact way. C - + Let's practice using regular expressions a little. The methods in this exercise should be created in the class `Checker`. - +

Day of week

- + Use regular expressions to create the method `public boolean isDayOfWeek(String string)`, which returns `true` if the parameter string is an abbreviation of a day of the week (mon, tue, wed, thu, fri, sat, sun) - -Example outputs of a program that uses the method: - @@ -636,26 +428,21 @@ The form is incorrect. - +

Vowel check

**NB**. For simplicity's sake, in this exercises **the letters that are considered vowels are: a, e, i, o, and u**. - + Create the method `public boolean allVowels(String string)` that uses a regular expression to check whether all the characters in the parameter string are vowels. - -Example outputs of a program that uses the method: - @@ -664,12 +451,7 @@ The form is correct. - @@ -679,30 +461,25 @@ The form is incorrect. - +

Time of day

- + Regular expressions come in handy in certain situations. In some cases the expressions become too complex, and the "correctness" of the string is best checked with some other style. Or it could be beneficial to use regular expressions for only some part of the check. - + Create the method `public boolean timeOfDay(String string)`. It should use a regular expression to check whether the parameter string expresses a time of day in the form `hh:mm:ss` (hours, minutes, and seconds each always take up two spaces). **NB. In this exercise we use the 24-hour clock**. So the acceptable values are between 00:00:00 and 23:59:59. - -Example outputs of a program that uses the method: - @@ -711,12 +488,7 @@ The form is correct. - @@ -725,12 +497,7 @@ The form is incorrect. - @@ -742,65 +509,33 @@ The form is incorrect.
- + Almost all programming languages ​​support regular expressions nowadays. The theory of regular expressions is one of the topics considered in the course Computational Models (TKT-20005). You can find more regular expressions by googling *regular expressions java*, for instance. - + ## Enumerated Type - Enum - + If we know the possible values ​​of a variable in advance, we can use a class of type `enum`, i.e., *enumerated type* to represent the values. Enumerated types are their own type in addition to being normal classes and interfaces. An enumerated type is defined by the keyword `enum`. For example, the following `Suit` enum class defines four constant values: `Diamond`, `SPADE`, `CLUB` and `HEART`. - + ```java public enum Suit { DIAMOND, SPADE, CLUB, HEART } ``` - In its simplest form, `enum` lists the constant values ​​it declares, separated by a comma. Enum types, i.e., constants, are conventionally written with capital letters. An Enum is (usually) written in its own file, much like a class or interface. In NetBeans, you can create an Enum by selecting *new/other/java/java enum* from project. The following is a `Card` class where the suit is represented by an enum: - ```java public class Card { @@ -827,20 +562,10 @@ public class Card { } ``` - -The card is used in the following way: - ```java Card first = new Card(10, Suit.HEART); @@ -853,15 +578,10 @@ if (first.getSuit() == Suit.SPADE) { } ``` - -The output: - HEARTS 10 @@ -869,20 +589,15 @@ is not a spade - + We see that the Enum values are outputted nicely! Oracle has a site related to the `enum` data type at http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html . - - - In the example above, two enums were compared with equal signs. How does this work? Each enum field gets a unique number code, and they can be compared using the equals sign. Just as other classes in Java, these values also inherit the Object class and its equals method. The equals method compares this numeric identifier in enum types too. @@ -896,10 +611,7 @@ public enum Suits { } ``` - + ```java System.out.println(Suit.DIAMOND.ordinal()); System.out.println(Suit.HEART.ordinal()); @@ -915,34 +627,15 @@ System.out.println(Suit.HEART.ordinal()); - + ### Object References In Enums - Enumerated types may contain object reference variables. The values ​​of the reference variables should be set in an internal constructor of the class defining the enumerated type, i.e., within a constructor having a `private` access modifier. Enum type classes cannot have a `public` constructor. In the following example, we have an enum `Color` that contains the constants ​​RED, GREEN and BLUE. The constants have been declared with object reference variables referring to their color codes: - ```java public enum Color { // constructor parameters are defined as @@ -963,12 +656,10 @@ public enum Color { } ``` - + The enum `Color` can be used like so: - + ```java System.out.println(Color.GREEN.getCode()); ``` @@ -979,30 +670,12 @@ System.out.println(Color.GREEN.getCode()); ## Iterator - - -Let's look at the following `Hand` class that represents the set of cards that a player is holding: - ```java public class Hand { private List cards; @@ -1023,22 +696,12 @@ public class Hand { } ``` - The `print` method of the class prints each card in the current hand. ArrayList and other "object containers" that implement the *Collection* interface implement the *Iterable* interface, and they can also be iterated over with the help of an *iterator* - an object specifically designed to go through a particular type of object collection. The following is a version of printing the cards that uses an iterator: - ```java public void print() { Iterator iterator = cards.iterator(); @@ -1050,11 +713,7 @@ public void print() { ``` - The iterator is requested from the `cards` list containing cards. The iterator can be thought of as a "finger" that always points to a particular object inside the list. Initially it points to the first item, then to the next, and so on... until all the objects have been gone through with the help of the "finger". The iterator offers a few methods. The `hasNext()` method is used to ask if there are any objects still to be iterated over. If there are, the next object in line can be requested from the iterator using the `next()` method. This method returns the next object in line to be processed and moves the iterator, or "finger", to point to the following object in the collection. @@ -1062,16 +721,7 @@ The iterator offers a few methods. The `hasNext()` method is used to ask if ther The object reference returned by the iterator's next method can of course also be stored in a variable. As such, the `print` method could also be written in the following way. - ```java public void print(){ Iterator iterator = cards.iterator(); @@ -1083,22 +733,10 @@ public void print(){ } ``` - + Let's now consider a use case for an iterator. We'll first approach the issue problematically to provide motivation for the coming solution. We attempt to create a method that removes cards from a given stream with a value lower than the given value. - ```java public class Hand { // ... @@ -1113,7 +751,7 @@ public class Hand { } ``` - + Executing the method results in an error. @@ -1124,29 +762,12 @@ Java Result: 1 - The reason for this error lies in the fact that when a list is iterated over using the forEach method, it's assumed that the list is not modified during the traversal. Modifying the list (in this case deleting elements) causes an error - we can think of the forEach method as getting "confused" here. If you want to remove some of the objects from the list during a traversal, you can do so using an iterator. Calling the `remove` method of the iterator object neatly removes form the list the item returned by the iterator with the previous `next` call. Here's a working example of the version of the method: - ```java public class Hand { // ... @@ -1167,71 +788,71 @@ public class Hand { - + Let's implement a program for managing employee data of a small company. - +

Education

- + Make an enumerated type (enum) `Education`. It should have the enumerators `PHD` (Doctoral degree), `MA` (Masters degree), `BA` (Bachelors degree) and `HS` (High School diploma). - +

Person

- + Make a class `Person`. The Person constructor takes a name and the education as parameters. A Person has a method `public Education getEducation()`, which returns the education of the person. A Person also has a `toString` -method which works as follows: - - - - + + + + ```java Person anna = new Person("Anna", Education.PHD); System.out.println(anna); ``` - + Anna, PHD - +

Employees

- + Make a class `Employees`. Employees -object contains a list of Person -objects. The class has a constructor which takes no parameters, and the following methods: - + - `public void add(Person personToAdd)` adds the given person to the employees list - + - `public void add(List peopleToAdd)` adds the given list of people to the employees list - + - `public void print()` prints all employees - + - `public void print(Education education)` prints the employees whose education matches the education given as a parameter. - + **NB:** The `print` method of the `Employees` class must be implemented using an iterator! - +

Firing an employee

- + Make a method `public void fire(Education education)` for the `Employees` class. The method removes all employees whose education matches the education given as parameter from the employees list. - + **NB**: Implement the method using an iterator! - + See an example of using the class below: ```java @@ -1249,7 +870,7 @@ System.out.println("=="); university.print(); ``` - + Prints: @@ -1266,25 +887,17 @@ Elina, PHD
- + - + The exercise template has a class that represents a playing card. Each card has a value and a suit. A card's value is represented as a number *2, 3, ..., 14* and its suit as *Club, Diamond, Heart* or *Spade*. Ace's value is 14. The value is represented with an integer, and the suit as an enum. Cards also have a method toString, which can be used to print the value and the suit in a readable form. - + New cards can be created like this: - ```java Card first = new Card(2, Suit.DIAMOND); @@ -1296,16 +909,10 @@ System.out.println(second); System.out.println(third); ``` - -The output: - @@ -1316,42 +923,32 @@ HEART Q - +

Comparable Card class

- + Change the Card class to be `Comparable`. Implement the `compareTo` method so that using it sorts the cards in ascending order based on their value. If the cards being compared have the same value, they are sorted by *club first, diamond second, heart third, and spade last.* - + Reading Ordinal method of Enum will help you out in sorting the cards by their suit. - + So, for this sorting, the least valuable card is two of clubs and most valuable card is the ace of spades.

Hand

- - + + Create a class `Hand` to represent the cards in a player's hand. Add the following methods to the class: - + - `public void add(Card card)` adds a card to the hand - `public void print()` prints the cards in hand as shown in the example below - ```java Hand hand = new Hand(); @@ -1364,17 +961,10 @@ hand.add(new Card(2, Suit.SPADE)); hand.print(); ``` - -Outputs: - DIAMOND 2 @@ -1384,27 +974,16 @@ SPADE 2 - + Use an ArrayList to store the cards. - -

Sorting the hand

- -Add a method `public void sort()` to the Hand class, which sorts the cards in the hand. After sorting, the cards are printed in order: +

Sorting the hand

- ```java Hand hand = new Hand(); @@ -1419,17 +998,10 @@ hand.sort(); hand.print(); ``` - -Output: - DIAMOND 2 @@ -1440,42 +1012,17 @@ SPADE A - -

Comparing hands

+

Comparing hands

- -In a card game, hands are ranked based on the sum of values of its cards. Modify the `Hand` class to be comparable based on this criteria, i.e. change the class so that interface `Comparable` applies to it. - - -Here's an example of a program that compares the hands: - ```java Hand hand1 = new Hand(); @@ -1502,17 +1049,10 @@ if (comparison < 0) { System.out.println("hands are equal"); } ``` - -Output - @@ -1524,31 +1064,23 @@ HEART J - +

Sorting cards with different criteria

- + What if we want to sort the cards in different ways, e.g. sorting all the cards of the same suit in a row. A class can only have one `compareTo` method, so we'll need something else to sort the cards in to a different order. - + Alternative sorting systems are possible through different sorting classes. Such a class must have the `Comparator` interface. An object of the sorting class will then compare two cards give as parameters. The class only has one method, compare(Card c1, Card c2), which returns a negative value if the card c1 should be sorted before card c2, a positive value if card c2 comes before card c1, and zero if they are equal. - + The idea is to create a different sorting class for each different way of sorting the cards, e.g. cards of the same suit in a row.: - ```java import java.util.Comparator; @@ -1559,27 +1091,14 @@ public class SortBySuit implements Comparator { } ``` - + When sorting the cards by suit, use the same order as with the `compareTo` method: *clubs first, diamonds second, hearts third, spades last.* - -Sorting still works with the sort method of Collections class. As its other parameter, the method now receives the object that has the sorting logic. - ```java ArrayList cards = new ArrayList<>(); @@ -1595,18 +1114,10 @@ Collections.sort(cards, sortBySuitSorter); cards.stream().forEach(c -> System.out.println(c)); ``` - -Output: - DIAMOND 2 @@ -1618,57 +1129,40 @@ SPADE 2 - + The sorting object can also be created directly when sort method is called. - + ```java Collections.sort(cards, new SortBySuit()); ``` - + It can even be done with a lambda function, without ever creating the sorting class. - + ```java Collections.sort(cards, (c1, c2) -> c1.getSuit().ordinal() - c2.getSuit().ordinal()); ``` - + You can learn more about creating sorting classes here. - + Now, create a class `BySuitInValueOrder` class that has the Comparator interface, which sorts the cards in the same order as in the above example, except that now the cards are sorted by value inside their suit. - -

Sorting the hand by suit

+

Sorting the hand by suit

- -Add a method `public void sortBySuit()` to class `Hand`. When the method is called, it sorts the cards in the hand with the same logic as in the previous part. After being sorted, the cards are printed in the following order: - ```java Hand hand = new Hand(); @@ -1684,19 +1178,10 @@ hand.sortBySuit(); hand.print(); ``` - -Output: - DIAMOND 2 diff --git a/data/part-10/4-summary.md b/data/part-10/4-summary.md index 59c88bcbf..6589cb28b 100644 --- a/data/part-10/4-summary.md +++ b/data/part-10/4-summary.md @@ -4,7 +4,7 @@ title: 'Summary' hidden: false --- - + Please take a moment to answer the quiz! Thank you! diff --git a/data/part-10/index.md b/data/part-10/index.md index a80e1ff65..b3901a9a3 100644 --- a/data/part-10/index.md +++ b/data/part-10/index.md @@ -5,14 +5,14 @@ overview: true hidden: false --- - + In the tenth part of the course we introduce handling collections with streams. You'll learn how to create a stream from a collection, filter the values of a stream, transform the values of a stream, and collect values of a stream to another collection. We introduce the concept lambda expression, and you'll learn to use it in your programs. You will also learn how to order objects using the Java Comparable interface, and some other useful techniques like regular expressions, enumerate type and iterator. - + The table of contents above lists the topics of the tenth part of the course. The tenth part has been designed to cover the tenth week of the course. You should reserve well above 10 hours for each part of the course, depending on previous experience with computers. If you've tried programming before, you might advance faster in the beginning. diff --git a/data/part-11/1-class-diagrams.md b/data/part-11/1-class-diagrams.md index 12378c198..5db4e7ca0 100644 --- a/data/part-11/1-class-diagrams.md +++ b/data/part-11/1-class-diagrams.md @@ -7,9 +7,9 @@ hidden: false - - - + + + - Know how to draw class diagrams and how to describe classes and their attributes, constructors, and methods - Know how to describe connections between classes and describe inheritance and interface implementation - Can implement a class based on a class diagram @@ -17,20 +17,20 @@ hidden: false - + A class diagram is a diagram used in designing and modeling software to describe classes and their relationships. Class diagrams enable us to model software in a high level of abstraction and without having to look at the source code. - + Classes in a class diagram correspond with classes in the source code. The diagram shows the names and attributes of the classes, connections between the classes, and sometimes also the methods of the classes. - + Next we will get familiar with creating and reading class diagrams using UML. Using a unified modeling language ensures that class diagrams drawn by different people can be read and understood by everyone familiar with the language.
## Describing class and class attributes - + First we will describe one class and its attributes. Below is the source code for a class called `Person` which has two class attributes name and age. @@ -41,20 +41,20 @@ public class Person { } ``` - + In a class diagram, a class is represented by a rectangle with the name of the class written on top. A line below the name of the class divides the name from the list of attributes (names and types of the class variables). The attributes are written one attribute per line. - + In a class diagram, class attributes are written "attributeName: attributeType". A + before the attribute name means the attribute is public, and a - means the attribute is private. - + [Person|-name:String;-age:int] ## Describing class constructor - + Below we have the source code for a constructor for our Person class. The constructor gets the name of the person as a parameter. ```java @@ -69,21 +69,21 @@ public class Person { } ``` - + In a class diagram, we list the constructor (and all other methods) below the attributes. A line below the attributes list separates it from the method list. Methods are written with +/- (depending on the visibility of the method), method name, parameters, and their types. The constructor above is written `+Person(initialName:String)` - + The parameters are written the same way class attributes are -- "parameterName: parameterType". - + [person|-name:String;-age:int|+Person(initialName:String)] ## Describing class methods - + Below we have added a method printPerson() which returns void to the Person class. ```java @@ -102,26 +102,26 @@ public class Person { } ``` - + In a class diagram, we list all class methods including the constructors; constructors are listed first and then all class methods. We also write the return type of a method in the class diagram. - + [Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void] - + A class diagram describes classes and their attributes, constructors and methods as well as the connections between classes. However a class diagram tells us nothing about the implementation of the constructors or the methods. Therefore a class diagram describes the structure of an object but not its functionality. - + For example the method `printPerson` uses the class attributes `name` and `age`, but this cannot be seen from the class diagram. - + Below we have added method `getName` to the Person class which returns the name of the Person. @@ -145,15 +145,15 @@ public class Person { } ``` - + [Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String] - + - + The class diagram below shows the class Customer. Implement the class in the exercise. @@ -163,7 +163,7 @@ The class diagram below shows the class Customer. Implement the class in the exe - + The class diagram below depicts the classes Book and Plane. Implement the classes in the exercise. @@ -171,15 +171,14 @@ The class diagram below depicts the classes Book and Plane. Implement the classe [Plane|-ID:String;-model:String;-yearOfIntroduction:int] - + ## Connections between classes - + In a class diagram, the connections between classes are shown as arrows. The arrows also show the direction of the connection. Below we have a class Book. @@ -194,11 +193,11 @@ public class Book { } ``` - + [Book|-name:String;-publisher:String] - + If we add a variable author, type of which is Person, in the source code the variable is declared like all other class variables. @@ -212,18 +211,18 @@ public class Book { } ``` - + In a class diagram variables which refer to other objects are not written with the rest of the class attributes, but are shown as connections between the classes. In the class diagram below we have the classes Person and Book, and the connection between them. - + [Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String][Book]-author->[Person] - + The arrow shows the direction of the connection. The connection above shows that a Book knows its author but a Person does not know about books they are the author of. We can also add a label to the arrow to describe the connection. In the above diagram the arrow has an accompanying label telling us that a Book has an author. - + If a book has multiple authors, the authors are saved to a list. ```java @@ -236,14 +235,14 @@ public class Book { } ``` - + In a class diagram, this situation is described by adding a star to the end of the arrow showing the connection between the classes. The star tells us that a book can have between 0 and unlimited number of authors. Below we have not amended the label to describe the multiplicity of the connection, but it would be a good idea for the sake of clarity. - + [Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String][Book]-*->[Person] - + Class methods are described just like we did before. Below we have added methods `getAuthors` and `addAuthor` to the Book class. @@ -265,36 +264,36 @@ public class Book { } ``` - + [Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String|+getAuthors():ArrayList;+addAuthor(author:Person)][Book]-*->[Person] - + We could add the type of the elements in the ArrayList `ArrayList` and a label describing the connection "authors" to the class diagram above. - + In the class diagram below, the classes Show and Ticket and their connection are depicted. The star is at the Ticket end of the connection -- in this case the star gives some extra information of the connection; even though a show doesn't know about the tickets that have been sold to it, you can still sell many tickets to one show. - + Implement the classes in the diagram in the exercise base. - + [Show|-movie:String;-time:String]<-*[Ticket|-seat:int;-code:int] - + If there is no arrowhead in a connection, both classes know about each other. Below is an example where a book knows about its author and a person knows about a book they have written. - + [Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String|+getAuthors():ArrayList;+addAuthor(author:Person)][Book]-*[Person] @@ -320,16 +319,16 @@ public class Book { } ``` - + As you can see, by default -- if there is no star on the connection -- the connection is singular. The classes above are interesting, because a Person can only have one book. - + If a person can have multiple books and a book can have multiple authors, we add a star to both ends of the connection: - + [Person|-name:String;-age:int|+Person(initialName:String);+printPerson():void;+getName():String][Book|-name:String;-publisher:String|+getAuthors():ArrayList;+addAuthor(author:Person)][Book]*-*[Person] - + Now the person class would be as follows: ```java @@ -345,11 +344,11 @@ public class Person { ``` - + - + Two classes, Student and University, are depicted below, as well as the connection between them. Implement these classes in the exercise base. @@ -360,40 +359,40 @@ Two classes, Student and University, are depicted below, as well as the connecti ## Describing inheritance - + In a class diagram inheritance is described by an arrow with a triangle head. The triangle points to the class being inherited from. In the below example the Engine inherits the class Part. - + [Part|-id:String;-manufacturer:String;-description:String][Engine|-type:String][Part]^-[Engine] - + In the below example the class diagram describes the classes from the Product warehouse exercise. The ProductWarehouseWithHistory class inherits the ProductWarehouse class, which, in turn, inherits the Warehouse class. ChangeHistory is a separate class connected to the ProductWarehouse. ProductWarehouseWithHistory knows about the ChangeHistory but the ChangeHistory does not know about the ProductWarehouseWithHistory. - + [Warehouse|-capacity:double;-balance:double|+Warehouse(capacity:double);+getBalance():double;+getCapacity():double;+howMuchSpaceLeft():double;+addToWarehouse(amount:double):void;+takeFromWarehouse(amount:double):double;+toString():String][ProductWarehouse|-name:String|+ProductWarehouse(name:String، capacity:double);+getName():String;+setName(name:String):String;+toString():String][ChangeHistory|-states:ArrayList|+ChangeHistory();+add(status:double);+clear():void;...][ProductWarehouseWithHistory||+ProductWarehouseWithHistory(name:String، capacity:double، initialBalance:double);+history():String;+printAnalysis():void;+addToWarehouse(amount:double);+takeFromWarehouse(amount:double):double][Warehouse]^-[ProductWarehouse][ProductWarehouse]^-[ProductWarehouseWithHistory][ChangeHistory]<-[ProductWarehouseWithHistory] - + Inheritance of abstract classes is described almost the same way as regular classes. However we add the description `<>` above the name of the class. The name of the class and its abstract methods are also written in cursive. - + - + The classes Player and Bot and the connection between them are depicted in the class diagram below. Implement these classes in the exercise. - + [Player|-name:String|+play():void;+printName():void]^-[Bot||+play():void;+addMove(move:String):void] - + A model answer is not supplied for this exercise. @@ -402,7 +401,7 @@ A model answer is not supplied for this exercise. ## Describing interfaces - + In class diagrams, interfaces are written `<>` NameOfTheInterface. Below we describe an interface Readable. @@ -412,27 +411,27 @@ public interface Readable { } ``` - + [<<interface>> Readable] - + Methods are described just like they are for a class. - + Implementing an interface is shown as a dashed arrow with a triangle arrowhead. Below, we describe a situation where Book implements interface Readable. - + [<<interface>> Readable][Book]-.-^[<<interface>> Readable] - + Below you'll see the interface Saveable and the class Person. Implement the contents of this class diagram in the exercise base. - + [<<interface>> Saveable ||+save():void;+delete():void;+load(address:String):void]^-.-[Person|-name:String;-address:String] @@ -441,16 +440,16 @@ Below you'll see the interface Saveable and the class Person. Implement the cont - + Class diagrams are an excellent way to describe a problem and a problem-domain to others. They are particularily useful when a programmer is designing a program with multiple classes. - + Often a class diagram is drawn on a whiteboard or a large sheet of paper during the design phase. Class diagrams should be thought of as helpful tools to build a program, which can be thrown away afterwards. You should not use too much energy to think about the correctness and details of the modeling language. Class diagrams should also be drawn in a suitable level of abstraction. For example, if you have tens of classes, it might not be worth describing each attribute and each method of each class; getting a good overview of the program structure is the most important. - +

The class diagrams here have been drawn using yUML, Creately, and draw.io. NetBeans also has tools for drawing class diagrams; for example, easyUML draws class diagrams from the source code.

@@ -458,10 +457,10 @@ NetBeans also has tools for drawing class diagrams; for example, ```java package library; @@ -62,26 +48,12 @@ public class Program { } ``` - - -Every package, including the default package, may contain other packages. For instance, in the package definition `package library.domain` the package `domain` is inside the package `library`. The word `domain` is often used to refer to the storage space of the classes that represent the concepts of the problem domain. For example, the class `Book` could be inside the package `library.domain`, since it represents a concept in the library application. - ```java package library.domain; @@ -99,23 +71,11 @@ public class Book { } ``` - - -A class can access classes inside a package by using the `import` statement. The class `Book` in the package `library.domain` is made available for use with the statement `import library.domain.Book;`. The import statements that are used to import classes are placed in the source code file after the package definition. - ```java package library; @@ -131,11 +91,7 @@ public class Program { } ``` - @@ -143,71 +99,59 @@ Hello packageworld: the ABCs of packages! - + From this point on, *nearly all* of the exercises will use packages. Let's begin by creating our first very own packages. - +

UserInterface

- + There is a package called `mooc` included in the exercise. We will create the functionality of the program inside this package. Add the package `ui` inside the package `mooc` (after which the package `mooc.ui` should be available), and add an interface called `UserInterface` in it. - + The interface `UserInterface` defines the method `void update()`. - +

Text user interface

- + In the same package, create the class `TextInterface` that implements the `UserInterface` interface. Implement the method `public void update()`, required by the interface `UserInterface`, so that the only thing it does is print the string `"Updating UI"` by calling the method `System.out.println`. - +

Application logic

- + Then create the package `mooc.logic`. Create the class `ApplicationLogic` in it. The functionality that the application logic offers should be as follows: - + - `public ApplicationLogic(UserInterface ui)`
The constructor of the ApplicationLogic class. It receives as a parameter a class that implements the UserInterface interface. NB: For application logic to see the interface, it must be "imported". Add the line `import mooc.ui.UserInterface` at the beginning of the file. - + - `public void execute(int times)`
Prints the string "Application logic is working" the number of times that is indicated by the variable `times`. After each print, the method should call the `update()` method of the object that was received as a constructor parameter (which implements the `UserInterface` interface). - -You can test the program with the following main program class. +You can test the program with the following main program class. - ```java import mooc.logic.ApplicationLogic; @@ -223,16 +167,7 @@ public class Main { } ``` - @@ -248,11 +183,11 @@ Updating UI
- + - + Within the exercise base, create three packages: `a`, `b`, and `c`. Create class `A` inside the package `a`, class `B` inside the package `b`, and class `C` inside the package `c`. The classes don't need object variables, constructors, or methods. @@ -260,55 +195,33 @@ Within the exercise base, create three packages: `a`, `b`, and `c`. Create class - + ## Directory structure in a file system - +

Every project you see in NetBeans is in your computer's file system or on a centralized server.

- -The project directory `src/main/java` contains the source code files of the program. If the package of a class is library, that class is stored inside the `src/main/java/libary` folder of the source code directory. You can also check the concrete project structure in NetBeans in the **Files** tab, which is normally next to the **Project** tab. If you cannot see the **Files** tab, you can make it appear by choosing the option **Files** from the dropdown menu **Window**. - +The project directory `src/main/java` contains the source code files of the program. If the package of a class is library, that class is stored inside the `src/main/java/libary` folder of the source code directory. You can also check the concrete project structure in NetBeans in the **Files** tab, which is normally next to the **Project** tab. If you cannot see the **Files** tab, you can make it appear by choosing the option **Files** from the dropdown menu **Window**. -Application development is normally done in the **Projects** tab, where NetBeans hides unimportant files from the programmer. - -## Packages and access modifiers +Application development is normally done in the **Projects** tab, where NetBeans hides unimportant files from the programmer. - -Until now, we've used two access modifiers. The modifier `private` is used to define variables (and methods) that are only visible inside the class where they are defined. They cannot be used from outside that class. The methods and variables defined with `public`, on the other hand, are available for everyone to use. +## Packages and access modifiers - ```java package library.ui; @@ -334,37 +247,15 @@ public class UserInterface { } ``` - - -If you create an object of the `UserInterface` class above, its constructor and `start` method are callable from anywhere in the program. The method `printTitle` and the variable `scanner` are available only from within the class. - -If the access modifier is missing, the methods and variables are only visible inside the same package. We call this the default or package modifier. Let's change the example above so that the method `printTitle` has package access modifier. - - ```java package library.ui; @@ -390,25 +281,11 @@ public class UserInterface { } ``` - -Now the classes inside the same package -- i.e., the classes inside the package `library.ui` -- can use the method `printTitle`. - - ```java package library.ui; @@ -426,26 +303,11 @@ public class Main { } ``` - - -If a class is in a different package, the method `printTitle` cannot be called. In the example below, the class `Main` is in the package `library`. As the `printTitle` method is in the package `library.ui` and has the package access modifier, it cannot be used. - - ```java package library; @@ -465,101 +327,15 @@ public class Main { ``` - - -## A larger example: flight control - -Let's take a look at a program that offers a text UI for adding and examining airplanes and flights. The user interface of the program looks like this. +## A larger example: flight control - @@ -649,61 +425,45 @@ Choose an action: - + There are many concepts of the problem domain in the program, and the essential ones are `Airplane` and `Flight`. Each flight also involves a `Place` (places of departure and destination). In addition to the concepts that represent the problem domain, the program also contains a text UI and a class through which the text UI uses the concepts. - + The package structure of the program could look like the following (for example): - + - `flightControl` - includes the main program class that is needed to start the program - + - `flightControl.domain` - includes the classes that represent concepts of the problem domain: `Airplane`, `Flight`, and `Place` - + - `flightControl.logic` - includes the functionality that is used to control the application - + - `flightControl.ui` - includes the textual user interface - + In the next subchapter, we list one possible organization for the operation of the program (excluding the main program class). - -## Classes that represent concepts of the problem domain - +## Classes that represent concepts of the problem domain -The classes that represent concepts of the problem domain are often placed inside a package called `domain`. Since the entirety of the application is inside the package `flightControl`, let's place the package `domain` inside the package `flightControl`. Concepts of the problem domain are represented by the classes `Place`, `Airplane`, and `Flight`. - ```java package flightControl.domain; @@ -723,33 +483,7 @@ public class Place { } ``` - ```java package flightControl.domain; @@ -779,39 +513,7 @@ public class Airplane { } ``` - ```java package flightControl.domain; @@ -848,62 +550,15 @@ public class Flight { ``` - - -### Application logic - - - -The application logic is typically kept separate from the classes that represents concepts of the problem domain. In our example, the application logic is stored in the package `logic`. Application logic includes the functionality to add airplanes and flights, and to list them. - - ```java package flightControl.logic; @@ -958,146 +613,15 @@ public class FlightControl { - - -### Text user interface - - - -The user interface is separate from the application logic and the classes that represent the problem domain. In this example, the user interface is stored in the package `ui`. - - ```java package flightControl.ui; @@ -1233,124 +757,38 @@ public class TextUI { ``` - + - + In this exercise, you will implement the application that was described above. You are free to design the structure as you wish, or you can follow the structure sketched out above. The appearance of the user interface and the required commands are predefined. This exercise is worth two normal exercise points. - + **NB: for the tests to work, you can only create one Scanner object in your program to read user input.** - +

In this exercise, you will implement a flight control application. It is used to control the airplanes and their flight routes. The system always knows the identifier and the capacity of an airplance. The flight information consists of the used airplane, the departure airport id (e.g. HEL), and the destination airport ID (e.g. BAL).

- + There can be multiple airplanes and flights. The same airplane can be used to make several flights. - -The application should operate in two parts: first, the user enters information about airplanes and flights in the airport asset control, after which the program offers the flight information service for the user. There are three operations in this latter flight control -- printing the airplanes, printing the flights, and printing the information of a single airplane. In addition, the user may exit the program by choosing the option `x`. If the user enters an invalid command, the program asks for a command again. - +The application should operate in two parts: first, the user enters information about airplanes and flights in the airport asset control, after which the program offers the flight information service for the user. There are three operations in this latter flight control -- printing the airplanes, printing the flights, and printing the information of a single airplane. In addition, the user may exit the program by choosing the option `x`. If the user enters an invalid command, the program asks for a command again. -**The program should start when the main method of the Main class inside the package `FlightControl` is executed** - -Example output of the program is presented below: +**The program should start when the main method of the Main class inside the package `FlightControl` is executed** - @@ -1439,14 +877,13 @@ Choose an action: - + **NB** For the purposes of the test it is essential that the *user interface* work **exactly** as described above. You should probably copy the options printed by the program from here to your code. The tests won't assume that your program is prepared to handle improper input. - - + +
diff --git a/data/part-11/3-exceptions.md b/data/part-11/3-exceptions.md index c1c10ce1f..1b0201c0d 100644 --- a/data/part-11/3-exceptions.md +++ b/data/part-11/3-exceptions.md @@ -8,25 +8,25 @@ hidden: false - - - + + + - Know what exceptions are and how to handle them - Can throw exceptions - Know that some exceptions have to be handled and that some exceptions do not have to be handled. - + When program execution ends with an error, an exception is thrown. For example, a program might call a method with a *null* reference and throw a `NullPointerException`, or the program might try to refer to an element outside an array and result in an `IndexOutOfBoundsException`, and so on. - + Some exceptions we have to always prepare for, such as errors when reading from a file or errors related to problems with a network connection. We do not have to prepare for runtime exceptions, such as the NullPointerException, beforehand. Java will always let you know if your code has a statement or an expression which can throw an error you have to prepare for. ## Handling exceptions - + We use the `try {} catch (Exception e) {}` block structure to handle exceptions. The keyword `try` starts a block containing the code which *might* throw an exception. the block starting with the keyword `catch` defines what happens if an exception is thrown in the `try` block. The keyword `catch` is followed by the type of the exception handled by that block, for example "all exceptions" `catch (Exception e)`. @@ -38,15 +38,15 @@ try { } ``` - + We use the keyword `catch`, because causing an exception is referred to as `throw`ing an exception. - + As mentioned above, we do not have to prepare for runtime exceptions such as the NullPointerException. We do not have to handle these kinds of exceptions, so the program execution stops if an error causes the exception to be thrown. Next, we will look at one such situation, parsing strings to integers. - + We have used the parseInt method of the `Integer` class before. The method throws a `NumberFormatException` if the string it has been given cannot be parsed into an integer. @@ -68,10 +68,10 @@ Give a number: **dinosaur**
- + The above program throws an error if the user input is not a valid number. The exception will cause the program execution to stop. - + Let's handle the exception. We wrap the call that might throw an exception into a `try` block, and the code executed if the exception is thrown into a `catch` block. ```java @@ -101,7 +101,7 @@ User input was not a number.
- + The code in the `catch` block is executed immediately if the code in the `try` block throws an exception. We can demonstrate this by adding a print statement below the line calling the `Integer.parseInt` method in the `try` block. @@ -134,13 +134,13 @@ User input was not a number. - + The user input, in this case the string `no!`, is given to the `Integer.parseInt` method as a parameter. The method throws an error if the string cannot be parsed into an integer. Note, that the code within the `catch` block is executed *only* if an exception is thrown. - + Let's make our integer parser a bit more useful. We'll turn it into a method which prompts the user for a number until they give a valid number. The execution stops only when the user gives a valid number. @@ -173,11 +173,11 @@ Give a number: **43** ## Exceptions and resources - + There is separate exception handling for reading operating system resources such as files. With so called try-with-resources exception handling, the resource to be opened is added to a non-compulsory part of the try block declaration in brackets. - + The code below reads all lines from "file.txt" and adds them to an ArrayList. Reading a file might throw an exception, so it requires a try-catch block. @@ -198,7 +198,7 @@ try (Scanner reader = new Scanner(new File("file.txt"))) { // do something with the lines ``` - + The try-with-resources approach is useful for handling resources, because the program closes the used resources automatically. Now references to files can "disappear", because we do not need them anymore. If the resources are not closed, the operating system sees them as being in use until the program is closed. @@ -206,11 +206,11 @@ If the resources are not closed, the operating system sees them as being in use ## Shifting the responsibility - + Methods and constructors can throw exceptions. There are roughly two categories of exceptions. There are exceptions we have to handle, and exceptions we do not have to handle. We can handle exceptions by wrapping the code into a `try-catch` block or *throwing them out of the method*. - + The code below reads the file given to it as a parameter line by line. Reading a file can throw an exception -- for example, the file might not exist or the program does not have read rights to the file. This kind of exception has to be handled. @@ -231,7 +231,7 @@ public List readLines(String fileName){ } ``` - + A programmer can also leave the exception unhandled and shift the responsibility for handling it to whomever calls the method. We can shift the responsibility of handling an exception forward by throwing the exception out of a method, and adding notice of this to the declaration of the method. Notice on throwing an exception forward `throws *ExceptionType*` is added before the opening bracket of a method. @@ -244,7 +244,7 @@ public List readLines(String fileName) throws Exception { } ``` - + Now the method calling the `readLines` method has to either handle the exception in a `try-catch` block or shift the responsibility yet forward. Sometimes the responsibility of handling exceptions is avoided until the end, and even the `main` method can throw an exception to the caller: @@ -256,12 +256,12 @@ public class MainProgram { } ``` - + Now the exception is thrown to the program executor, or the Java virtual machine. It stops the program execution when an error causing an exception to be thrown occurs. ## Throwing exceptions - + The `throw` command throws an exception. For example a `NumberFormatException` can be done with command `throw new NumberFormatException()`. The following code always throws an exception. @@ -275,12 +275,12 @@ public class Program { } ``` - + One exception that the user does not have to prepare for is `IllegalArgumentException`. The `IllegalArgumentException` tells the user that the values given to a method or a constructor as parameters are *wrong*. It can be used when we want to ensure certain parameter values. - + Lets create class `Grade`. It gets a integer representing a grade as a constructor parameter. ```java @@ -297,7 +297,7 @@ public class Grade { } ``` - + We want that the grade fills certain criteria. The grade has to be an integer between 0 and 5. If it is something else, we want to *throw an exception*. Let's add a conditional statement to the constructor, which checks if the grade fills the criteria. If it does not, we throw the `IllegalArgumentException` with `throw new IllegalArgumentException("Grade must be between 0 and 5.");`. @@ -336,32 +336,32 @@ Exception in thread "..." java.lang.IllegalArgumentException: Grade must be betw - + If an exception is a runtime exception, e.g. IllegalArgumentException, we do not have to warn about throwing it on the method declaration. - + - + Let's practise a little parameter validation with the `IllegalArgumentException` exception. There are two classes included with the exercise base: `Person` and `Calculator`. Modify the classes in the following manner: - +

Validating a person

- + The constructor of the class `Person` should ensure that the name given as the parameter is not null, empty, or over 40 characters in length. The age should between 0 and 120. If some of these conditions are not met, the constructor should throw an `IllegalArgumentException`. - +

Validating the calculator

- + The methods of the `Calculator` class should be as follows: The method `factorial` should only work if the parameter is a non-negative number (0 or greater). The method `binomialCoefficient` should only work when the parameters are non-negative and the subset size does not exceed the set size. If these methods receive invalid parameters when they are called, they should throw an `IllegalArgumentException` @@ -370,15 +370,15 @@ The methods of the `Calculator` class should be as follows: The method `factoria - + We said "*there are roughly two categories of exceptions: exceptions which must be handled, and exceptions which do not have to be handled.*" - + Exceptions which must be handled are exceptions which are checked for during compilation. Due to this, some exceptions have to be prepared for with a `try-catch` block or by throwing them out of a method with a `throws` attribute in a method declaration. For example, exceptions related to handling files, including `IOException` and `FileNotFoundException`, are this kind of exception. - + Some exceptions are not checked for during compilation. They can be thrown during execution. These kinds of exceptions do not have to be handled with a `try-catch` block. For example, `IllegalArgumentException` and `NullPointerException` are this kind of exception. @@ -387,7 +387,7 @@ These kinds of exceptions do not have to be handled with a `try-catch` block. Fo ## Exceptions and Interfaces - + An Interface can have methods which throw an exception. For example the classes implementing the following `FileServer` interface *might* throw an exception from the methods `load` or `save`. @@ -398,7 +398,7 @@ public interface FileServer { } ``` - + If an interface declares a `throws Exception` attribute to a method, so that these methods might throw an exception, the class implementing this interface must also have this attribute. However the class does not have to throw an error, as we can see below. @@ -426,7 +426,7 @@ public class TextServer implements FileServer { ## Details of the exception - + A `catch` block defines which exception to prepare for with `catch (Exception e)`. The details of the exception are saved to the `e` variable. @@ -438,7 +438,7 @@ try { } ``` - + The `Exception` class has some useful methods. For example `printStackTrace()` prints the *stack trace*, which shows how we ended up with an exception. Below is a stack trace printed by the `printStackTrace()` method. @@ -451,7 +451,7 @@ Exception in thread "main" java.lang.NullPointerException - + We read a stack trace from the bottom up. At the bottom is the first call, so the execution of the program has begun from the `main()` method of the `Class` class. Line 29 of the main method of the `Class` class calls the `print()` method. Line 43 of the `print` method has thrown a `NullPointerException` exception. @@ -461,29 +461,20 @@ The details of an exception are very useful when trying to pinpoint where an err - + - + All the classes should be placed inside the `application` package. - + We have the following interface at our disposal: - + ```java public interface Sensor { @@ -495,35 +486,23 @@ public interface Sensor { } ``` - +

Standard sensor

- + Create a class called `StandardSensor` that implements the interface `Sensor`. - + A standard sensor is always on. Calling the methods setOn and setOff have no effect. The StandardSensor must have a constructor that takes one integer parameter. The method call `read` returns the number that was given to the constructor. - -An example: - ```java public static void main(String[] args) { @@ -549,68 +528,51 @@ true - +

TemperatureSensor

- + Create a class `TemperatureSensor` that implements the `Sensor` interface. - + At first a temperature sensor is off. When the method `read` is called and the sensor is on, the sensor randomly chooses an integer in the range -30...30 and returns it. If the sensor is off, the method `read` throws an `IllegalStateException`. - + Use the ready-made Java class Random to choose the random number. You'll get an integer in the range 0...60 by calling `new Random().nextInt(61);` -- to get a random integer in the range -30...30 you'll have to subtract a suitable number from the random number in the range 0...60.
- +

Average sensor

- + Create a class called `AverageSensor` that implements the interface `Sensor`. - + An average sensor includes multiple sensors. In addition to the methods defined in the `Sensor` interface, the AverageSensor has the method `public void addSensor(Sensor toAdd)` that can be used to add a new sensor for the average sensor to control. - + An AverageSensor is on when *all* its sensors are on. When `setOn` is called, all the sensors must be set on. When `setOff` is called, at least one of the sensors must be set off. It's also acceptable to set off all the sensors. - -The method `read` of AverageSensor returns the average of the `read` methods of its sensors (since the return value is `int`, the number is rounded down as is the case with integer division). If this method is called while the AverageSensor is off, or if no sensors have been added to it, the method should throw an `IllegalStateException`. - +The method `read` of AverageSensor returns the average of the `read` methods of its sensors (since the return value is `int`, the number is rounded down as is the case with integer division). If this method is called while the AverageSensor is off, or if no sensors have been added to it, the method should throw an `IllegalStateException`. -Here follows an example program that uses the sensors (NB: the constructors of both TemperatureSensor and AverageSensor are non-parameterized): - ```java public static void main(String[] args) { @@ -631,17 +593,12 @@ public static void main(String[] args) { } ``` - -The print statements below depend on which temperatures are randomly returned: +The print statements below depend on which temperatures are randomly returned: - @@ -651,33 +608,15 @@ temperature in Helsinki region 8 degrees Celsius - +

All readings

- -Add to the class AverageSensor the method `public List readings()`. The method should return the results of all the executed readings that the average sensor has done as a list. Here is an example: - ```java public static void main(String[] args) { @@ -699,7 +638,7 @@ public static void main(String[] args) { } ``` - + Again, the exact print statements depend on the randomized readings: diff --git a/data/part-11/4-processing-files.md b/data/part-11/4-processing-files.md index 015d3dd5d..0d674b946 100644 --- a/data/part-11/4-processing-files.md +++ b/data/part-11/4-processing-files.md @@ -5,36 +5,30 @@ hidden: false --- - + - + - You will refresh your memories of reading from files. - + - You will be able to write to a file. - + We have already learned some strategies to read text files. If your memories of the subject are hazy, take a look at the relevant parts of Part 4 of the course material. - + Next, let's take a look at writing data to files. The [PrintWriter](https://docs.oracle.com/javase/8/docs/api/java/io/PrintWriter.html) class offers the functionality to write to files. The constructor of the `PrintWriter` class receives as its parameter a string that represents the location of the target file. - + ```java PrintWriter writer = new PrintWriter("file.txt"); @@ -44,25 +38,16 @@ writer.print("And a little extra"); // writes the string "And a little extra" to writer.close(); //closes the file and ensures that the written text is saved to the file ``` - + In the example above, we write to the file "file.txt" the string "Hello file!", followed by a line change and some additional text. Take notice that when writing to the file the method `print` does not add line changes, and you have to add them yourself. In contrast, the method `println` adds a new line change at the end of the parameter string it receives. - + The constructor of the `PrintWriter` class might throw an exception that must be either handled or thrown so that it is the responsibility of the calling method. Here is what a method that receives as its parameters a file name and the text contents to write into it could look like. - ```java public class Storer { @@ -75,21 +60,16 @@ public class Storer { } ``` - + In the `writeToFile` method above we begin by creating a `PrintWriter` object. It writes data the the file that is located at the path that the string `fileName` indicates. After this, we write the text to the file by calling the `println` method. The possible exception that the constructor throws has to be handled with a `try-catch` block or the handling responsibility has to be transferred elsewhere. In the `writeToFile` method, the responsibility to handle the exception is placed on the method that calls `writeToFile`. - + Let's create a `main` method that calls the `writeToFile` of a `Storer` object. There is nothing to force the `main` method to handle the exception -- it, too, can state that it might throw an exception by adding `throws Exception` to the method definition. - + ```java public static void main(String[] args) throws Exception { @@ -98,11 +78,11 @@ public static void main(String[] args) throws Exception { } ``` - + By calling the method above we create a file called "diary.txt" and write the text "Dear diary, today was a good day." into it. If the file already exists, the earlier contents are erased when we store the new text. - + It is also possible to handle files in a way that adds the new text after the existing content. In that case, you might want to use the [FileWriter](https://docs.oracle.com/javase/8/docs/api/java/io/FileWriter.html) class. @@ -113,27 +93,27 @@ It is also possible to handle files in a way that adds the new text after the ex - + In this exercise we will extend the dictionary, so that it can read words from a file and write words to a file. The dictionary must also be able to translate both from Finnish to another language and from another language to Finnish (in this exercise we ignore the fact that some words might be written the same in Finnish and in other languages). Your mission is to create a dictionary in the class `SaveableDictionary`. Implement the class in the package `dictionary`. - +

The basic functionality

- + For the dictionary, implement a constructor which takes no parameters, and the following methods: - - + + - `public void add(String words, String translation)` adds a word to the dictionary. Every word has just one translation, and if the same word is added for the second time, nothing happens. - `public String translate(String word)` returns the translation for the given word. If the word is not in the dictionary, returns null. - + In this phase, the dictionary should work as follows: @@ -149,7 +129,7 @@ System.out.println(dictionary.translate("ohjelmointi")); System.out.println(dictionary.translate("banana")); ``` - + Prints @@ -162,28 +142,28 @@ banaani - + As can be seen from the output, after a translation has been added to the dictionary, it can translate the word to and from Finnish. - + NB: the methods `add` and `translate` do not read from a file or write to a file! The constructor does not use a file either. - +

Deleting words

- + Add the dictionary method `public void delete(String word)` which deletes the given word and its translation from the dictionary. - + It might be worth reviewing the material concerning deleting objects from an ArrayList from previous weeks. - + NB: the method `delete` does not write to a file. - + In this phase, the dictionary should work as follows: ```java @@ -201,7 +181,7 @@ System.out.println(dictionary.translate("banaani")); System.out.println(dictionary.translate("ohjelmointi")); ``` - + Prints @@ -215,21 +195,21 @@ programming - + Deleting also works both ways: Both the word and its translation are removed if either the word or the translation are deleted. - +

Reading from file

- + Make a constructor `public SaveableDictionary(String file)` and method `public boolean load()`, which loads the dictionary from the file given to the constructor as a parameter. If the program is unable to open the file or read from it, the method returns false, otherwise it returns true. - + NB: the constructor only tells the dictionary the name of the file to load the dictionary from. The constructor does not read the file. Only the method `load` reads the file. - + In the dictionary file, one line contains a word and its translation separated by ":". The exercise template contains a file `words.txt` which contains the following: @@ -241,20 +221,11 @@ olut:beer - + Read the dictionary file line by line with the method `nextLine`. You can split a line using the String method `split` like so: - ```java Scanner fileReader = new ... @@ -267,7 +238,7 @@ while (fileReader.hasNextLine()) { } ``` - + The dictionary can be used as follows: ```java @@ -295,16 +266,16 @@ below - +

Saving to a file

- + Create the method `public boolean save()`, which saves the dictionary to the file given to the dictionary as a parameter to the constructor. If the program cannot save to the file, the method returns false. Otherwise it returns true. The dictionary files have to be saved in the form described above, so the program can read the files it has written. - + NB: Only the method `save` writes to the file. - + **NB:** Even though the dictionary can translate both ways, the dictionary file should only contain one way. So if the dictionary, for example, knows that *computer = tietokone*, the file should contain: @@ -322,13 +293,13 @@ computer:tietokone - + but not both! - + It is best to handle the saving to, such that the whole dictionary is written on top of the previously saved version, so it might not be the best to use the `append` method described in the material. - + The final version of the dictionary works as follows: ```java @@ -340,7 +311,7 @@ dictionary.load(); dictionary.save(); ``` - + In the beginning, the dictionary is loaded from a file, and, in the end, it is saved back to the file, so that changes made to the dictionary are kept for the next time the dictionary is used.
diff --git a/data/part-11/5-conclusion.md b/data/part-11/5-conclusion.md index f6e02fbc9..8dcc11b8a 100644 --- a/data/part-11/5-conclusion.md +++ b/data/part-11/5-conclusion.md @@ -4,9 +4,7 @@ title: 'Conclusion' hidden: false --- - Finally, please take a moment to answer a self-reflective survey on the learning goals of the eleventh part. diff --git a/data/part-11/index.md b/data/part-11/index.md index 66a7cc695..9aa53f087 100644 --- a/data/part-11/index.md +++ b/data/part-11/index.md @@ -5,7 +5,7 @@ overview: true hidden: false --- - + In the eleventh part you'll learn to decypher simple class diagrams. You'll become familiar with packages in Java and learn what the different parts of an `import` statement mean. You'll practise using exceptions in Java: how to throw and handle them. You'll take another look at reading data from a file, and learn to write data to a file. diff --git a/data/part-12/1-type-parameters.md b/data/part-12/1-type-parameters.md index f6359a6e2..6ad5d6f40 100644 --- a/data/part-12/1-type-parameters.md +++ b/data/part-12/1-type-parameters.md @@ -4,50 +4,38 @@ title: 'Type parameters' hidden: false --- - + - + - You know what is meant with the concept of a generic type parameter. - + - You are familiar with already existing Java classes that make use of generic type parameters. - + - You can create classes of your own that make use of generic type parameters. - + Since we began using lists, we have given data structures the type of the values that we want them to store. For example, a list that stores strings has been defined as `ArrayList`, and a hash map that stores keys and values as Strings has been defined as `HashMap`. How on Earth can you implement a class that can contain objects of a given type? - + *Generics* relates to how classes that store objects can store objects of a freely chosen type. The choice is based on the generic type parameter in the definition of the classes, which makes it possible to choose the type(s) *at the moment of the object's creation*. Using generics is done in the following manner: after the name of the class, follow it with a chosen number of type parameters. Each of them is placed between the 'smaller than' and 'greater than' signs, like this: `public class Class`. The type parameters are usually defined with a single character. - -Let's implement our own generic class `Locker` that can hold one object of any type. - ```java public class Locker { @@ -64,17 +52,12 @@ public class Locker { ``` - + The definition `public class Locker` indicates that the `Locker` class must be given a type parameter in its constructor. After the constructor call is executed, all the variables stored in that object are going to be of the type that was given with the constructor. Let's create a locker for storing strings. - ```java Locker string = new Locker<>(); @@ -90,24 +73,12 @@ System.out.println(string.getValue()); - -In the program above, the **runtime** implementation of the `Locker` object named `string` looks like the following. +In the program above, the **runtime** implementation of the `Locker` object named `string` looks like the following. - ```java public class Locker { @@ -123,16 +94,11 @@ public class Locker { } ``` - + Changing the type parameter allows for creating lockers that store objects of other types. You could store an integer in the following manner. - ```java Locker integer = new Locker<>(); @@ -148,16 +114,11 @@ System.out.println(integer.getValue()); - + Similarly, here is how to create a locker for storing a `Random` object. - ```java Locker random = new Locker<>(); @@ -167,29 +128,11 @@ System.out.println(random.getValue().nextDouble()); ``` - - -There is no maximum on the number of type parameters, it's all dependent on the implementation. The programmer could implement the following `Pair` class that is able to store two objects of specified types. - ```java public class Pair { @@ -214,15 +157,12 @@ public class Pair { - + A significant portion of the Java data structures use type parameters, which enables them to handle different types of variables. ArrayList, for instance, receives a single type parameter, while HashMap receives two. - + ```java List strings = new ArrayList<>(); @@ -230,22 +170,16 @@ Map keyValuePairs = new HashMap<>(); ``` - + From here on out when you see the type `ArrayList`, you know that its internal implementation uses a generic type parameter. The same principle holds true for the interface Comparable, for example. - + Creating generic interfaces is very similar to creating generic classes. Below you can study the generic interface `List` (our own definition, which is not as extensive as the existing Java [List](https://docs.oracle.com/javase/8/docs/api/java/util/List.html)). - + ```java public interface List { @@ -256,31 +190,12 @@ public interface List { ``` - - -There are two ways for a class to implement a generic interface. One is to decide the type parameter in the definition of the class, and the other is to define the implementing class with a type parameter as well. Below, the class `MovieList` defines the type parameter when it implements List. The MovieList is meant only for handling movies. - ```java public class MovieList implements List { @@ -303,30 +218,11 @@ public class MovieList implements List { } ``` - -The alternative is to use a type parameter in the class defintion, in which case the parameter is passed along to the interface. Now this concrete implementation of the interface remains generic. - ```java public class GeneralList implements List { @@ -349,38 +245,11 @@ public class GeneralList implements List { } ``` - - -If you wanted, you could also use the existing ArrayList class to implement the GeneralList. The implementation would look roughly like this. - - ```java import java.util.ArrayList; @@ -412,46 +281,34 @@ public class GeneralList implements List { ``` - + - + Implement a class called Hideout, which has a single generic type parameter. The object created from the class may only hide one object at a time. The class should provide a parameterless constructor as well as the following three methods: - + - `public void putIntoHideout(T toHide)` puts an object with a type in accordance with the type parameter given to the the class into the hideout. In case an object is already in the hideout, it will disappear. - + - `public T takeFromHideout()` takes out the object with a type in accordance with the type parameter given to the the class from the hideout. In case there is nothing in the hideout, we return `null`. Calling the method returns the object in the hideout and removes the object from the hideout. - + - `public boolean isInHideout()` returns the value `true` if there is an object in the hideout. In case there isn't an object in the hideout, it should return the value `false`. - + **There are no tests for the class in the exercise template**. Submit the exercise when the following examples work as intended. - + ```java Hideout den = new Hideout<>(); @@ -467,17 +324,7 @@ System.out.println(den.takeFromHideout()); System.out.println(den.isInHideout()); ``` - @@ -491,15 +338,7 @@ false - + ```java Hideout den = new Hideout<>(); @@ -524,42 +363,33 @@ false - + - + Implement a class called Pipe, which has a single generic parameter type. The pipe works, such that we can add values into it and values can be taken out. Adding to the pipe happens from one end, and taking out from the other end. In other words, we always remove the value which has been inside the pipe the longest and add to it the newest value. The class should provide a parameterless constructor as well as the following three methods: - + - `public void putIntoPipe(T value)` puts an object with a type in accordance with the type parameter given to the the class into the pipe. - + - `public T takeFromPipe()` takes out the value, which has been in the pipe the longest. In case there is nothing in the pipe, return `null`. Calling the method returns the value, which has been in the pipe the longest, and removes it from the pipe. - + - `public boolean isInPipe()` returns the value `true` if the pipe has values. In case the pipe is empty, it returns the value `false`. - + Use ArrayList to implement the internal functionality of the class. - + **There are no tests for the class in the exercise template**. Submit the exercise when the following examples work as intended. - + ```java Pipe pipe = new Pipe<>(); @@ -572,14 +402,7 @@ while(pipe.isInPipe()) { } ``` - @@ -590,19 +413,7 @@ daa - ```java Pipe numberPipe = new Pipe<>(); diff --git a/data/part-12/2-arraylist-and-hashtable.md b/data/part-12/2-arraylist-and-hashtable.md index de013baf4..c767cc3c3 100644 --- a/data/part-12/2-arraylist-and-hashtable.md +++ b/data/part-12/2-arraylist-and-hashtable.md @@ -4,41 +4,41 @@ title: 'ArrayList and hash table' hidden: false --- - + - + - You know how to implement a generic list that has changing size. - + - You know of one possible method to implement a class like Java's ArrayList. - + - You know how to implement a hash table. - + - You are aware of one possible method to implement a class like Java's HashMap. - + ArrayList and HashMap are commonly used data structures in programming. We are now going to take a look at their actual implementation. First we'll remind ourselves of how to use an array, after which we're going to build a data structure called `List`, imitating ArrayList. Then we'll make use of the List to implement the data structure `HashTable`. - + ## A brief recap of arrays - + An array is an object that contains a limited number of places for values. The length (or size) of an array is the number of places in it; in other words, how many values can be stored in the array. The size of an array is always predetermined: it is chosen when the array is created, and cannot be changed later. - + The array type is defined with square brackets preceded by the type of the elements in the array (typeOfElements[]). An array is created with the `new` call, followed by the type of the elements in that array, square brackets, and the number of elements in the array places inside the square brackets. @@ -47,7 +47,7 @@ int[] numbers = new int[3]; String[] strings = new String[5]; ``` - + The elements of the array are referred to by the indexes. Below we create an integer array of size three, after which we set values to indexes 0 and 2. Then we print those values. @@ -68,27 +68,15 @@ System.out.println(numbers[2]); - + Setting a single value to a certain position is done similarly to setting a value to a regular variable, just that when placing the value in an array, you use the index to indicate the position. - -To discover the size of an array you can use the public object variable `length` that arrays have. Examining the elements one by one can be accomplished with a for loop, for instance. - ```java int[] numbers = new int[4]; @@ -104,17 +92,7 @@ for (int i = 0; i < numbers.length; i++) { } ``` - @@ -131,10 +109,10 @@ There are 4 elements in the array. - + In the class `Program` implement a class method `public static int sum(int[] array, int fromWhere, int toWhere, int smallest, int largest)`. The method must calculate the sum of the elements in the array between the lower and the upper limits. Only numbers smaller or equal to the int largest and larger or equal to the int smallest are added to the sum. - + The method must also check that the lower and the upper limit are valid indexes in the array. If the parameter `fromWhere` is smaller than 0, the lower limit becomes 0 instead. Accordingly, if the parameter `toWhere` is larger than the size of the array, the upper limit becomes the last index of the array instead. @@ -161,18 +139,18 @@ System.out.println(sum(numbers, -1, 999, -10, 10)); - + Arrays can be used in the exact same manner as other variables, so they can be object variables, method parameters, return values of methods, and so on. - + A significant portion of generally used data structures use arrays in their internal implementation. ## Lists - + Let's examine one way to implement the Java ArrayList data structure. Java ArrayList uses an array. The type of the elements in the array is defined by the type parameter given to the ArrayList. Due to this we can add nearly any type of data to a list. Java List offers multiple methods, but right now `add`, `contains`, `remove` and `get` are most relevant for us. @@ -197,7 +175,7 @@ false ### Creating a new list - + Let's create class `List`. The List has a generic array -- the type of the elements in the array is defined on run time using type parameters. Let's set the size of the array to `10`. The array is created as type object, and changed to type generic with `(A[]) new Object[10];` -- this is done because Java does not support the call `new A[10];` for now. @@ -213,13 +191,13 @@ public class List { } ``` - + List encapsulates an array. In the beginning, every element in the array contains a `null`-reference. ### Adding values to the list - + Let's add the method `public void add(A value)`, which enables adding values to the list. We have to add an int variable to keep track of the first empty index in the array. @@ -241,7 +219,7 @@ public class List { } ``` - + Now we can add values to the list -- or at least we can create a list and call the add method. We cannot test if the values are actually saved to the list yet. ```java @@ -252,7 +230,7 @@ myList.add("world"); ### Adding values to a list part 2 - + There is a small problem with the `add` method. The problem occurs when the following code is run: @@ -269,13 +247,13 @@ Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10 at dataStructures.Program.main(Program.java:8) - + The size of the list does not grow. One of the benefits of the `ArrayList` class is, that it grows as needed -- programmers do not have to worry about the list getting full. - + Let's add the functionality for increasing the size of the List. The size of the List increases if user tries to add a value to a full list. The size of the List is increased by creating a new, larger, array to which the values from the old array are copied to. After this the old array is abandoned and the List starts to use the new array. - + The size of the array is determined in Java with the formula `oldSize + oldSize / 2`. Let's use the same formula in our implementation. We'll create a new method `grow` for increasing the size of the array. The method is available only for other methods in the class (it is `private`). @@ -291,11 +269,11 @@ private void grow() { } ``` - + The implementation creates a new array whose size is 1.5 times the size of the old array. After this all the elements of the old array are copied into the new one, and finally the value of the object variable `values` is set to the new array. The automatic Java garbage collector removes the old array at some point, now that there are no longer any references to it. - + Let's modify the `add` method so that the size of the array grows when needed. @@ -310,15 +288,15 @@ public void add(Type value) { } ``` - + Now we can add almost unlimited amount of elements to the List. - + The method described above copies every element from the old array to the new array. If we would have for example two million elements in an array, we must go through two million elements while copying them. - + We will discuss the effectiveness of this method -- and ways to make it more effective -- in the courses Datastructures and Algorithms and Design and analysis of algorithms. @@ -326,10 +304,10 @@ We will discuss the effectiveness of this method -- and ways to make it more eff ### Checking the existence of a value - + Next we'll create the method `public boolean contains(Type value)`, which we use to check whether the List contains a value or not. We will make use of the fact that each Java object -- no matter its type -- inherits the Object class (or is type Object). Due to this, each object has the method `public boolean equals(Object object)`, which we can use to check equality. - + The variable `firstFreeIndex` contains the number of elements in the array. We can implement the `contains` method so, that it only checks the indexes in the array which contain a value. ```java @@ -344,7 +322,7 @@ public boolean contains(Type value) { } ``` - + We can now inspect the elements in the List. ```java @@ -361,16 +339,16 @@ true - + The method above assumes, that the user will not add a `null` reference to the list, and that the equals method checks that the value given to it as a parameter is not null. ### Removing a value - + We can now add values to the List, and check if the List contains a value. Now we will implement the functionality for removing a value from the List. Let's implement the method `public void remove(Type value)`, which removes *one* value type `value`. - + Simple implementation would be as follows: ```java @@ -385,10 +363,10 @@ public void remove(Type value) { } ``` - + The above implementation is however problematic, because it leaves "empty" slots to the List, which would lead to the contains method not working. - + ```java public void remove(T value) { @@ -404,10 +382,10 @@ public void remove(T value) { } ``` - + We are not really satisfied with the solution above, because it does too many things at the same time. The method looks for an element and moves elements around. We will split the functionality into two methods: `private int indexOfValue(Type value)`, which searches for the index of the value given to it as a parameter, and `private void moveToTheLeft(int fromIndex)`, which moves the elements above the given index to the left. - + First let's implement the method `private int indexOfValue(Type value)`, which searches for the index of the given value. The method returns -1 if the value is not found. ```java @@ -422,7 +400,7 @@ private int indexOfValue(Type value) { } ``` - + Then we will implement the method `private void moveToTheLeft(int fromIndex)`, which moves values from the given index one place to the left. ```java @@ -433,7 +411,7 @@ private void moveToTheLeft(int fromIndex) { } ``` - + Now we can implement the method `remove` using these two methods. ```java @@ -451,16 +429,16 @@ public void remove(Type value) { - + The method describes above copies each element after the removed element one place to the left. Think about the effectiveness of this method when the List is used as a queue. - + We will discuss the effectiveness of this method -- and ways to make it more effective -- in the courses Datastructures and algorithms and Design and analysis of algorithms. - + The class List now contains some repeated code. The method `contains` is very similiar to the method `indexOfValue`. Let's modify the method `contains` so that it uses the method `indexOfValue`. @@ -470,7 +448,7 @@ public boolean contains(Type value) { } ``` - + Now we have a List, which has the methods `add`, `contains`, and `remove`. The List also grows in size when needed. The implementation of the List could of course be improved by for example adding functionality for decreasing the size of the List if the number of values in it decreases. ```java @@ -493,7 +471,7 @@ false ### Searching from an index - + Let's add method `public Type value(int index)`, which returns the value in the given index of the List. If the user searches for a value in an index outside of the Array, `IndexOutOfBoundsException` is thrown. ```java @@ -506,7 +484,7 @@ public Type value(int index) { } ``` - + This method would be easier to use, if the user had information about the indexes of the values. Let's modify the method `indexOfValue(Type value)` so it can be used by everyone, so it is `public` instead of `private`. ```java @@ -546,7 +524,7 @@ false ### Size of the List - + Lastly we will add a method for checking the size of the List. The size of the list can be determined by the variable `firstFreeIndex`. @@ -556,7 +534,7 @@ public int size() { } ``` - + Now we can use a for-loop to go through the elements of the list. @@ -580,61 +558,38 @@ world - + Following the example above, implement a class `List`. This exercise has no tests -- test your class using the examples in the material and your own tests. This exercise is worth 2 points. - + ## Hash map - + Hash map is implemented as an array, in which every element includes a list. The lists contain (key, value) pairs. The user can search from the hash map based on the key, and they can also add new key-value pairs into it. Each key can appear at most once in the hash map. - + The functioning of the hash map is based on the hash value of the key. When a new (key, value) pair is stored in a hash map, we calculate a hash value based on the key to be stored. The hash value decides the index of the internal array that will be used for storing. The (key, value) pair is stored in the list that can be found at that index. - + Let's sketch out how a hash map functions. ### Key-value pair - -Let's start by creating the class `Pair` that represents a key-value pair. We want to make the hash map as general as possible, so the types of the key and the value are determined at run-time. The Pair class contains a key and a value, as well as the related get methods. The generic types K and V are named so after the words 'key' and 'value'. - - - ```java public class Pair { @@ -661,25 +616,18 @@ public class Pair { } ``` - + Creating key-value pairs is straightforward. - + ```java Pair pair = new Pair<>("one", 1); System.out.println(pair.getKey() + " -> " + pair.getValue()); ``` - @@ -688,27 +636,16 @@ one -> 1 - + ### Creating a hash map - -A hash map contains an array of lists. Each value on the list is a pair (described in the previous section) that contains a key and a value. A hash map also knows the number of the values. Here we have at our disposal the previously created class `List`. +A hash map contains an array of lists. Each value on the list is a pair (described in the previous section) that contains a key and a value. A hash map also knows the number of the values. Here we have at our disposal the previously created class `List`. - ```java public class HashMap { @@ -724,41 +661,24 @@ public class HashMap { ``` - + ### Retrieving a value - + Let's implement a method called `public V get(K key)`. It can be used to search for a value based on a key. - -The method begins by calculating a hash value for the key, and using it to figure out which is the relevant index of the internal array of the hash map. The hash value is calculated with the `hashCode` method that each object has. Then modulo (remainder of division operation) is used for ensuring that the index stays within the size boundaries of the internal array. - +The method begins by calculating a hash value for the key, and using it to figure out which is the relevant index of the internal array of the hash map. The hash value is calculated with the `hashCode` method that each object has. Then modulo (remainder of division operation) is used for ensuring that the index stays within the size boundaries of the internal array. -If there is no list in the calculated index, no key-value pairs have been added to that index. This means that there are no key-value pairs with this key that have been stored. In this case we'll return the `null` reference. Otherwise, the program goes through the list at the index, and we compare the parameter key to the key of every key-value pair on that list. If some of the keys matches the parameter key, the method returns the value of that key-value pair. Otherwise we cannot find a suitable key (and related value), so the method returns the value null. - ```java public V get(K key) { @@ -782,59 +702,35 @@ public V get(K key) { - + The main principle of the hash map is that the key-value pairs are divided into small sets with the help of hash values. In this case a search based on key demands only going through a very small number of key-value pairs -- assuming that the hash values are calculated in a sensible manner. - + If the hash value is always the same -- e.g. 1 -- the internal implementation of a hash map is similar to a list -- all the values are on the same list. If the hash values are sufficiently random, the different values are as evenly distributed to the different lists as possible. - + Hash maps also grow the size of their internal array if the number of values becomes large enough (typically 75% of the size of the array). Typically a hash map that contains millions of key-value pairs only contains a few key-value pairs in each index. The practical consequence is that discovering if a key-value pair exists, we only need to calculate the hash value and examine a few objects -- this is very significantly faster than going through a single list that contains the entirety of stored values. - + ### Adding to hash map - -Let's implement the first version of the method `public void add(K key, V value)`, which is used to add values to the hash map. In this version we are not going to increase the size of the internal array when new values are added to the hash map. - +Let's implement the first version of the method `public void add(K key, V value)`, which is used to add values to the hash map. In this version we are not going to increase the size of the internal array when new values are added to the hash map. -The method first calculates the hash value for the key, and uses it to determine the suitable index in the internal array. If there is no value in that index, we create a list into that index. After this the method goes through the list at the index, and looks for a key-value pair whose key matches the key of the key-value pair to be added. If the matching key is found, the value related to it is updated to match the new value. Otherwise the method adds a new key-value pair in the list -- in which case the number of stored values is also incremented by one. - ```java public void add(K key, V value) { @@ -862,31 +758,12 @@ public void add(K key, V value) { } ``` - -The method is quite complex, so let's divide it into smaller parts. The first part is responsible for finding the list related to the key, and the second part is responsible for finding the key on that list. +The method is quite complex, so let's divide it into smaller parts. The first part is responsible for finding the list related to the key, and the second part is responsible for finding the key on that list. - ```java private List> getListBasedOnKey(K key) { @@ -909,24 +786,12 @@ private int getIndexOfKey(List> myList, K key) { } ``` - + Now we can write a somewhat clearer implementation of the method `public void add(K key, V value)` - ```java public void add(K key, V value) { @@ -943,36 +808,23 @@ public void add(K key, V value) { ``` - + ### Adding to hash table, part 2 - + The way of adding to a hash table that was described above works partly. The greatest fault in the functionality is that the size of the internal array is not increased when the number of values grows too large. Let's add a growing functionality to the program that doubles the size of the internal array of the hash map. The growing operation should also place each value in the hash map into the newly created bigger array. - + Let's sketch the beginning of the growing functionality. The responsible method should create a new array whose size is double that of the old array. After this it goes through the old array, index by index. The encountered key-value pairs are copied into the new array. Finally, the old array is replaced with the new one. - -Below there is a first version of how the method should work. We haven't implemented the copying yet. - ```java private void grow() { @@ -989,25 +841,12 @@ private void grow() { } ``` - + Then let's begin to create a method that copies the list of values at one index of the old array into the new one. When copying, the location of each key-value pair is recalculated for the new array -- this is done because the size of the internal array grows, and we want to distribute all the key-value pairs in that array as evenly as possible. - ```java private void copy(List>[] newArray, int fromIdx) { @@ -1026,25 +865,12 @@ private void copy(List>[] newArray, int fromIdx) { - -Now you can call the copy method from the grow method +Now you can call the copy method from the grow method - ```java private void grow() { @@ -1061,28 +887,12 @@ private void grow() { } ``` - -Finally, let's add the growing functionality to be a part of the `add` method. We want to grow the size of the hash map if the number of key-value pairs in it is greater than 75% of the size of the internal array. +Finally, let's add the growing functionality to be a part of the `add` method. We want to grow the size of the hash map if the number of key-value pairs in it is greater than 75% of the size of the internal array. - ```java public void add(K key, V value) { @@ -1103,36 +913,20 @@ public void add(K key, V value) { ``` - + ### Remove - + Let's give the hash map the functionality to remove a key-value pair based on key. The removal functionality returns null if the value cannot be found, and otherwise it will remove the value that is paired with the key to be removed. - -We can take advantage of the method we've already implemented in the removing method. Explain to yourself (out loud) how the method described below concretely works. - ```java public V remove(K key) { @@ -1154,57 +948,22 @@ public V remove(K key) { - + Implement the class HashMap in the exercise base, following along the lines of the previous example. Unlike the example, implement the class so that it uses the ready-made Java class ArrayList in its internal implementation. There are no tests in the exercise base -- test its functionality with the examples in the material, and with your own experimentation. This exercise is worth three points. - - -## On search performance - - -Let's compare the performance of searching from a list or a hash map. To evaluate performance we can use the `System.nanotime()` method and the value it returns, which represents the time as nanoseconds. The program first creates a hash map and a list, each containing a million elements, after which a thousand randomly chosen values are chosen from both. Roughly 50 % of the values are found with both structures. - ```java List myList = new List<>(); @@ -1250,6 +1009,6 @@ Hash map: the search took about 0 milliseconds (805106 nanoseconds.) - + *The list and hash map that are described in this chapter do have some differences from the readymade tools we use elsewhere in the course. The data structures offered by the programming language have more different kinds of optimizations -- other courses go more in detail with these specifics. For the purposes of this course it's enough to know how to use the data structures and to have some idea of the performance differences and when they are suitable to use.* diff --git a/data/part-12/3-randomness.md b/data/part-12/3-randomness.md index 77f0c388d..5893c5a8d 100644 --- a/data/part-12/3-randomness.md +++ b/data/part-12/3-randomness.md @@ -7,14 +7,14 @@ hidden: false - - + + - Know how to generate random numbers, and know some situations where random numbers are needed. - Can use Java `Random` class to generate random numbers. - + Encryption algorithms, machine learning and making computer games less predictable all require randomness. We can model randomness using random numbers. Java offers ready-made `Random` class for creating random numbers. An instance of the Random class can be used as follows: @@ -36,10 +36,10 @@ public class Raffle { } ``` - + Above we create an instance of the `Random`class. It has `nextInt` method, which gets an integer as a parameter. The method returns a random number between `[0, integer[` or *0..(integer -1)*. - + The program output is not always the same. One possible output is the following: @@ -58,23 +58,14 @@ The program output is not always the same. One possible output is the following: - + - + Write a program that prompts the user for how many random numbers should be generated and then prints the numbers. The printed numbers should be within the range `[0, 10]`. Below are some examples. - @@ -88,20 +79,7 @@ How many random numbers should be printed? - @@ -121,7 +99,7 @@ How many random numbers should be printed? - + We can use the `nextInt` method to create diverse randomness. For example, we might need a program to give us a temperature between [-30,50]. We can do this by first creating random a number between 0 and 80 and then subtracting 30 from it. @@ -133,30 +111,13 @@ int temperature = weatherMan(81) - 30; System.out.println(temperature); ``` - - - -The exercise template contains a class `Die`, which has the following body: + - ```java import java.util.Random; @@ -177,25 +138,15 @@ public class Die { } ``` - + Modify the class, such that the constructor `Die(int numberOfFaces)` creates a new die-object with the given number of faces (i.e. the number of "sides" with a number). Also, modify the method `throwDie` so it returns the result of a random throw of the die, which should be a value withing the range `1 ... number of faces`. - + The following is a main program for testing the die: - ```java public class Program { @@ -209,7 +160,7 @@ public class Program { } ``` - + The output could be as follows: @@ -230,10 +181,10 @@ The output could be as follows: - + A Random object can also be used to create random doubles. These can for example be used for calculating probabilities. Computers often simulate probabilities using doubles between [0..1]. - + The `nextDouble` method of the Random class creates random doubles. Let's assume the weather follows these probabilities: @@ -241,7 +192,7 @@ Let's assume the weather follows these probabilities: - There is 0.3 probability it snows (30%) - There is 0.6 probability the sun shines (60%) - + Let's create a weather forecast using these probabilities. ```java @@ -273,7 +224,7 @@ public class WeatherMan { } ``` - + The `makeAForecast` method is interesting in many ways. The `this.random.nextGaussian()` call is a regular method call. However what is interesting is that this method of the `Random` class returns a normally distributed number (normally distributed numbers can be used to for example model the heights and weights of people -- if you are not interested in different kinds of randomness that is OK!). ```java @@ -282,11 +233,11 @@ public int makeAForecast() { } ``` - + In the previous example we use explicit type casting to convert doubles to integers `(int)`. We can equally convert integers to doubles with `(double) integer`. - + Let's now add a main which uses the `WeatherMan` class. ```java @@ -319,7 +270,7 @@ public class Program { } ``` - + The program output could be: @@ -335,69 +286,39 @@ Sun: The sun shines -5 degrees - + - + Your assignment is to complete the class `LotteryRow`, which is used to draw the week's winning numbers. The numbers are in range 1--40, and 7 numbers will be drawn in total. In other words, a lottery row consists of seven different numbers that are all in range 1--40. - + We wish to implement the following functions in the class: - + - the constructor `LotteryRow` creates a new LotteryRow object that contains new randomized numbers. - + - the method `numbers` returns the drawn lottery numbers of this lottery row - -- the method `containsNumber` tells whether the given number is included in the drawn numbers - +- the method `containsNumber` tells whether the given number is included in the drawn numbers -- the method `randomizeNumbers` randomizes new numbers for the lottery row. - -The basic structure of the class is as follows: - - ```java import java.util.ArrayList; @@ -431,28 +352,12 @@ import java.util.Random; } ``` - - -The following main program is supplied in the exercise base: - ```java import java.util.ArrayList; @@ -472,17 +377,12 @@ public class Program { } ``` - -Here are a few possible outputs of the program: +Here are a few possible outputs of the program: - @@ -491,12 +391,7 @@ Lottery numbers: - @@ -505,7 +400,7 @@ Lottery numbers: - + **NB!** The same number can only appear once in a lottery row. The numbers don't need to be ordered. @@ -514,23 +409,23 @@ Lottery numbers: - + We can predict how computers work, because they slavishly execute any command we give them. Is a random number generated by a computer then really random? - + Random numbers used by computer programs are typically pseudorandom. They seem like random numbers, but in reality they follow some algorihmically created series of numbers. Most of the time pseudorandom is good enough -- for example the user will not notice any difference when YouTube random play is pseudorandom. On the other hand if random numbers are used for scientific calculations, using a weak pseudorandom number generator can lead to questionable results. One example is IBM's RANDU which was used for a short while in the 1960's.
- + All randomness in computer programs is not pseudorandom. Programs aiming for stronger randomness use, among other things, real life random phenomena to generate random numbers. For example space radiation or lava lamps are thought to be random phenomena.
- + You can read more about randomness from https://www.random.org/randomness/.
diff --git a/data/part-12/4-multidimensional-data.md b/data/part-12/4-multidimensional-data.md index 5b9282ad9..0c91e1e12 100644 --- a/data/part-12/4-multidimensional-data.md +++ b/data/part-12/4-multidimensional-data.md @@ -6,19 +6,19 @@ hidden: false - - + + - Know ways to represent multidimensional data - Can create and use multidimensional arrays - + Previously we have used one dimensional arrays, where the index tells us the location of a value in the only dimension. We can also create multidimensional arrays. Then we need the indexes of a value in each dimension to access the value. This comes handy when our data is multidimensional, for example when dealing with coordinates. - + A two dimensional array with two rows and three columns can be created like so: @@ -28,7 +28,7 @@ int columns = 3; int[][] twoDimensionalArray = new int[rows][columns]; ``` - + In the array we created above, each row refers to an array with a certain number of columns. We can iterate over a two dimensional array using two nested for loops like so: @@ -46,7 +46,7 @@ for (int row = 0; row < twoDimensionalArray.length; row++) { } ``` - + The program output is as follows: @@ -61,10 +61,10 @@ row, column, value - + We can see that the default value of variables type `int` is 0. - + We can change the values in the array just like before. Below we set new values to three elements of the array. @@ -86,7 +86,7 @@ for (int row = 0; row < twoDimensionalArray.length; row++) { } ``` - + The program output is as follows: @@ -103,27 +103,19 @@ row, column, value - + - + Create in the exercise base a method called `public static String arrayAsString(int[][] array)`. It should create a string representation of the array it receives as the parameter and return it. - + Brush up on using StringBuilder in part 10.3 before taking on this exercise. Below there are a few examples of how the method is expected to work. - + ```java int rows = 2; @@ -142,15 +134,7 @@ System.out.println(arrayAsString(matrix)); - ```java int[][] matrix = { @@ -173,30 +157,30 @@ System.out.println(arrayAsString(matrix)); - + - + Magic squares are squares composed of integers, where the sum of each row, column, and diagonal is the same. Let's practice our array skills and play around with magic squares.
- + In the exercise base there is a partially implemented class called `MagicSquare` that we can use as a basis for our program. Your assignment is to first add functionality to the class so that it can check whether a given square is magical. After this you'll implement an algorithm for creating a magic square. - +

Sums of rows

- + In the class MagicSquare there is already a method called `public ArrayList sumsOfRows()`, which returns an empty ArrayList object. Change the functionality of the method so that it returns a list of sums of every row of the (magic) square. - + For example, with the following magic square the `sumOfRows` method should return a list that contains the integers `15, 15, 15`. @@ -206,7 +190,7 @@ For example, with the following magic square the `sumOfRows` method should retur 4 9 2 ``` - + Even if the magic square is not a "legitimate" magic square, the sums of the rows should still be returned. With the input below, the `sumsOfRows` should return a list with the integer contents `6, 15, 24`. @@ -217,15 +201,15 @@ Even if the magic square is not a "legitimate" magic square, the sums of the row ``` - +

Sums of columns

- + There already exists a stub for the method `public ArrayList sumsOfColumns`. At the moment it only returns an empty ArrayList object. Change the functionality of the method so that it returns a list that contains the sums of every column of the magic square. - + As an example, when receiving the following magic square the sumsOfColumns should return a list that contains the integers `15, 15, 15`. @@ -235,7 +219,7 @@ As an example, when receiving the following magic square the sumsOfColumns shoul 4 9 2 ``` - + Even if the magic square is not a "legitimate" magic square, the sum of columns should be returned. In the example below, the sumsOfColumns method should return a list that contains the integers `12, 15, 18`. @@ -247,15 +231,15 @@ Even if the magic square is not a "legitimate" magic square, the sum of columns ``` - +

Sums of diagonals

- + Next, implement the method `public ArrayList sumsOfDiagonals()` that returns a list with the sums of the diagonals of a magic square. - + With the following magic square, for instance, the method should return a list with the contents `15, 15` (8 + 5 + 2) and (4 + 5 + 6). @@ -265,7 +249,7 @@ With the following magic square, for instance, the method should return a list w 4 9 2 ``` - + Even if the square is not a "legitimate" magic square, the sums of the diagonals should still be returned. With the square below, the sumsOfDiagonals should return a list with the integer contents `(15, 15)` (1 + 5 + 9) and (7 + 5 + 3). @@ -276,43 +260,43 @@ Even if the square is not a "legitimate" magic square, the sums of the diagonals ``` - +

Conjuring a magic square

- + NB! This part might be quite tricky, so you might want to return the previous sections before beginning it. - + It's also possible to create magic squares of your own. Let's familiarize ourselves with the Siamese method. It can be used to create magic squares that have an odd size (as opposed to even).
- + The Siamese method algorithm works in the following manner. You set number one to the centermost column of the top row. After this, we move one row up and one column right, and place number two in this cell. We continue by moving one right, one up, and placing the number 3, etc. - + Two rules govern the number placements: - + 1. If the transition would leave us outside the bounds of the magic square, we jump to the opposite edge. In other words, if we go "over the right edge" we continue from the left edge, and if we go "over the top edge" we continue from the bottom. - + 2. If the place already contains a number, we don't go up and right. Instead we take one step downwards. - + Check the visualization for the described algorithm on the Wikipedia page Siamese method.
- + Implement in the class `MagicSquareFactory` the method `createMagicSquare`. It should return a magic square whose side has the length that is specified as the parameter. The method only needs to work in cases where the width of the square is an odd integer. @@ -321,11 +305,11 @@ Implement in the class `MagicSquareFactory` the method `createMagicSquare`. It s - + We can implement the same functionality using a hash table. Wouldn't a hash table be a better option, since we do not have to worry about increasing its size at any point? - + When we search for a value of a key from a hash table, we use the hashCode method to find the index to search from. There can be multiple values at the same index (on a list). Then we have to compare the key we want to find the value for to the key of each key-value pair on the list using the equals method. @@ -333,12 +317,12 @@ When we search for a value of a key -- or index -- in an array, we do not have t An array either contains a certain value or it does not, so there is a small performance beneft on using arrays. - + This performance benefit comes with some added workload and proneness to errors. Hash tables have tested and proven functionality for increasing the size of the table. Arrays do not come with this benefit, and when implementing a new functionality we might cause errors which increases the workload. However, errors are accepted and natural part of software development. - + When we consider the memory usage, hash tables might -- in some situations -- have some benefits. When an array is created, enough memory for the whole array is allocated for it. If we do not have values in each element of the array, some of the memory stays unused. @@ -347,4 +331,4 @@ With hash tables this does not happen -- the size of the hash table is increased - + diff --git a/data/part-12/index.md b/data/part-12/index.md index 8e8c90941..83c5cf727 100644 --- a/data/part-12/index.md +++ b/data/part-12/index.md @@ -5,7 +5,7 @@ overview: true hidden: false --- - + In the twelfth part of the course we will introduce type parameters and you will learn what `ArrayList;` actually means. You will learn to implement classes that use type parameters. You will get to understand how ArrayList and HashMap are implemented, and you will implement your own versions as well. You will learn how to create random numbers, and practice using some Java tools to create random numbers. You will learn how multidimensional data can be presented, and how to use multidimensional arrays. diff --git a/data/part-13/1-graphical-user-interfaces.md b/data/part-13/1-graphical-user-interfaces.md index 64d7d1b32..b43683c6e 100644 --- a/data/part-13/1-graphical-user-interfaces.md +++ b/data/part-13/1-graphical-user-interfaces.md @@ -4,20 +4,16 @@ title: 'Graphical user interfaces' hidden: false --- - + - + - You know what user interfaces (UIs) consist of and know how to launch a graphical user interfaces (GUIs). - We'll now take a look at creating graphical user interfaces (GUIs). When creating graphical user interfaces, we mostly make use of user-interface libraries that provide us with ready-made components, such as buttons and text areas. These user-interface libraries take care of the drawing the components for us, meaning that we don't have to draw every single component in our program, only add them to it. @@ -26,55 +22,35 @@ Whereas text interfaces have the functionality coupled to a particular form of i We'll be using Java's [JavaFx] (https://en.wikipedia.org/wiki/JavaFX) user-interface library to create our graphical user interfaces. The applications we develop are desktop applications.
- + - + A library called JavaFX is used to create graphical user interfaces. On Linux machines, you may have to install the openjfx library -- depending on how Java's installed. You can install this in Ubuntu (from the command line) with the command: - + ```bash user@computer:~$ sudo apt-get install openjfx ``` - + A test library called [TestFX] (https://github.com/TestFX/TestFX/wiki) is used in the exercise templates to test JavaFx programs. This library is included in the templates. - + - + Some of the tests in this section assume that tmcbeans is able to freely move the cursor around the screen. On macOS (Apple computers), tmcbeans has to be granted this right explicitly. Here are instructions on how to grant this right: [macOS help] (/macos help) - -We can create a simple window using JavaFX with the following program. - - ```java package application; @@ -96,63 +72,32 @@ public class JavaFxApplication extends Application { ``` - + When the program is launched, it looks as follows. - + Empty window with a 'Hello World' title When the launch method is called, the method of the Application class creates a new object from the given class (here JavaFxApplication) and calls its init method. The init method is defined in the Application class and is used, for instance, to initialize objects of a program. After calling the init method, the program calls the start method, which gets a [Stage] (https://docs.oracle.com/javase/8/javafx/api/javafx/stage/Stage.html) object as its parameter, which describes the window. In the implementation of the start method above, the setTitle method sets the title of the Stage-type window object obtained as a parameter. The method show is then called, which leads to the window being displayed. The program then stays in a state where it continuously listens to events on user interface, such as closing the window that causes the application to shut down. - + Create a GUI app with the title "My first application". The app should start when the main method is executed. - + ## Structure of a User Interface - Graphical user interfaces consist of three essential parts. The Stage object behaves as the program's window. A [Scene] (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Scene.html) is set for a Stage object that represents a scene within the window. The Scene object, on the other hand, contains an object responsible for arranging the components belonging to the scene (such as FlowPane), which contains the actual user interface components. The program below creates an interface with a single button. - ```java package application; @@ -184,18 +129,14 @@ public class JavaFxApplication extends Application { } ``` - + The application looks like this. - -A window, which has a button. The button contains the text 'This is a button'. +A window, which has a button. The button contains the text 'This is a button'. - UI components are added as "children" to the object responsible for setting them -- FlowPane. This has to do with a JavaFx design decision, whereby each object responsible for UI components may contain other objects responsible for UI components as well as actual UI components. This enables GUIs where the layout of the UI components depends on their location on the user interface. For example, menu items located at the top of a UI are usually placed side by side, while list items are placed one below the other. diff --git a/data/part-13/2-UI-components-and-layout.md b/data/part-13/2-UI-components-and-layout.md index f08c158fd..c86134716 100644 --- a/data/part-13/2-UI-components-and-layout.md +++ b/data/part-13/2-UI-components-and-layout.md @@ -6,20 +6,18 @@ hidden: false - + - You are aware of some interface components and know how to add them to a user interface. - You're familiar with methods for configuring user interface components. - + Programmers typically use ready-made libraries for implementing graphical user interfaces. As an example, it would not make much sense to implement a button from scratch (which would require creating a class that draws a button and handles all of its functions) since pre-built button components can usually be found in existing libraries. Let's take a look now at some UI components. - + Text can be displayed using the [Label](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/Label.html) class. The Label class provides a UI component for which text can be set, and offers methods for modifying the text it contains. The displayed text is either set in the constructor, or by using the `setText` method. @@ -53,11 +51,11 @@ public class JavaFxApplication extends Application { } ``` - + Window with a textComponent. The window shows the text 'Text element'. - + Buttons can be added using the [Button](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/Button.html) class. Buttons are added the same way as labels. @@ -94,7 +92,7 @@ public class JavaFxApplication extends Application { Ikkuna, jossa on nappi. Napissa on teksti 'This is a button'. - + You also have the ability to add multiple components at once. In the example below, both a button and a textComponent have been added. @@ -132,31 +130,31 @@ public class JavaFxApplication extends Application { ``` - + The application looks like this: Ikkuna, jossa on nappi sekä textComponent. Napissa on teksti 'This is a button' ja textComponent sisältää tekstin 'Text element'. - + You can find a list of the available UI components on [https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/](https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/). The site also provides examples on how to use them. - + There is a considerable amount of different UI components. Using online materials, such as the one linked above, is a good way to learn about them. When staring out, components should be tried out in isolation by adding a single component at a time and inspecting how it works. - + As you become more familiar with the various components, using them becomes more straightforward. What's common to almost all of the components is the way that they're added to an interface - once you know how to add one, you can add almost any component to your interface. - + The biggest difference in adding components is where they're placed on the interface. You'll soon learn more about the lay these components out. - + Following the example above create a user interface containing a Button and a Label to the class in the exercise template. The Label must be either on top or on the left side of the Button. @@ -165,68 +163,36 @@ The Label must be either on top or on the left side of the Button. - + Create a graphical user interface to the class in the exercise template. The interface must contain a button and a text field. The text field can be implemented using the [TextField](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TextField.html) class. The Button must be on the left or on the top of the text field. - + Create a graphical user interface in the class that is supplied with the exercise base. It should contain a button and a text field. You can implement the text field with the help of the [TextField](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TextField.html) class. The button should be placed above or to the left of the text field. - + ## UI Component Layout - Each UI component has its place on the interface. The location of a component is determined by the class used to layout the components. In previous examples, we used a class called [FlowPane] (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/FlowPane.html) to set up our front-end components. With FlowPane, components that you add to the interface are placed side-by-side. If the size of Window is reduced so that the components no longer fit next to eahch other, the components will be automatically aligned. In the image below, the application resulting from the previous example has been narrowed so that the components are automatically aligned. - + Window that has a button and a textComponent. The button has the text 'This is a button and the textComponent contains the text 'Text element'. The window's width is so narrow that the components are placed on seperate rows. ### BorderPane - -The [BorderPane] (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/BorderPane.html) class lets you lay out components in five different primary positions: top, right, bottom, left and center. Traditional applications such as the web browser you are using take advantage of this layout. There's a menu and address bar at the top, and in the middle is the content of the page. - - - ```java package application; @@ -259,14 +225,14 @@ public class JavaFxSovellus extends Application { } ``` - + A user interface using the BorderPane layout, which contains a textComponent in each primary location - + - + Create a graphical user interface in the class provided in the exercise template. It should use the BorderPane class for laying out the components of the user interface. Add a textComponent at the top edge of the window containing the text "NORTH", a textComponent along the right edge containing the text "EAST", and a textComponent at the bottom edge containing the text "SOUTH". @@ -275,25 +241,11 @@ Create a graphical user interface in the class provided in the exercise template ### HBox - -[HBox](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/HBox.html)-class enables UI components to be laid out in a single horizontal row. - - ```java @Override public void start(Stage window) { @@ -310,30 +262,15 @@ public void start(Stage window) { } ``` - -Text components have been placed in a row using the HBox layout. The components are attached to one another. +Text components have been placed in a row using the HBox layout. The components are attached to one another. - -As evident from the previous example, HBox by default completely glues the UI components to each other. We can use the setSpacing method to add space in between the components. - ```java @Override public void start(Stage window) { @@ -351,42 +288,26 @@ public void start(Stage window) { } ``` - + The components have been placed in a row using the HBox layout. There is a gap of 10 pixels between the components. - + The class [VBox](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/VBox.html) works in a similar way, but instead sets the components in a vertical column. - + The components have been placed in a column using the VBox layout. There is a gap of 10 pixels between the components.. ### GridPane - + The [GridPane](https://docs.oracle.com/javafx/2/api/javafx/scene/layout/GridPane.html) class can be used to lay the UI components in a grid. In the example below, we create a 3x3 row in which each cell contains a button. - ```java @Override public void start(Stage window) { @@ -404,66 +325,19 @@ public void start(Stage window) { window.show(); } ``` - - -3 times 3 grid containing 9 buttons. - - - -### Multiple Layouts ons a Single Interface - - -Layout components can be combined. A typical setup involves using the BorderPane layout as the base with other layouts inside it. In the example below, the top of the BorderPane contains a HBox used for horizontal layout and a VBox used for vertical layouts. A text box has been placed placed in the center. - - ```java package application; @@ -512,14 +386,14 @@ public class JavaFxSovellus extends Application { } ``` - + Multiple layouts have been used in a single interface. A BorderPane creates the frame, a HBox is at the top and a VBox on the left side. The text area in the center has some text written in it. - + - + Create an applicaton in the class provided in the exercise template. Use the BorderPane class for the layout. In the center there should be a text field created using the TextArea class, and along the bottom edge there should be three textComponents. Place the text components along the bottom edge into a HBox object.The first text component should have the text "Letters: 0", the second text component should have the text "Words: 0", and the third text component should have the text "The longest word is:". diff --git a/data/part-13/3-event-handling.md b/data/part-13/3-event-handling.md index b0055262b..1246d9adb 100644 --- a/data/part-13/3-event-handling.md +++ b/data/part-13/3-event-handling.md @@ -4,32 +4,24 @@ title: 'Event handling' hidden: false --- - + - + - You're familiar with the concept of an event handler and are able to handle user interface events. - + The user interfaces we've previously implemented have not been able to react to events in the user interface. This inability to react is not due to the components of the interface themselves, but due to the fact that we've yet to added any functionality that handles component events. - + Button presses are handled using a class that implements the [EventHandler](https://docs.oracle.com/javase/8/javafx/api/javafx/event/EventHandler.html) interface. The type of the event in these cases is [ActionEvent](https://docs.oracle.com/javase/8/javafx/api/javafx/event/ActionEvent.html). The interface implementation specifies *what is done* when a user presses a button. - + ```java Button button = new Button("This is a button"); @@ -41,16 +33,11 @@ button.setOnAction(new EventHandler() { }); ``` - + If desired, the explicit implementation of the interface can be replaced by a Lambda expression. - + ```java Button button = new Button("This is a button"); @@ -59,35 +46,19 @@ button.setOnAction((event) -> { }); ``` - + When the button is pressed, the program prints the text "Pressed!" to the console. - -**Event handlers** attached to user interface components, such as the EventHandler used previously, are always connected to specific user interface components. Whenever an action is performed on a user interface component, e.g., a button is pressed, each of the event handlers attached to that particular component is called and the functionality written for them is executed. - +**Event handlers** attached to user interface components, such as the EventHandler used previously, are always connected to specific user interface components. Whenever an action is performed on a user interface component, e.g., a button is pressed, each of the event handlers attached to that particular component is called and the functionality written for them is executed. -We often want an event handler to change the state of some object. To get hold of an object, the event handler needs a reference to it. Let's think about the following user interface which has two text fields and a button. - ```java @Override @@ -107,38 +78,18 @@ public void start(Stage window) { } ``` - + There is a text field on both the left and right hand sides of the user interface. In addition to these, there's a button in the middle with the text "Copy". - -Two text fields and a button with the text 'Copy'. +Two text fields and a button with the text 'Copy'. - -We'd like to have an application where the content of the left text field is copied over to become the content of the right text field when the user presses the button. This can be done with the help of an object implementing the EventHandler interface. - ```java @Override @@ -163,30 +114,30 @@ public void start(Stage window) { ``` - + Now pressing the button results in the content of the left text field being copied to the text field on the right. - + Two text fields and a button with the text 'Copy'. - + NB! The method implemented can use objects that were declared before the method definition, as long as the values of the objects being used are not reassigned using the equals operator, i.e., the references do not change. - + - + Create a user interface in the class included in the exercise template. It should contain three user interface components. The topmost is a text field (TextField), the middle one is a button (Button), and component on the bottom is a text component (Label). Lay out the components using the VBox class. The user interface should look kind of like the following. . - + Then add functionality to the application, where pressing the button leads to the text in the text field being copied as the value of the text component. In the example below we have written the message "hello world!" into the text field, after which we have pressed the button. @@ -196,21 +147,11 @@ Then add functionality to the application, where pressing the button leads to th - + The eventhandler being used depends on what kind of user interface component we attach it to. If we want to listen to changes made to a text field character by character, then we would use the interface [ChangeListener](https://docs.oracle.com/javafx/2/api/javafx/beans/value/ChangeListener.html). In the example below we have attached an object implementing the ChangeListener interface to text field on the left. This object prints the changes in the text field to the console as well as sets the new value into the text field on the right. - ```java leftText.textProperty().addListener(new ChangeListener() { @@ -225,17 +166,12 @@ leftText.textProperty().addListener(new ChangeListener() { ``` - + In the previous example the changes being observed are in the text of the text field. Beacause text is in string format we have provided string as the type for the handler interface. As before, we can also express this code in a more compact form. - + ```java leftText.textProperty().addListener((change, oldValue, newValue) -> { @@ -245,23 +181,11 @@ leftText.textProperty().addListener((change, oldValue, newValue) -> { ``` - + The program can also do statistics. Calculating the values for the text fields in the previous exercise is quite straightforward. Following the example below, the values would be updated every time the user changes the content of the text field. - ```java leftText.textProperty().addListener((change, oldValue, newValue) -> { @@ -278,16 +202,16 @@ leftText.textProperty().addListener((change, oldValue, newValue) -> { ``` - + - + Copy the work you did in the Text statistics exercise into the class included in the exercise template and add to it the functionality from the example above for calculating the statistics. The end result should an application that calculates statistics based on text that is input, which are updated automatically and displayed in the application. - + A example of the functionality of an application made for text statistics. diff --git a/data/part-13/4-launch-parameters.md b/data/part-13/4-launch-parameters.md index 4b691e002..180d0491d 100644 --- a/data/part-13/4-launch-parameters.md +++ b/data/part-13/4-launch-parameters.md @@ -4,36 +4,20 @@ title: "Application's launch parameters" hidden: false --- - + - + - You know how to pass parameters to a graphical user interface. - + The JavaFx applications in the examples have so far been launched by the main method of the class that inherits the Application class. Let's take a brief look at launching applications from outside of the `Application` class. Let's assume that we have the following simple JavaFx for our use. - ```java package application; @@ -50,24 +34,12 @@ public class JavaFxApplication extends Application { } } ``` - -The application can be launched from outside the class by using the `launch` method provided by the `Application` class. A separate class `Main` launches the application in the example below. +The application can be launched from outside the class by using the `launch` method provided by the `Application` class. A separate class `Main` launches the application in the example below. - ```java package application; @@ -80,12 +52,7 @@ public class Main { } } ``` - When the `main` method of the class above is executed, the user interface defined by the class `JavaFxApplication` is launched. @@ -93,26 +60,7 @@ The application can also be provided run-time parameters as part of the `launch` The `getParameters` method returns a [Parameters] (https://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.Parameters.html) type object whose method `getNamed` can access a hash table containing key-value pairs. The key-value pairs are given to the launch method in the form `--key = value`. In the example below, the title is made up of two parameters: `organization` and `course`. - ```java package application; @@ -134,26 +82,11 @@ public class JavaFxApplicationextends Application { } ``` - -Launching an application now with the following class sets the application's title to "Once upon a time: Title". - ```java package application; @@ -169,20 +102,17 @@ public class Main { } } ``` - + Parameters could be used to tell the program, for instance, the name of the file used to store and load persons, or even a web address. - + Write a program that asks for a title in a command line interface. When the user types the title and presses enter, the user is shown a graphical user interface with the given title. Notice, this exercise does not have automatic tests. Return the program once it works as described in the exercise. - diff --git a/data/part-13/5-multiple-views.md b/data/part-13/5-multiple-views.md index cc381f3dd..03f9292d5 100644 --- a/data/part-13/5-multiple-views.md +++ b/data/part-13/5-multiple-views.md @@ -4,13 +4,7 @@ title: 'Multiple views' hidden: false --- - @@ -20,11 +14,11 @@ hidden: false - + Thus far our graphical interfaces have always included only one view. Next, we'll become familiar with user interfaces containing multiple views. - + Generally the views are created as Scene-objects and the transitioning between them happens with events bound to the application. The example below has two Scene objects which both have their own content and an event related to the content. Instead of having an object for laying out components (such as BorderPane) in the example Scene objects, both objects have just one user interface component. @@ -67,42 +61,42 @@ public class BackAndForthApplication extends Application { ``` - + Starting the application above creates a user interface where one can transition from a view to another with the press of a button. - + - + There is a class called MultipleViews in the exercise template. Create in it an application that contains three separate views. The views are as follows: - + - The layout of the first view is done with the help of the BorderPane class. At the top there is the text "First view!". The center of the view contains a button with the text "To the second view!". By pressing that button the application swithces to the second view. - + - The layout of the second view is done with the help of the VBox class. The first element in the layout is a button with the text "To the third view!" in it -- by pressing the button the application switches to the third view. The button is followed by the text "Second view!". - + - The third view uses the GridPane class for its layout. At the coordinates (0, 0) there is a text that reads "Third view!". At coordinates (1, 1) there is a button with the text "To the first view!". Pressing this button brings back the first view. - + When first started, the program should display the first view. - + ## Own layout for each view - + Let's get familiar with an example containing two different views. In the first view user is asked to input a password. If the user types a wrong password, the application informs the user about the mistakee. If the user types the correct passwod, the application switches to the next view. The program functions as follows: @@ -110,7 +104,7 @@ Let's get familiar with an example containing two different views. In the first - + Switching between views happens like in the previous example. The concrete switching event has been bound to the login button. When pressing the button, the application checks the password typed to the password field -- here we're hoping that the user writes "password". If the password is correct, the view of the window is changed. In our example the view only includes the text "Welcome, this is the beginning!". @@ -192,20 +186,20 @@ public class PasswordProtectedApplication extends Application { ``` - + The example takes advantage of GridPane's and StackPane's built in setPrefSize and setAlignMents -methods for layout. Method setPrefSize takes the preferred size of the layout as and arguments and the setAlignMent-method is used to define how the content of the layout should be aligned. The parameter Pos.CENTER is used for asking the content to be placed to the center of the application - + - + In the exercise templare there is a class called GreeterApplication. Create in it an application with two views. The first view should have a text field that's used to ask for the user's name. The second view then shows the user a greeting text. The greeting should be of the form "Welcome name!" where the user's name is inserted in place of 'name'. - + An example of how the program should work: @@ -213,94 +207,19 @@ An example of how the program should work: - - -## Views with the same main alignment - - - -Sometimes one wants an application to have a permanent view whose parts are swapped when needed. Typically applications that have some kind of menus function in this manner. - - - -In the example below, there is a application which contains a main menu and an area with variable content. When pressing the buttons on the main menu the the content of the content area changes. - - ```java package application; @@ -378,25 +297,25 @@ public class ExampleApplication extends Application { ``` - + The program functions as follows: - + Application which contains a menu. By pressing the buttons in the menu on is able to change the content of the applivation. - + - + Use the class JokeApplication that is provided with the exercise template to create a program that explains a joke. The application offers a menu consisting of three buttons, and the contents that can be changed by clicking on these buttons. The first button (containing the text "Joke") shows a question that is related to a joke. The second button (text "Answer") show the related answer. The third and the final button ("Explanation") brings up the explanation for the joke. - + By default (when it starts) the program should show a joke-related question. Use the following string as the question: "What do you call a bear with no teeth?". The answer should be "A gummy bear." You can come up with a suitable explanation by yourself. @@ -404,16 +323,16 @@ By default (when it starts) the program should show a joke-related question. Use - + ## Separating application logic and user interface logic - + Keeping the application logic and user interface logic in the same class or in the same classes is usually a bad idea. It makes testing and editing the application considerably more difficult and also makes the source code harder to read. The principle "Each class should have only one clear responsibility" applies well here too. - + Let's inspect separating application logic from user interface logic. Let's suppose that we have an object using the following interface and we want to create a user interface for saving applications. @@ -431,47 +350,15 @@ public interface PersonWarehouse { } ``` - -When implementing a user interface a good starting point is drawing the interface followed bt adding appropriate user interface components to the user interface. When saving persons to a database we need a field for name, a field for social security number and a button for adding the person. In addition we'll also create - - - -Lets use `GridPane` class for the layout. There are 3 rows and 2 columns in the user interface. We'll add the event handling later. The initialization method is as follows: - - ```java @Override @@ -502,31 +389,15 @@ public void start(Stage window) { window.show(); } ``` - + Two text fields and a button - + Next lets add an object that implements the ActionEvent interface that adds field values to PersonWarehouse interface. - ```java @Override @@ -540,66 +411,11 @@ public void start(Stage window) { } ``` - - -But where do we get the actual PersonWarehouse-object? It is created at the beginning of the start method. Below is the code in whole. - - ```java @@ -655,59 +471,21 @@ public class PersonApp extends Application { ## A slightly larger application: Vocabulary practice - -Let's outline an application that can be used to practise vocabulary of a foreign language. The application offers two features to the user: entering words and their translations, and practising with the stored words. We'll create four different classes for the application: the first class offers the core logic, i.e. maintaining a dictionary; second and third classes contain the entering view and the practice view; and the fourth class contains the main menu and the functionality required to start the application. - - - - -### Dictionary - - - -The dictionary is going to be implemented with the help of a hash map and a list. The hash map contains the words and their translations, and the list is used to randomly choose the word for practice. The class has the necessary methods for adding a translation, for fetching a translation, and for drawing a random word. +Let's outline an application that can be used to practise vocabulary of a foreign language. The application offers two features to the user: entering words and their translations, and practising with the stored words. We'll create four different classes for the application: the first class offers the core logic, i.e. maintaining a dictionary; second and third classes contain the entering view and the practice view; and the fourth class contains the main menu and the functionality required to start the application. - ```java package application; @@ -750,80 +528,27 @@ public class Dictionary { ``` - - -You could also implement the Dictionary so that returning a random word would always generate a new list of words from the keys of the translations hash map. In such a case there would be no need to maintaing a separate list of words. However, this would have an effect on the performance of the program (or it would have had an effect before the turn of the millennium -- computers these days are a tad faster...). - - - - -### Entering new words - - - -Next we'll shape the functionality that's needed for entering words. In order for us to do that, we're going to need a reference to the dictionary object, and text fields for the word and its translation. The GridPane layout works well for the fields. Let's create a class called InputView. It contains the method getView that creates the view necessary for entering new words. This method should return a reference to a [Parent](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Parent.html) type object. Parent is a superclass to many classes, among them all the classes used for layouts. Therefore any layout class can be represented as a Parent object. - - - -The class also defines what happens when a button in the user interface is pressed. When the user clicks the button, the new word is added to the dictionary. The text fields are also cleared so that the next word can be entered. +You could also implement the Dictionary so that returning a random word would always generate a new list of words from the keys of the translations hash map. In such a case there would be no need to maintaing a separate list of words. However, this would have an effect on the performance of the program (or it would have had an effect before the turn of the millennium -- computers these days are a tad faster...). - ```java package applicatoin; @@ -881,80 +606,22 @@ public class InputView { ``` - - -### Vocabulary training - - - -Now we shall create the functionality to practise mastery of the stored words. We are going to need a reference to a dictionary object, so that we have a source for the words used for practice and so that we can check whether the translation is correct. In addition to the dictionary, we are going to need a text component that informs the user of which word to translate, and a text field where the translation can be placed. GridPane works well enough to handle the layout of the fields in this case, too. - - - - -The translated word at each time is an object variable of the class. The object variable can be used and changed also in the method that is defined in the context of an event handler. - - - ```java package application; @@ -1017,78 +684,16 @@ public class PracticeView { ``` - - -### Practice application - - - - -The practice application both unites the previously created classes and offers the main menu of the application. The structure of the practice application is as follows. - - ```java package application; @@ -1155,19 +760,19 @@ public class PracticeApplication extends Application { } ``` - + - + In this exercise you are going to create the previously described application to practise new vocabulary. The application should start when the main method of the VocabularyPracticeApplication is executed. - + Follow the previous example and create an application for practising translations. The application should offer two views. In the first view the user can enter words and their translations into the program. In the second view the user is asked to translate different words. The words to be translated should be randomly selected from among all the words that have been entered into the program. - + Let's discuss the user interface in more detail. The button that shows the input view should contain the text "Enter new words". The button that shows the practice view should contain the text "Practice". In the input view, the first text field should have the word in the original language, and the second text field should contain the translation of that word. The button that adds this word and the translation should read "Add the word pair". In the practice view the user is represented with a word in the original language, and their task is to write down the translation. If the answer is correct, the user interface displays the text "Correct!". If the answer is incorrect, the text that is displayed is "Incorrec!". In this case the correct translation is also shown. @@ -1175,33 +780,30 @@ Let's discuss the user interface in more detail. The button that shows the input - + There are no automatic tests in this project -- return your solution when the program works in the way described above. The model solution contains an initial sketch of a possible solution to create statistics. This is not essential for the purposes of this exercise, so there is no need to find these elements in your answer. - + - + In this exercise you will create a tic-tac-toe game of size 3x3. The assignment has been divided into three parts: first we create the parts of the user interface, then the funcionality of the buttons, and finally the option to play the game to conclusion. - + 3x3 tic-tac-toe - + NB! You can make the characters in the buttons to be equally large with a suitable font selection. The font that the buttons in the screenshot use has been set in the following manner: - + ```java Button btn = new Button(" "); @@ -1209,43 +811,43 @@ btn.setFont(Font.font("Monospaced", 40)); ``` - +

User interface

- + Modify the TicTacToeApplication class so that it starts the graphical user interface. First, use the BorderPane class to create the layout of the UI components. The top of the BorderPane should continue a text component that includes the information about the turn, and at the end of the game the message that the game has ended. Set to the middle of the BorderPane a GridPane that contains 9 buttons. The GridPane should have 3 rows and 3 columns, so that the buttons form a 3x3 grid. - +

Taking turns and fair play

- + The players of the game are X and O. X always takes the first turn. Add the following functionality to the buttons: when a button is pressed, the game updates so that symbol of the current player (X if it was X's turn when the button was pressed) is stored in the button. After this the other player gets their turn. - + The text component at the top of the game must always show whose turn it is. The text begins as "Turn: X". Once X playes their turn, i.e. presses a button, the text should change to "Turn: O". After the player O has played their turn, the text turns once again into "Turn: X". - + NB! If a player has already placed their symbol in a position, the other player cannot choose the same position. Make sure that the turn doesn't change if a player tries to choose a position that already contains a symbol. - + NB!! You might encounter the following error: "local variables referenced from a lambda expression must be final or effectively final". This is because objects instanced of interfaces cannot use variables that are defined outside of the method. You can avoid the error by creating new variables that you set the problematic values to just before using them in the method. - +

Finishing the game

- + Add the possibility to finish the game to the program. The game ends if one player positions three of their symbols in a line (horizontally, vertically, or diagonally). The end of the game should be indicated by the text "The end!" at the top of the program. It is no longer possible to continue the game after this. - + The tests of this exercise are not the most detailed ones. Try to create the program without relying on the tests too much. diff --git a/data/part-13/6-summary.md b/data/part-13/6-summary.md index e73f9dcba..323848014 100644 --- a/data/part-13/6-summary.md +++ b/data/part-13/6-summary.md @@ -4,9 +4,7 @@ title: 'Summary' hidden: false --- - In this part we took our first steps towards creating a graphical user interface. We learned to use program windows, add UI components and event handling. Altough we used the JavaFX library the principles of graphical user interfaces are the same in other libraris. We also learned event based programming. diff --git a/data/part-13/index.md b/data/part-13/index.md index 0bb0bf4c8..f524c6122 100644 --- a/data/part-13/index.md +++ b/data/part-13/index.md @@ -5,7 +5,7 @@ overview: true hidden: false --- - + The thirteenth part of the course material introduces the topics of creating graphical user interfaces and the kinds of components that are used in them. You will learn to handle different events that occur in graphical user interfaces, and practise creating applications that contain multiple views. @@ -14,7 +14,7 @@ The thirteenth part of the course material introduces the topics of creating gra - + diff --git a/data/part-14/1-data-visualization.md b/data/part-14/1-data-visualization.md index af2fac6e6..e705329e4 100644 --- a/data/part-14/1-data-visualization.md +++ b/data/part-14/1-data-visualization.md @@ -4,12 +4,10 @@ title: 'Data visualization' hidden: false --- - + - + - You are aware of data visualizations methods. - You know how to use Java's ready-made data visualization interface components. - You know a way to visualize information that changes dynamically. @@ -17,19 +15,17 @@ hidden: false - The adage "a picture is worth a thousand words" describes the goal of data visualization appropriately. Data visualization seeks to present information in a concise, yet comprehensible form. Visualizations can emphasize important points and provide the user with useful things, such as summaries of data. The image below shows an application that allows you to view statistics of cyclists. The statistics used have been taken from the the Helsinki City Planning Agency data set (CC-BY) found at [https://www.avoindata.fi/data/en/dataset/helsingin-pyorailijamaarat](https://www.avoindata.fi/data/en/dataset/helsingin-pyorailijamaarat).
- + cyclist data set visualization - + When comparing the statistics shown in the image to file format - a few lines have been shown below as an example - the benefits are evident. In the original data set the values ​​are presented on an hourly basis, whereas monthly summaries have been generated from the data for the visualization. The original set also contains all of the the places of inspection, whereas in the visualization the user is able to select a specific point. @@ -44,16 +40,10 @@ ke 1 tammi 2014 03:00;;2;;;;;;0;2;0;;7;;;5;3
- + Data that's in the format shown above can be processed as strings row by row. The rows are split into pieces that can be processed using a list structure. One way of doing this is the following. - + ```java String row = "Päivämäärä;Huopalahti (asema);Kaisaniemi;Kulosaaren silta et.;..." String[] pieces = row.split(";"); @@ -72,47 +62,38 @@ for (int i = 0; i < pieces.length; i++) { - + We'll familiarize ourselves with some patterns used in data visualization, and a technique for visualizing changing data. - + ## Charts - + Java offers [lots of pre-made classes](https://docs.oracle.com/javafx/2/api/javafx/scene/chart/package-summary.html) for drawing different types of charts. The types of charts include, among others, area charts, bar charts, and line charts. - + We are next going to take a look at using both a line and a bar chart. It might be worthwhile to also take a look at Oracle's guide on the subject, which can be found here: [https://docs.oracle.com/javafx/2/charts/jfxpub-charts.htm](https://docs.oracle.com/javafx/2/charts/jfxpub-charts.htm).
- + ### Line Chart - + Line charts can be used to illustrate change that happens over time. The data is illustrated as a line that connects dots in a two-dimencional coordinate system, where the x-axis represents time, and the y-axis the value of the variable at each point in time. A line chart can also contain many different variables. - + Let's use a line chart on some real-world data. Statistics Finland offers data on the total votes and relative percentage of votes in the Finnish communal elections for the years 1968-2008. The original data can be found at [https://tilastokeskus.fi/til/kvaa/2008/kvaa_2008_2010-07-30_tau_002.html](https://tilastokeskus.fi/til/kvaa/2008/kvaa_2008_2010-07-30_tau_002.html). A few data points have been drawn from it for visualization purposes -- we'll be focusing on the relative share of the votes here. Our data below uses tabs for separation (i.e., the character '\t').
- +
 Party	1968	1972	1976	1980	1984	1988	1992	1996	2000	2004	2008
@@ -126,18 +107,12 @@ RKP	5.6	5.2	4.7	4.7	5.1	5.3	5.0	5.4	5.1	5.2	4.7
 
- + It's possible to split one of the rows above in the following manner: - + ```java String row = "Party 1968 1972 1976 1980 1984 1988" @@ -147,17 +122,7 @@ for (int i = 0; i < pieces.size(); i++) { } ``` - @@ -171,51 +136,11 @@ for (int i = 0; i < pieces.size(); i++) { - - -Using a line chart requires that we define the axes of the coordinate system, create the line chart that uses those axes, and insert the data into the line chart. Our first conceptualization of the application is as follows. The progam attempts to visualize the support enjoyed by the RKP party in the years 1968-2008. - - ```java @Override @@ -260,19 +185,13 @@ public void start(Stage stage) { } ``` - + When we start the program, we notice a few problems (try it out and see what the data looks like). The class that we've used to create the axes, [NumberAxis](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/chart/NumberAxis.html), happens to offer another constructor as well. You can give the lower and upper bounds as parameters to the constructor, as well as the number of ticks betwen them. Let's set the lower bound as 1968, the upper bound as 2008, and the number of ticks as 4.
- + ```java @@ -283,67 +202,12 @@ public void start(Stage stage) { // .. the rest of the code stays the same ``` - -Adding the numbers of support for another party to the program can be done in a similar manner. In the example below, we add the party VIHR to the chart -- the party has been active since the year 1984. +Adding the numbers of support for another party to the program can be done in a similar manner. In the example below, we add the party VIHR to the chart -- the party has been active since the year 1984. - ```java @Override @@ -403,39 +267,19 @@ public void start(Stage stage) { } ``` - + The program should look like this when started. chart showing support for the rkp and vihr parties - - -Each data point was manually added above to the program code -- given that we're programmers, this approach feels clumsy. The solution is to read the data into a suitable data structure, after which we can go through the structure and add the data contained in it to the chart. A good candidate for this data structure is a hash map that uses the names of the parties as its keys. The values of the hash table are pairs of numbers that represent the year and the corresponding support number. It's now much more straightforward to add data into the chart. - ```java // the axes and the line chart created previously @@ -459,11 +303,11 @@ values.keySet().stream().forEach(party -> { }); ``` - + - + Universities are compared yearly. One internationally respected comparer is the Shanghai Ranking Consultancy, which published a yearly comparison list of internationally famous universities. The list also includes the rank for each university. The University of Helsinki has obtained the following ranks in the years 2007-2017: @@ -481,11 +325,11 @@ Universities are compared yearly. One internationally respected comparer is the 2017 56 - + You will find the class `ShangaiApplication` in the exercise base. Create in it a program that shows how the University of Helsinki's ranking has varied during these years. NB! Don't use any layout in the application -- give the line chart object directly as the Scene object's constructor parameter. Also take notice that the Scene also needs the width and height of the displayed area as parameters. - + The result drawn by the application could like the following example: @@ -494,34 +338,27 @@ The result drawn by the application could like the following example: - + - + The exercise base contains the class PartiesApplication. Create in it an application that displays the relative support of the major Finnish parties during the years 1968-2008. The project contains the raw data that has been used in the previous examples, and it can be found in the file "partiesdata.tsv". - + The relative support must be displayed for each party so that a separate line represents each of them in the line chart. Always set the name of the XYChart.Series object to be the party name that can be found in the data (with the help of the setName method). - + When creating the x axis that the line chart uses, take notice that the first year that the statistics cover is the year of 1968. - + Tab-separated string can be split into parts in the following manner: - + ```java String string = "KOK 16.1 18.1 20.9"; @@ -542,11 +379,11 @@ KOK - + To create a floating point number of a string that contains a floating point number, you can use the valueOf method of the Double class. So for instance `Double.valueOf("16.1");` - + The visualization created by the application should look something like this: @@ -555,7 +392,7 @@ The visualization created by the application should look something like this:   - + *Data for similar charts can be found in the [PX-Web databases](https://pxnet2.stat.fi/PXWeb/pxweb/fi/StatFin/) of Statistics Finland* @@ -564,7 +401,7 @@ The visualization created by the application should look something like this: - + In this exercise you will implement a program for calculating and displaying the sum in a savings account. User can give the calculator a sum to save each month and the yearly interest rate, and the calculator will display how the savings will increase over 30 years. @@ -573,22 +410,22 @@ In this exercise you will implement a program for calculating and displaying the

User interface

- + First implement the user interface of the program. The components of the application can be managed using a BorderPane. In the middle of the BorderPane add a line chart (LineChart), which has two numerical axis (NumberAxis). On the top of the BorderPane add a VBox component which contains two BorderPanes. The first BorderPane (on top) contains the text "Monthly savings" on the left, a slider in the middle and a text describing the slider on the right. The second BorderPane (below the first one) has the text "Yearly interest rate" on the left, a slider in the middle and a text describing the slider on the right. - + You can find tips for using the Slider -class by googling "javafx slider". - + Define the Sliders so, that the minimum monthly savings is 25 and the maximum is 250. The minimum yearly interest rate is 0 and the maximum is 10. The x-axis of the line chart displays years from 0-30. The y-axis must adapt to the values being shown. - + In this phase the application should look like so: @@ -596,13 +433,13 @@ In this phase the application should look like so:

Displaying the savings

- + After the user interface is complete, start implementing the functionality of the program. - + Modify the user interface so, that when user changes the sum to save each month (by moving the uppermost slider), the line chart updates to display the savings amount of the new monthly sum. For example when the monthly savings amount is 50, the line chart should have a line showing the values [(0,0), (1,600), (2,1200),(3,1800),...]. - + In this phase the application should look like so (when the monthly sum to save is 50): @@ -610,45 +447,39 @@ In this phase the application should look like so (when the monthly sum to save

Displaying the savings and the interest rate

- + Modify the user interface so, that it shows the interest rate as well. The line chart should have two lines, one for showing just the monthly savings, and one for showing the monthly savings and the interest rate. - + Calculate the interest rate yearly according to the expected savings at the end of the year. For example when the monthly savings sum is 50 and the yearly interest rate is 5%, the line chart should have a line showing the values [(0,0), (1, 630), (2, 1291.5), (3, 1986,075), ...]. - + In this phase the application should look like so (when the monthly sum to save is 50 and the yearly interest rate is 10%): - + In the chart we see the compound interest of our savings, although with a very optimistic interest rate. When you have completed the application and returned it, you can for example calculate how saving 25 euros a month with 4% yearly interest rate grows over 50 years.
- + ### Bar Charts - + Bar charts are used to visualize categorical data. The data is represented as bars -- each bar represents a certain category, and its height (or length) represents the value associated with the category. Examples of data that could well be illustrated with bar charts are populations of countries or the market shares of stores or products. - + Let's take a look at using a bar chart to visualize the population figures of the Nordic countries. The used data is from [the Wikipedia article on the Nordic countries](https://en.wikipedia.org/wiki/Nordic_countries) (retrieved 6.12.2019, populations are estimates from the year 2018).
- +
 Iceland, 343518
@@ -659,35 +490,13 @@ Denmark, 5809502
 
- + We'll use the JavaFx [BarChart] class (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/chart/BarChart.html). As with line charts, the axes have to be defined and data has to be added to the chart. In this case, however, we're going to take advantage of the categorical [CategoryAxis](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/chart/CategoryAxis.html) class to define the x axis. With the CategoryAxis class, the type of the axis values is String. This must also be accounted for in the data that is going to be added to the chart.
- +
 Iceland, 343518
@@ -723,55 +532,52 @@ public void start(Stage stage) {
 
 
 
-
+
 
 The source code above produces the following chart.
 
 A bar chart showing the populations of the Nordic countries
 
-
+
 
 As you notice, since the x-axis is defined with the CategoryAxis class, the chart follows the order in which the categories are supplied to the program. In the previous example, the countries were ordered by population. Try to modify the program so that the chart orders the Nordic countries by name. After launching the application you may be able to understand why this form of visualization is hardly used...
 
 
 
 
-
+
 According to the old saying "There are three kinds of lies: lies, damned lies and statistics.", nothing lies like a statistic. The saying might not be completely wrong, as some statistics are purposefully made difficult to read.
-
+
 The application in the exercise template opens a visualization used for marketing for an imaginary company. The visualization displays the speed of their internet, and shows a remarkable difference to their competitors.
 
 
 
 
-
+
 The comparison however is not really fair, and gives the wrong impression on the situation. Modify the program so, that the comparison is fairer.
 
-
+
 This exercise has no automatic tests or model answer, so you can define the comparison with some freedom.
 
 
 
 
-
+
 
 
 
-
+
 
 In the exercise base there is a ready application that illustrates cycling statistics as a line chart. Modify the program so that it uses a bar chart instead of the line chart. All the references to line charts must be removed in the course of the editing.
 
 
 
 
-
-## Visualizing Dynamic Data
 
+## Visualizing Dynamic Data
 
-
 Software is also used to visualize contunually changing information. As an example, the software used to track share prices is constantly searching for the latest share prices and displaying that information to the user. Similarly, weather software retrieves data from stations and displays the most recent information to the user. Software developed for monitoring server-side software works in the same way by pinging the various parts of the server-side software at certain intervals to check for responses.
 
 
@@ -779,61 +585,12 @@ The [AnimationTimer](https://docs.oracle.com/javase/8/javafx/api/javafx/animatio
 
- + The example below illustrates [the large numbers law](https://en.wikipedia.org/wiki/Larger_numbers_Law). This law is a phenomenon related to probability calculus, which says that the average of a random variable approaches the expected value of the random variable as the number of iterations increases. In practice, for example, the average of rolls of a six-sided dice approaches 3.5 as the number of rolls increases. In the same way, when a coin is thrown the heads-to-tails ratio approaches a "fifty-fifty" split as the number of coin throws increases.
- ```java @Override public void start(Stage stage) { @@ -885,31 +642,20 @@ public void start(Stage stage) { } ``` - + The image below shows an example of the application in use. The dice has been rolled nearly a 100 times in it. A chart illustrating the law of large numbers - Eagle-eyed readers may have noticed that the application's source code did not re-draw the chart as data was added. What on earth? Charts such as LineChart and BarChart use a data structure that implements the [ObservableList](https://docs.oracle.com/javase/8/javafx/api/javafx/collections/ObservableList.html) interface to store internal data. Collections that implement the ObservableList interface provide the ability to listen to changes in collections. When a new record is added to the list, such as a new data point for the mean, the list informs all of the objects listening to changes on the list of this change. Charts such as LineChart and BarChart are constructed internally in a way that they listen to changes in the information that they display. If the data changes, the chart is updated automatically. In some situations we may only want to display the 100 most recent observations of the dynamically changing data. This can be done in the previous example by turning off the random value generation representing the x-axis of the NumberAxis object (the method setAutoRanging(false)), and by adding the following check to the end of the handle method of the AnimationTimer class. - + ```java if (average.getData().size() > 100) { average.getData().remove(0); @@ -918,5 +664,5 @@ if (average.getData().size() > 100) { } ``` - + The application now only displays the last 100 observations to the user. diff --git a/data/part-14/2-multimedia-in-programs.md b/data/part-14/2-multimedia-in-programs.md index 61b74b143..93219b7c3 100644 --- a/data/part-14/2-multimedia-in-programs.md +++ b/data/part-14/2-multimedia-in-programs.md @@ -14,13 +14,13 @@ hidden: false - + This part servers as a short introduction to using multimedia in JavaFX applications. - + ## Drawing - + The JavaFX interface library uses a [Canvas](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/canvas/Canvas.html) object for drawing. A Canvas object can be thought of as a empty canvas we can draw on. We use a [GraphicsContext](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/canvas/GraphicsContext.html) object provided by a Canvas object to draw on it. @@ -28,7 +28,7 @@ We use a [GraphicsContext](https://docs.oracle.com/javase/8/javafx/api/javafx/sc - + Below we have created a simple drawing application. The application creates a 640 pixels wide and 480 pixels tall canvas, which is then placed to the middle of a BorderPane object. It also creates a [ColorPicker](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ColorPicker.html) object for selecting the color to draw with. ColorPicker can also tell us the currently selected color. @@ -81,21 +81,21 @@ public class MiniPaint extends Application { ``` - + The application looks like so. In the image below we have already drawn something with the application. Yksinkertainen piirto-ohjelma. Käyttäjä voi piirtää pitämällä hiirtä pohjassa. Oikeassa laidassa on värin valintaan käytettävä ColorPicker-olio. - + - + Create a graphical user interface into the class that is supplied with the exercise base. Add a BorderPane into the GUI to be responsible for the application's layout. Add a Canvas object in the middle of the BorderPane. After doing this, use the GraphicsContext object of the Canvas object to draw a smiley. Use white (Color.WHITE) as the background color, and black (Color.BLACK) as the color of the smiley. - + The tests in this exercise only check that you draw into the window. Before returning, make sure that drawing the smiley works correctly. Notice that the purpose here is NOT to manually draw the smiley with the mouse -- use the methods of the GraphicsContext object so that the picture is already drawn when the program is first started. @@ -106,11 +106,11 @@ The tests in this exercise only check that you draw into the window. Before retu ## Images - + There are many ways to display an image as a part of application's interface. One straightforward way is to use the [Image](https://docs.oracle.com/javafx/2/api/javafx/scene/image/Image.html) and [ImageView](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/image/ImageView.html) classes from JavaFX. - + We pass the name of the image file to the Image class as an argument. The file name must be preceded with the prefix `file:`, with which we tell the application the image is a file in the file system. In the example below we first load the file `humming.jpg` and then pass it to a ImageView object we create as an argument. The ImageView object is then placed to a Pane object. Note that Pane is not used to arrange layout items -- it does not care how items within it are placed on a screen. @@ -150,7 +150,7 @@ public class ImageApplication extends Application { ``` - + Below you can see the window that opens when the program is run. Here we expect that the file `humming.jpg` exists and is located at the root of the project (the same directory as for example `pom.xml`). @@ -159,10 +159,10 @@ Here we expect that the file `humming.jpg` exists and is located at the root of - + In the example we use an image by [Linda Tanner](https://www.flickr.com/photos/15323831@N05) from [http://www.freestockphotos.biz/stockphoto/17874](http://www.freestockphotos.biz/stockphoto/17874). The image has a [Creative Commons CC BY 2.0](https://creativecommons.org/licenses/by/2.0/) lisence. - + ImageView object has a punch of methods available for (simple) image processing tasks. We can for example change the size of an image, flip it around or move it on the screen. Below we have flipped the image, halved its size and moved it a bit to the right. @@ -192,13 +192,13 @@ public void start(Stage stage) { - + We can access an image trough the ImageView class, but it does not let us access separate pixels (the small "frames" containing a single color an Image is formed off of) within it. We can access the separate pixels of an image using a [PixelReader](https://docs.oracle.com/javafx/2/api/javafx/scene/image/PixelReader.html) object available from the Image class. PixelReader object can be used to go trough an image pixel by pixel, simultaneously writing a new image to a separate [WritableImage](https://docs.oracle.com/javafx/2/api/javafx/scene/image/WritableImage.html) object. - + Below we copy an image pixel by pixel to a separate WritableImage object, and display it in the application. ```java @@ -240,66 +240,66 @@ public void start(Stage stage) { } ``` - + The image looks just like it did before copying. - + - + Andy Warhol was famous for his photo collages where one or more pictures are repeated multiple times with different colors, for instance. - + In this exercise we are going to imitate his style and create an Andy Warhol-ish interpretation of the famous Mona Lisa. The finished program will show Mona Lisa looking like this: - + Let's begin. - +

Top left corner

- + In the exercise base there is a program that loads and displays the Mona Lisa. In this section your goal is to create a situation where the Mona Lisa is displayed as a smaller image in the top left corner. The size of the smaller image should be one fourth of the original image. - + So in practice the point (0, 0) should contain the value at the coordinates (0, 0). The coordinates at (0, 1) should contain the value at coordinates (0, 2). Similarly, the point (0, 2) should contain the value at the point (0, 4), the point (0, 3) the value at (0, 6), etc. The same holds true with the y-axis, so point (1, 1) should have the value of (2, 2), the point (1, 2) the value of (2, 4), etc. - +

Grid

- + Then modify the program so that the small image at the top left corner is repeated four times in the whole collage. The top-left corner of the first image should be at the coordinates (0, 0). The top-left corner of the second image should be at the point (width of image / 2, 0). The top-left corner of the third image should be at (0, height of image / 2), and the top-left corner of the fourth image should be at (width of image / 2, height of image / 2). - +

Negative

- + You've come this far, and now you can display a grid of four small images. Next, modify the image so that the negative of the original is displayed. You can create a negative by assigning to each pixel, the following color values: the subtraction of the original color from 1. So for the red color this would be `red = 1.0 - red`. - + *The Mona Lisa image included in the exercise base has been downloaded from the Wikimedia path [https://commons.wikimedia.org/wiki/Category:Mona_Lisa](https://commons.wikimedia.org/wiki/Category:Mona_Lisa). It can be used freely.* @@ -308,12 +308,12 @@ You've come this far, and now you can display a grid of four small images. Next, ## Sounds - + There are multiple ways to handle sound files, and here we will go trough one of them. We will handle sound files as audio clips, which can be for example sound effects. - + In the example we use a sound file by Daniel Simionin, which has a [Creative Commons Attribution 3.0](https://creativecommons.org/licenses/by/3.0/) lisence. The file has been downloaded from [http://soundbible.com/](http://soundbible.com/). @@ -323,7 +323,7 @@ The file has been downloaded from [http://soundbible.com/](http://soundbible.com - + We expect the file is called `bell.wav` and is located at the root of the project. The simplest way to play a sound is as follows: @@ -332,7 +332,7 @@ AudioClip sound = new AudioClip("file:bell.wav"); sound.play(); ``` - + AudioClip object is dependent on the JavaFX library, so the sound file must be played as a part of a JavaFX application. The example below searches for the file `bell.wav` from the root of the project, and creates an audio clip from it. Then the audio clip is played, and the application window (currently empty) opens. @@ -361,17 +361,17 @@ public class AudioClipApplication extends Application { } ``` - + - + In the root folder of the exercise base there is a file called `Applause-Yannick_Lemieux.wav`. The file contains a hurray sound. Your task is to create a program that contains a "Hurray!" button. When the user clicks the button, the program should play the audio file included in the project. - + *The audio file is recorded by Yannick Lemieux. It is licensed with the Creative Commons attribution license [https://creativecommons.org/licenses/by/3.0/](https://creativecommons.org/licenses/by/3.0/).* @@ -381,7 +381,7 @@ In the root folder of the exercise base there is a file called `Applause-Yannick - + You can find a guide for creating a media player from [https://examples.javacodegeeks.com/desktop-java/javafx/javafx-media-api/](https://examples.javacodegeeks.com/desktop-java/javafx/javafx-media-api/). The guide is a very good starting point if playing and processing sound programmatically interests you. diff --git a/data/part-14/3-larger-application-asteroids.md b/data/part-14/3-larger-application-asteroids.md index 28899d757..10c83d433 100644 --- a/data/part-14/3-larger-application-asteroids.md +++ b/data/part-14/3-larger-application-asteroids.md @@ -5,12 +5,12 @@ hidden: false --- - + - - - + + + - You know a way of implementing an interactive game. - You are able to picture how a larger application is built on step by step. @@ -18,90 +18,66 @@ hidden: false - + [Asteroids](https://en.wikipedia.org/wiki/Asteroids_(video_game)) developed by [Atari](https://en.wikipedia.org/wiki/Atari,_Inc.) and self published in the year 1979 is a video game classic. The gameplay consists of the player steering a triangular spaceship, with the goal of destroying asteroids by shooting them. - + What follows is a larger scale example, where we create a part of the Asteroids game. The game is also an exercise in the course -- write the game into the provided template (at the end of the example) by following the example. - + The game is constructed in multiple parts, which are the following: - + - Creating the game window - + - Creating the ship - + - Turning the ship - + - Moving the ship - + - Creating an asteroid - + - The collision between the ship and an asteroid - + - Multiple asteroids - + - Staying within the window - + - Projectiles - + - Adding points - + - Continuous adding of asteroids - + Let's begin making the application by creating the game window - + ## Creating the game window - + We will build the application such that the game window may contain an arbitrary amount of elements, the positions of which will be ignored by the layout used. This task fits the [Pane](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/Pane.html) class. The Pane class contains a list of type [ObservableList](https://docs.oracle.com/javase/8/javafx/api/javafx/collections/ObservableList.html) containing child elements. The list can be accessed using the `getChildren` method of the Pane class. - -The program shown below creates a window that is 300 pixels wide and 200 pixels tall. At the point 30, 50 in the window is a circle with a radius of 10 pixels. In computer programs it is typical for the origin of the coordinate system is placed at the top left corner of the window. Additionally the value of the y-coordinate increases when moving down. - ```java import javafx.application.Application; @@ -132,34 +108,11 @@ public class PaneExample extends Application { Ympyrä ikkunassa. - - -We call our application `AsteroidsApplication`. AsteroidsApplication applies the above example. The application does not add a circle to the window, but we have provided a title for the application. The width of the window is 600 pixels and the height is 400 pixels. - - ```java import javafx.application.Application; @@ -186,32 +139,19 @@ public class AsteroidsApplication extends Application { } ``` - + ## Creating the ship - + Next we create the ship. In Asteroids the ship is a triangle. The display of the triangle is possible using the [Polygon](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/Polygon.html) class, which is used to represent polygons. The corners of the polygon are set for the Polygon object, either as parameters of the constructor or into the list contained within the Polygon class. - -In the example below we have added a parallelogram that is 100 pixels wide and 50 pixels tall using the Polygon class. - ```java @Override @@ -231,27 +171,11 @@ public void start(Stage stage) throws Exception { Suunnikas ikkunassa. - - -Moving the polygon into a more fitting position can be done with the provided methods `setTranslateX` and `setTranslateY` of the Polygon class. In the example below we create a parallelogram just like before, but now the parallelogram has been moved 100 pixels to the right and 20 pixels down. - ```java @Override @@ -274,41 +198,11 @@ public void start(Stage stage) throws Exception { Suunnikas ikkunassa. Suunnikasta on siirretty 100 pikseliä oikealle ja 20 pikseliä alas. - -Let's create a triangle representing the ship and add it to our AsteroidsApplication. We set the triangle at the center of the screen -- because the width of the screen is 600 pixels and the height is 400 pixels, we move the triangle 300 pixels to the right and 200 pixels down. - ```java import javafx.application.Application; @@ -342,36 +236,19 @@ public class AsteroidsApplication extends Application { } ``` - + ## Turning the ship: Keyboard listener, part 1 - + Classes like Polygon and Circle inherit the [Node](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html) class of JavaFx. The Node class has a variable `rotate`, which describes the rotation of the node in degrees. Turning any object inheriting the Node class is therefore quite straightforward -- you just use the existing method `setRotate`. The method is given the amount to turn in degrees as its parameter.
- -In the example below we have modified a previous example such that the parallelogram is rotated 30 degrees. - ```java @Override @@ -392,29 +269,19 @@ public void start(Stage stage) throws Exception { } ``` - + In reality we don't want a situation where the ship only turns once, but one in which we can steer the ship while the game is running. - + The `Scene` object describing the content of the window provides a method `setOnKeyPressed`, which can be given an object for handling events as its parameter. Let's create an event handler, which reacts to events on the keyboard. Keyboard events have an enumerated variable `KeyCode`, which tells us the key that was pressed. We are interested in the keys left (LEFT) and right (RIGHT). - + First we make a test version, in which the turning of the ship is simple. If the user presses the left arrow, the degrees are set to -30. Then again, if the user presses the right key, then the degrees are set to 30. - ```java scene.setOnKeyPressed(event -> { @@ -428,28 +295,18 @@ scene.setOnKeyPressed(event -> { }); ``` - + If the ship was a parallelogram the functionality would look as follows: Suunnikasta voi kääntää vasemmalle tai oikealle. - + The turning can be made smoother by utilizing existing information about the rotation. In the next example the ship turns five degrees at a time. - ```java scene.setOnKeyPressed(event -> { @@ -463,42 +320,32 @@ scene.setOnKeyPressed(event -> { }); ``` - + Below is pictured an equivalent example, where instead of rotating the ship we rotate a parallelogram. Suunnikasta voi kääntää vasemmalle tai oikealle. - + ## Turning the ship: Keyboard listener, part 2 - + The previous approach enables a "kind of OK"-way to turn a node. There is an issue with the approach -- the movement is not smooth. When the key is pressed, the ship rotates, then takes a short break, after which it continues rotating. - + This is related to how programs handle keyboard events by default. If the program would handle the keypress as multiple events immediately as the key is pressed, then, for example, writing text would become quite difficult, since even slightly longer keypresses would immediately generate multiple characters. - + Let's change the handling of keyboard event, such that we keep a record of pressed keys. This can be done, for example, using a hash table. The hash table contains the KeyCode object, i.e. the object representing the key, as the key and a Boolean variable as the value. If the value of the boolean variable of a particular key is `true`, then the key is pressed, otherwise the key is not pressed. - -Now we also consider depressing the key, i.e. the `onKeyReleased` event. - ```java Map pressedKeys = new HashMap<>(); @@ -512,40 +359,16 @@ scene.setOnKeyReleased(event -> { }); ``` - -But! Nothing is currently turning the ship. - - - -Indeed. We still need functionality for rotation. We will start using the AnimationTimer class, which is meant for creating animations, and assign it the responsibility of turning the the ship in case the left or right key is pressed. +But! Nothing is currently turning the ship. - ```java Map pressedKeys = new HashMap<>(); @@ -573,49 +396,29 @@ new AnimationTimer() { }.start(); ``` - + The `handle` method of the AnimationTimer class is called approximately 60 times per second. Now the rotation is much smoother (however, it is not very apparent in the gif below...). Suunnikasta voi kääntää vasemmalle tai oikealle. - + ## Moving the ship: First attempt - -It's now possible to rotate the ship. Next, we'll add the possibility to move around. The ship should be able to move in any cardinal direction, which means that we need values for both x and y coordinates to represent movement. The concrete implementation of the movement is to modify the position of the polygon that represents the ship while the program is running. - +It's now possible to rotate the ship. Next, we'll add the possibility to move around. The ship should be able to move in any cardinal direction, which means that we need values for both x and y coordinates to represent movement. The concrete implementation of the movement is to modify the position of the polygon that represents the ship while the program is running. -Let's make use of the existing [Point2D](https://docs.oracle.com/javase/8/javafx/api/javafx/geometry/Point2D.html) Java class to represent movement -- the class has both x and y coordinates. - -The first test version is to create a movement variable and adding it to the AnimationTimer class's handle method. +Let's make use of the existing [Point2D](https://docs.oracle.com/javase/8/javafx/api/javafx/geometry/Point2D.html) Java class to represent movement -- the class has both x and y coordinates. - ```java Point2D movement = new Point2D(1, 0); @@ -639,30 +442,18 @@ new AnimationTimer() { }.start(); ``` - + Hurray! The ship is moving (and it can be rotated). Although it disappears quite quickly... Suunnikasta voi kääntää vasemmalle tai oikealle. - + The class that we chose, Point2D, is like the String class in some regards -- namely, it is *immutable* so it cannot be modified. We cannot change the values of an existing point, and calling the methods of a point always returns a new point value. This poses something of a problem, since we cannot set the values of the objects to something else inside methods. The following solution is therefore ruled out. - ```java new AnimationTimer() { @@ -678,53 +469,19 @@ new AnimationTimer() { }.start(); ``` - - -However, method calls are allowed. Looks like it's time for refactoring and clearing up the structure of the program... - -## Moving the ship: Refactoring - - - -Let's create a class called Ship, which contains a Polygon object and a Point2D object. The Polygon object represents the ship, and the Point2D object represents the movement of the ship. The ship receives the x and y coordinates of the ship as its constructor parameters. The ship can be rotated left or right. - - ```java import javafx.geometry.Point2D; @@ -763,16 +520,12 @@ public class Ship { ``` - + This refactoring leads to changes in the program in a couple of places. Instead of the point to represent movement and a polygon to represent the ship, we will create a Ship. In addition, the Pane object is given the Polygon object of the ship, but not the Ship object itself. - ```java Ship ship = new Ship(150, 100); @@ -780,28 +533,11 @@ Ship ship = new Ship(150, 100); pane.getChildren().add(ship.getCharacter()); ``` - - -The method in the AnimationTimer object should also be updated to use the methods of the ship. - ```java new AnimationTimer() { @@ -822,40 +558,30 @@ new AnimationTimer() { }.start(); ``` - + ## Moving the ship: Second attempt - + The ship moves, but it's not possible to affect the movement yet. Let's add an acceleration functionality to the shpi. The ship should accelerate so that the speed accelerates to the direction that the ship points to. We can get the acceleration information from the rotation degree, which we can use the `getRotate()` method. We have already become well acquainted with it in rotating the ship. - + The direction of the acceleration can be figured out with sine and cosine functions. The existing Java [Math](https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html) class contains the relevant methods. The methods assume their parameters to be in radians, so we are also going to need the Math class method that converts degrees into radians. - + ```java double changeX = Math.cos(Math.toRadians(*angle in degrees*)); double changeY = Math.sin(Math.toRadians(*angle in degrees*)); ``` - + The first version of the accelerate method of the Ship class looks like this. - ```java public void accelerate() { @@ -866,31 +592,11 @@ public void accelerate() { } ``` - - -Let's add the possibility to accelerate into the application. The accelerate method is called when the user is pressing the up button. - - ```java new AnimationTimer() { @@ -917,22 +623,12 @@ new AnimationTimer() { Alus kiihtyy. - -As can be seen, the ship accelerates, indeed. The amount of acceleration is quite high, so it should be tweaked somewhat. Let's modify the accelerate mehtod of the ship so that the change is only 5% of the previous value. +As can be seen, the ship accelerates, indeed. The amount of acceleration is quite high, so it should be tweaked somewhat. Let's modify the accelerate mehtod of the ship so that the change is only 5% of the previous value. - ```java public void accelerate() { @@ -946,71 +642,27 @@ public void accelerate() { } ``` - + Now it's more or less possible to steer the ship. Alus kiihtyy siten, että sitä pystyy kontrolloimaan. - + ## Creating an asteroid - + Next up, we are going to create an asteroid. An asteroid has a shape, position, and movement. Hmm.. - - -Come to think of it, these are almost exactly the same things that a ship needs -- the only difference is in the shape. This is a good moment to *generalize*. We'll create an *abstract class* called Character, which receives a polygon and position as its constructor parameters. Notice that the functionality is almost entirely copied from the class `Ship`. - - ```java import javafx.geometry.Point2D; @@ -1058,21 +710,12 @@ public abstract class Character { } ``` - -Then let's change the class Ship to inherit from the Character class. +Then let's change the class Ship to inherit from the Character class. - ```java import javafx.scene.shape.Polygon; @@ -1085,24 +728,15 @@ public class Ship extends Character { } ``` - + Pretty straighforward stuff. - -Then let's create the Asteroid class. The first draft is going to be a rectangle -- we'll return to worry about the shape of the asteroid at a later stage. - ```java import javafx.scene.shape.Polygon; @@ -1117,25 +751,11 @@ public class Asteroid extends Character { - -Then let's make sure that you can also add an asteroid to the application. - - ```java Pane pane = new Pane(); @@ -1153,33 +773,12 @@ asteroid.accelerate(); asteroid.accelerate(); ``` - - -In order for an asteroid to move, the related move method must be called in the animation. - - ```java new AnimationTimer() { @@ -1204,28 +803,24 @@ new AnimationTimer() { }.start(); ``` - + Now the application contains both a ship and an asteroid. Sovelluksessa sekä alus että yksi asteroidi. - + ## The collision between the ship and an asteroid - + Next we will implement collision between a ship and an asteroid. If a ship collides with an asteroid, the `stop` method of an AnimationTimer -object is called, and the animation stops. - + Both a ship and an asteroid are characters. Add a method for checking if two characters collide to the `Character` class. For now two characters never collide. - + ```java public boolean collide(Character other) { @@ -1233,18 +828,13 @@ public boolean collide(Character other) { } ``` - + The [Shape](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/Shape.html) class, which the Polygon class inherits, has a handy method for checking for collision. The method [public static Shape intersect(Shape shape1, Shape shape2)](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/Shape.html#intersect-javafx.scene.shape.Shape-javafx.scene.shape.Shape-) returns the intersection of two Shape objects. -If the intersection is zero, there is no collision. +If the intersection is zero, there is no collision. Let's modify the collide method so, that it uses the intersect method. - + ```java public boolean collide(Character other) { @@ -1253,36 +843,11 @@ public boolean collide(Character other) { } ``` - -Let's also add functionality that stops the application if a collision happens. - - - ```java new AnimationTimer() { @@ -1311,32 +876,21 @@ new AnimationTimer() { }.start(); ``` - + Now the application stops if a ship and an asteroid collide. Sovellus pysähtyy mikäli alus ja asteroidi törmäävät. - + ## Multiple asteroids - + Now we will add more asteroids. We can represent the asteroids as a list. In the example below we first create a ship and then add five asteroids. - ```java Ship ship = new Ship(150, 100); @@ -1351,39 +905,11 @@ pane.getChildren().add(ship.getCharacter()); asteroids.forEach(asteroid -> pane.getChildren().add(asteroid.getCharacter())); ``` - -Let's modify drawing asteroids and checking for collision so that they work with multiple asteroids. - - - ```java new AnimationTimer() { @@ -1415,53 +941,21 @@ new AnimationTimer() { }.start(); ``` - + Now when the application starts we see multiple asteroids. Monta asteroidia. - + At the moment every asteroid looks the same and moves the same way. It would be nice if there was some variance between the asteroids. Let's modify the Asteroid -class so, that it has a method for randomly assigning attributes to asteroids. We can decide that asteroids always have five corners, and their basic shape is always a pentagon. We can add variance to their shapes by moving the locations of the corners a little. - + You can find the formula for calculating the angles of the corners of a pentagon from [http://mathworld.wolfram.com/Pentagon.html](http://mathworld.wolfram.com/Pentagon.html). Below we have used the formula, and added some variance to the size of the asteroids and the locations of an asteroids corners. - ```java import java.util.Random; @@ -1497,18 +991,10 @@ public class PolygonFactory { } ``` - -Let's modify the Asteroid class so that it uses the PolygonFactory class to create polygons. - ```java public class Asteroid extends Character { @@ -1520,48 +1006,20 @@ public class Asteroid extends Character { } ``` - + Now the asteroids look a bit more varied. Asteroideissa on vaihtelua. - + We will also add movement and direction to the asteroids. Movement and direction have been partially defined in the Character class, but we want to add some randomness to the movement. When an asteroid is created, it's direction should be a random number between [0, 360]. Asteroids also move a little -- the movement is defined as a random number of acceleration calls when the character is created. Finally an asteroid also rotates. Each time an asteroid moves, it also rotates a little. - ```java import java.util.Random; @@ -1593,7 +1051,7 @@ public class Asteroid extends Character { } ``` - + In the example below we use inheritance in the `move` method. When the move method is called, it first calls the move method from the Character class. Then the character is rotated. The final product is an asteroid with some rotational movement. @@ -1601,39 +1059,16 @@ When the move method is called, it first calls the move method from the Characte - + ## Staying within the window - -The application is a bit boring, because the asteroids and the ship can leave the screen. Let's modify it so, that the characters stay on screen. - -We will define constants width and height for the AsteroidsApplication. Each class can have class specific values using the keyword `static`. Below we define variables `WIDTH` and `HEIGHT`, which can be referenced elsewhere in the program code. - - ```java public class AsteroidsApplication extends Application { @@ -1661,34 +1096,13 @@ public class AsteroidsApplication extends Application { ``` - + Variables with the keyword `static` are not part of objects made from the class. If a `static` variable is also `public` --like above -- the variable can be referenced by other classes. Let's modify the move method of the Character class so that it uses the *static variables* of the AsteroidApplication, the class variables WIDTH and HEIGHT. The move method below checks that the character stays on screen. - ```java public void move() { @@ -1713,36 +1127,26 @@ public void move() { } ``` - + Now the characters stay on screen. - + We are not quite satisfied with this version of the application, because characters sometimes "jump" from one side of the screen to the other. The size of the character is not taken into account, so its x- or y -coordinates can be outside of the screen, even if part of the character stays visible. We can --probably-- solve this problem with the getBoundsInParent-method of the Node -class. However we will not go more into it here. - + ## Projectiles - + Playing asteroids without projectiles would be just dodging asteroids. Next we will add projectiles. Projectiles have a shape, a direction and movement. We can use the Character class for creating projectiles. Let's create the first version of the Projectile-class. For now all projectiles are squares. - ```java import javafx.scene.shape.Polygon; @@ -1757,32 +1161,21 @@ public class Projectile extends Character { ``` - + Contrary to ships and asteroids, we don't want any projectiles on screen when the application starts. We will declare a list for projectiles, but leave it empty for now. - + ```java List projectiles = new ArrayList<>(); ``` - + A projectile is created when the user presses the spacebar. When a projectile is created its direction is the same as the ship's direction. Let's make the first version of shooting projectiles. - ```java if (pressedKeys.getOrDefault(KeyCode.SPACE, false)) { @@ -1795,30 +1188,18 @@ if (pressedKeys.getOrDefault(KeyCode.SPACE, false)) { } ``` - + Now the ship shoots a projectile when the user presses the spacebar, but the projectiles do not move. The projectiles do not hit other characters either. - + We want to be able to modify the movement of a projectile. However, currently the `move` method of a Character is `private`, and we have to access to it through other methods. Let's add `getMovement` and `setMovement` to the `Character` class. - -Now setting the speed of a projectile is straightforwards. We accelerate the speed of a projectile a bit (so it never stays put) and normalize the speed (in practice we handle the speed as a vector with the length of 1). Here the speed is multiplied by three. - ```java if (pressedKeys.getOrDefault(KeyCode.SPACE, false)) { @@ -1834,14 +1215,10 @@ if (pressedKeys.getOrDefault(KeyCode.SPACE, false)) { } ``` - + Finally we add moving the projectiles to moving all other characters. - + ```java ship.move(); @@ -1849,22 +1226,10 @@ asteroids.forEach(asteroid -> asteroid.move()); projectiles.forEach(projectile -> projectile.move()); ``` - + Now the projectiles move. They do not yet hit anything, and there are quite a lot of them... Let's limit the number of projectiles a bit -- we can decide that there can only be 3 projectiles at once. - ```java if (pressedKeys.getOrDefault(KeyCode.SPACE, false) && projectiles.size() < 3) { @@ -1880,22 +1245,11 @@ if (pressedKeys.getOrDefault(KeyCode.SPACE, false) && projectiles.size() < 3) { } ``` - + Let's also add functionality for hitting asteroids. Projectiles can hit asteroids. If a projectile hits an asteroid, the asteroid is removed from the asteroid list and is not drawn. - ```java projectiles.forEach(projectile -> { @@ -1912,32 +1266,10 @@ projectiles.forEach(projectile -> { - -The projectiles do not however disappear when they hit an asteroid. One way to remove the projectiles after a hit is described below. - - ```java List projectilesToRemove = projectiles.stream().filter(projectile -> { @@ -1963,34 +1295,11 @@ projectilesToRemove.forEach(projectile -> { }); ``` - + It works, but we can improve it a bit. In practice this is declaring wether a Character is "in the game" or not. We could for example add an attribute "alive", which we could use to make things clearer. Using this attribute the code improves a bit. - ```java projectiles.forEach(projectile -> { @@ -2017,38 +1326,26 @@ asteroids.removeAll(asteroids.stream() .collect(Collectors.toList())); ``` - + The lines at the end are almost identical -- both are handling characters. Maybe we could refactor this a bit. - + ## Adding points - + Asteroids games almost always have a some sort of a points system. The points are displayed as text-objects, value of which changes when the number of points changes. We can decide that a player gets 1000 points every time they destroy an asteroid. - + The Java Text -class is great for this purpose. A Text object has coordinates and content. In the example below the player always has 0 points.
- ```java @Override @@ -2066,35 +1363,12 @@ public void start(Stage stage) throws Exception { Ikkuna, jossa on teksti pisteet. Pisteet on nollassa. - + However we want to be able to increase the number of points. One handy tool for this is the [AtomicInteger](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicInteger.html)-class, which offers integers as encapsulated objects. AtomicInteger also enables us to increase the points when a method is called. - ```java @Override @@ -2123,27 +1397,14 @@ public void start(Stage stage) throws Exception { Ikkuna, jossa on teksti pisteet. Pisteet kasvavat. - + Now we can display the number of points and increase it. Let's connect the points to the game so, that the number of points increases every time player's projectile hits an asteroid. - + This can be done as a part of collision between a projectile and an asteroid. - ```java projectiles.forEach(projectile -> { @@ -2160,34 +1421,26 @@ projectiles.forEach(projectile -> { }); ``` - + Now, if the increasing of points has been removed from the start of the animation timer, player gets points when they hit an asteroid. Like a boss. - + ## Continuous adding of asteroids - + When we hit an asteroid, they disappear, and soon there is nothing to shoot. This is not acceptable! - + We will add a function which adds asteroids throughout the game. A new asteroid is added with the probability of 0.5% each time the AnimationTimer-object is called. A new asteroid is added only if it does not collide with a ship immediately. - + The handle method of an AnimationTimer-object is called approximately 60 times a second, so in ten seconds a few asteroids are added. We add the call to the end of the handle -method. - + ```java if(Math.random() < 0.005) { @@ -2202,66 +1455,66 @@ if(Math.random() < 0.005) { Like a boss. - + - + The exercise template contains an empty program template. Create the Asteroids game by following the preceding example of a large application. - + While you are creating the game, remember to update the method `partsCompleted` in the `AsteroidsApplication` class such that it returns the number of the part you have completed. You may submit the exercise even if you don't complete all of the parts, in which case you will receive points for the parts you have completed. - + When you have completed the exercise you may keep going if you like. E.g. you could add sounds and different characters -- how would, for example, aliens work in the game? Would they try to shoot the ship of the player? - +

Part 1

- + Implement the steps presented at the start of the material (1) creating the game window, (2) creating the ship, and (3) turning the ship. - + When you have these parts working, set the return value of the `partsCompleted` method of the `AsteroidsApplication` class to `1`. - +

Part 2

- + Add functionality for moving the ship to the Asteroids game as presented in the material. - + When you have these, and the previous parts working, set the return value of the `partsCompleted` method of the `AsteroidsApplication` class to `2`. - +

Part 3

- + Extend the Asteroids game with (1) creating an asteroid, (2) the collision between ship and asteroid, and (3) adding multiple asteroids. - + When you have these, and the previous parts working, set the return value of the `partsCompleted` method of the `AsteroidsApplication` class to `3`. - +

Part 4

- + Extend the Asteroids game by adding the rest of the game functionality, i.e. (1) staying within the window, (2) projectiles, (3) adding points, and (4) adding new asteroids. - + When you have these, and the previous parts working, set the return value of the `partsCompleted` method of the `AsteroidsApplication` class to `4`. - + *The exercise does not have a model solution. The exercise is meant to be done by following the example in the material step by step.*
diff --git a/data/part-14/4-maven-and-third-party-libraries.md b/data/part-14/4-maven-and-third-party-libraries.md index f56137437..67a05275b 100644 --- a/data/part-14/4-maven-and-third-party-libraries.md +++ b/data/part-14/4-maven-and-third-party-libraries.md @@ -6,10 +6,10 @@ hidden: false - - - - + + + + - Know the term library and know some third party libraries - Know where to search for libraries - Can implement an application which uses a third party library @@ -18,46 +18,46 @@ hidden: false - + The programming exercises of this course have been done in the NetBeans development environment with a Test My Code plugin for downloading and submitting exercises. However the exercise templates we have used are not dependent on NetBeans or Test My Code in any way, and you can use them in other development environments as well. - + The exercise templates use a tool called [Maven](https://maven.apache.org/), which is used for executing and managing programs. Maven dictates the structure of our projects -- every project has a file called `pom.xml` located at its root, and their source code is located in a directory called `src`. The `src` directory typically has two sub-directories: `main` containing the project source code and `test` containing the source code of the tests for the project. - + One advantage of using Maven is, that it is useful for downloading libraries. Libraries are source code which has been packaged to be used by anyone. For example we have used the JUnit library for unit tests. There is a library for almost anything. The search engine at [https://mvnrepository.com/](https://mvnrepository.com/) finds over 10 million libraries, although many of them are different versions of the same library. - + You can find for example libraries for using databases or creating telegram bots. Next you will get to know some of those libraries a bit better. - + ## Using a database - + Databases, or rather database management systems, are tools for managing data. You have a chance to familiarize yourself better with them on the course Introduction to Databases (TKT10004). Let's have a brief look at an application that uses a database. - + There are several libraries for using databases at the address [https://mvnrepository.com/](https://mvnrepository.com/). We will show an example of how to begin using the database management system called [H2](http://www.h2database.com/html/main.html). This can be done by adding the H2 library to the file `pom.xml`, between the tags `` and ``, which is the area for the library dependencies. You can take a look at the example below. ```xml - + - + com.h2database @@ -65,172 +65,51 @@ There are several libraries for using databases at the address [https://mvnrepos 1.4.197 - + - + ``` - + This has already been done in the exercise base. When the library dependency has been configured as part of the project, the classes included in that library are usable in the project. In the following exercise you are going to use the previously described dependency, and implement a program that uses a database to manage data. - + - -The exercise base contains an application that has the H2 database configured as a dependency. It also includes the following four classes: - +The exercise base contains an application that has the H2 database configured as a dependency. It also includes the following four classes: -- `Todo`: a class that represents a task that is to be done. Each todo has a numerical identifier (id), a name, a description, and the information abot whether it has been done. - -- `TodoDao`: a class that is used to store todos to the database. The word "dao" comes from the phrase "data access object". The class offers methods for listing, adding, setting as completed, and removing todos. Removing or setting as done is done on the basis of the id. The class constructor receives the location of the database. +- `Todo`: a class that represents a task that is to be done. Each todo has a numerical identifier (id), a name, a description, and the information abot whether it has been done. - -- `UserInterface`: a class that is used to ask the user for instructions for what to do. The constructor receives a Scanner object and a TodoDao object as its parameters. Calling the `start` method starts the user interface, after which the user controls the program with their keyboard input. - +- `TodoDao`: a class that is used to store todos to the database. The word "dao" comes from the phrase "data access object". The class offers methods for listing, adding, setting as completed, and removing todos. Removing or setting as done is done on the basis of the id. The class constructor receives the location of the database. -- `Program`: a class that serves as a starting point for the program. - +- `UserInterface`: a class that is used to ask the user for instructions for what to do. The constructor receives a Scanner object and a TodoDao object as its parameters. Calling the `start` method starts the user interface, after which the user controls the program with their keyboard input. -In this exercise it is your task to modify the user interface so that the user of the program can add new todos, or list, mark as done, or remove existing ones. Don't do changes in the classes `Todo`, `TodoDao`, or `Program`. - -The finished program is expected to behave in the following manner: +- `Program`: a class that serves as a starting point for the program. - ``` @@ -355,7 +234,7 @@ Thank you! ``` - + The text user interface in this exercise does not differ in any essential way from the earlier text UIs we have created. The difference is that the data is being stored in a database: *the stored data will be available for the program when it is started the next time.* @@ -364,11 +243,11 @@ The text user interface in this exercise does not differ in any essential way fr ## Telegram bot - + As we mentioned above, you can use Maven to find a great number of libraries you can use as a part of your own applications. By searching telegram from [https://mvnrepository.com/](https://mvnrepository.com/) you find e.g the [TelegramBots](https://github.com/rubenlagus/TelegramBots) library for making Telegram bots. - + Telegram bots are programs which react to messages sent on Telegram, and for example tell jokes. Creating these bots is out of the scope of this course, but the skills you have learned will help you to study different tutorials. . If you want to learn to make a Telegram bot, read the guide at [https://github.com/rubenlagus/TelegramBots/wiki/Getting-Started](https://github.com/rubenlagus/TelegramBots/wiki/Getting-Started). @@ -378,25 +257,25 @@ Remember to start implementing your bot bit by bit -- start by for example makin ## Packaging applications - + So far it has seemed like our applications have required a development environment to work. This is not strictly true however, because executing a program on a development environment is quite the same as executing a program outside of it. We can define a class which contains the `public static void main` method for starting the program. - + Oracle has a [javapackager](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/javapackager.html) tool for packaging an application. You can find information about using it from [https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/packager.html](https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/packager.html). - + Using the instructions on the website linked above you can create packaged versions of your applications you can share with others. The library used in the instructions can be found packaged as a Maven plugin from [https://github.com/javafx-maven-plugin/javafx-maven-plugin](https://github.com/javafx-maven-plugin/javafx-maven-plugin). - + There are other tools for packaging, for example the [JavaPackager](https://github.com/fvarrui/JavaPackager) Maven plugin. ## Other development environment - + Java is one of the most used programming languages in the world, and it is used i.e in Android phones. The techniques for creating graphical user interfaces practiced in this course can be used for mobile applications as well, altough JavaFX is primarily targeted for desktop applications. If you want to use JavaFX for a mobile application, [JavaFXPorts](https://gluonhq.com/products/mobile/javafxports/) project is created for that. @@ -404,7 +283,7 @@ The JavaFXPorts project can be used to create mobile applications using the Java You can find more information about it from [https://docs.gluonhq.com/javafxports/](https://docs.gluonhq.com/javafxports/). - + If you are interested in developing mobile applications, it is worth it to study the Android's developer guide for app developers which can be found from [https://developer.android.com/guide/](https://developer.android.com/guide/). This programming course has given you excellent basis for learning app development. Correspondingly if you are interested in developing simple (mobile) games, we recommend learning to use the [FXGL](https://github.com/AlmasB/FXGL/wiki) library. diff --git a/data/part-14/5-conclusion.md b/data/part-14/5-conclusion.md index 21f571006..711fae609 100644 --- a/data/part-14/5-conclusion.md +++ b/data/part-14/5-conclusion.md @@ -4,7 +4,7 @@ title: 'Conclusion' hidden: false --- - + In this last part we looked into data visualization, displaying media programmatically and some third party libraries. We also took some time to create a little asteroid game. If you feel insipired you can keep adding features to the game you made. diff --git a/data/part-14/index.md b/data/part-14/index.md index f3baab13f..b00922d47 100644 --- a/data/part-14/index.md +++ b/data/part-14/index.md @@ -5,7 +5,7 @@ overview: true hidden: false --- - + In the fourteenth part you will learn methods for data visualization and acquaint yourself with Java's existing charts (line chart, bar chart). You will learn to make simple drawings and take a look at image processing. You will also learn to play audio files. Finally, there is a slightly larger program -- the Asteroids game -- that you will create by following an example. @@ -13,7 +13,7 @@ In the fourteenth part you will learn methods for data visualization and acquain - + diff --git a/data/part-2/1-problems-and-patterns.md b/data/part-2/1-problems-and-patterns.md index feec7896a..e6924e0f2 100644 --- a/data/part-2/1-problems-and-patterns.md +++ b/data/part-2/1-problems-and-patterns.md @@ -6,9 +6,7 @@ hidden: false - + - You recognize that certain sub-problems, such as reading input or calculations, recur in programs. - You're aware of solution models to certain sub-problems. @@ -16,42 +14,24 @@ hidden: false - + The same small problems, or "sub-problems", reappear in programs time after time: "Read input from the user", "Calculate the sum of values", and so forth. - + Let's look at a few sub-problems and patterns for solving them. - + ## Reading User Input - -The solution pattern for programming tasks involving reading user input is straightforward. If the program needs to read from the user, a Scanner helper tool is created for the task. The Scanner is created in the main method after the line `public static void main(String[] args) {`. To use the Scanner, it needs to be made available in the program through the statement `import java.util.Scanner;`, which comes before the class definition (`public class ...`). Importing the Scanner tool makes it available for the program. - ```java // Making the scanner available in the program @@ -75,38 +55,25 @@ public class Program { - + ## Calculating - + We quite often need to calculate something in a program, such as an average or a sum. The solution pattern to solve such problems is as follows. - + 1. Define the inputs required for the calculation and declare variables for them. Input refers to the values used in the calculation. You can typically identify the type of inputs from the problem description. 2. Identify the operation needed, and declare a variable for the result of the calculation. Perform the calculation using the inputs, and assign the result to the variable that was reserved for it. The type of the result can also usually be identified from the problem description. 3. Once the calculation is done, do something with its result. This can mean printing the result of a computation, or, for example, using it in calculating an average by dividing a sum of the inputs by their count. - -For example, the solution pattern for the problem _Create a program to calculate the sum of two integers_ is the following. - ```java // Identifying the input values and declaring the variables for them @@ -120,37 +87,11 @@ int sum = first + second; System.out.println("The sum of " + first + " and " + second + " is " + sum); ``` - -A program that both reads and calculates combines both of these patterns. One that calculates the product of two integers provided by the user looks like this: - ```java // Making the scanner available in the program @@ -179,32 +120,11 @@ public class Program { } ``` - -In the example above, the program has been implemented so that the variables are declared first after which values are read into them. Variable declaration and the reading of values into them can also be combined into one. - ```java // Making the Scanner available to the program @@ -231,7 +151,7 @@ public class Program { - + Write a program that reads an integer from the user and prints the square of the given integer, i.e. the integer multiplied by itself. @@ -261,17 +181,13 @@ Write a program that reads an integer from the user and prints the square of the - + Write a program that reads two integers from the user and prints the square root of the sum of these integers. The program does not need to work with negative values. - + You can calculate the square root of an integer with the command `Math.sqrt` like this: - + ```java int number = 42; @@ -279,7 +195,7 @@ double squareRoot = Math.sqrt(number); System.out.println(squareRoot); ``` - + Here are a few examples: @@ -310,20 +226,15 @@ Here are a few examples: - + ## Conditional Logic - + Problems often contain some conditional logic. In these instances we use conditional statements. A conditional statement starts with an `if` command followed by an expression in parentheses. The expression evaluates to either true or false. If it evaluates true, the following block delimited by curly brackets gets executed. - + ```java // if the value is greater than five @@ -332,18 +243,11 @@ if (value > 5) { } ``` - + A program that prints "ok" if the value of the variable is greater than `42`, and otherwise prints "not ok" looks like this: - + ```java int value = 15; @@ -354,21 +258,11 @@ if (value > 42) { } ``` - + You can also chain together multiple conditions. In such a case, the problem takes the form "if a, then b; else if c, then d; else if e, then f; otherwise g". The chain consists of an `if`-statement followed by `else if`-statements, each containing its own expression and a block. - + ```java // if the value is greater than five @@ -384,7 +278,7 @@ if (value > 5) { - + The quiz below uses `System.out.print` for printing. It works exactly like `System.out.println`, but it doesn't add a line break to the end of the output. @@ -393,40 +287,11 @@ The quiz below uses `System.out.print` for printing. It works exactly like `Syst - -Conditional logic can be combined with other patterns used for problem solving. Let's look into a problem "Read two integers from the user. If the sum of the integers is over 100, print `too much`. If the sum is less than 0, print `too little`. Otherwise, print `ok`. The program below combines reading, calculating and conditional functionality. - ```java // Bringing Scanner to the program's use @@ -459,10 +324,10 @@ public class Program { ``` - + - + Write a program that reads an integer from the user. If the number is less than 0, the program prints the given integer multiplied by -1. In all other cases, the program prints the number itself. A few examples of how the program's expected to function are shown below: @@ -489,14 +354,14 @@ Write a program that reads an integer from the user. If the number is less than - + - + Write a program that reads two integers from the user. If the first number is greater than the second, the program prints "(first) is greater than (second)." If the first number is less than the second, the program prints "(first) is smaller than (second)." Otherwise, the program prints "(first) is equal to (second)." The (first) and (second) should always be replaced with the actual numbers that were provided by the user. - + A few examples of the expected behaviour: diff --git a/data/part-2/2-repeating.md b/data/part-2/2-repeating.md index 527b26394..4cbf0cb3f 100644 --- a/data/part-2/2-repeating.md +++ b/data/part-2/2-repeating.md @@ -7,27 +7,27 @@ hidden: false - + - You are familiar with loops and know how to create a program that contains one. - + - You know how to use the `break` command to end a loop's execution. - + - You know how to use `continue` command to return to the beginning of a loop. - + - You are able to create a program that reads inputs from a user until a specific input is given. For example, the number 0 or the string "end", after which the program prints something about the provided inputs (e.g., the input count, and in the case of numbers their sum and average). - + A computer's processor, which specializes in executing commands, is capable of executing -- in a modern computer -- over a billion (machine code) commands in a second. In this section, we'll get used to writing often-repeated program code with the help of loops. - + Let's motivate ourselves to use loops. Below you'll find an example of a program that asks the user for five numbers and calculates their sum. ```java @@ -52,10 +52,10 @@ sum = sum + Integer.valueOf(scanner.nextLine()); System.out.println("The sum of the numbers is " + sum); ``` - + It does the job, but not elegantly. What if the program had to read a hundred, or perhaps a thousand numbers and print their sum? What if the program had to read three numbers only? - + The problem can be solved with a loop which keeps track of both the sum and the number of times input has been read. The program that prints the sum of five numbers now looks as follows ```java @@ -77,12 +77,12 @@ while (true) { System.out.println("The sum of the numbers is " + sum); ``` - + Next off we will get familiar with loops. - + ## Loops and Infinite Loops - + A loop consists of an expression that determines whether or not the code within the loop should be repeated, along with a block containing the source code to be repeated. A loop takes the following form. ```java @@ -92,11 +92,11 @@ while (_expression_) { } ``` - - + + We'll use the value `true` as the loop's expression for now. This way, the loop's execution is always continued when the program arrives at the point that decides whether it should be repeated or not. This happens when the execution of the program first arrives at the loop expression for the first time, and also when it reaches the end of the loop's block. - + The loop execution proceeds line-by-line. The following program outputs _I can program_ an infinite number of times. ```java @@ -105,17 +105,17 @@ while (true) { } ``` - + A program that runs infinitely does not end on its own. In NetBeans, it can be shut down by clicking the red button located on the left side of the output window. - + # Ending a Loop - + The loop can be broken out of with command 'break'. When a computer executes the command 'break', the program execution moves onto the next command following the loop block. - + The example below is a program that prints numbers from one to five. Note how the variable that's used within the loop is defined before the loop. This way the variable can be incremented inside the loop and the change sticks between multiple iterations of the loop. ```java @@ -144,13 +144,13 @@ Ready! - + Breaking out of the loop occurs when a user enters a specified input or whenever a calculation performed in the loop ends in the desired result. These kinds of programs contain both a loop used to define a section to be repeated and also a conditional expression used to check whether or not the condition to exit the loop has been fulfilled. - + Users can also be asked for input within a loop. The variables that are commonly used in loops (such as Scanner readers) are defined before the loop, whereas variables (such as the value read from the user) that are specific to the loop are defined within it. - + In the example below, the program asks the user whether to exit the loop or not. If the user inputs the string "y", the execution of the program moves to the command following the loop block, after which the execution of the program ends. ```java @@ -169,7 +169,7 @@ while (true) { System.out.println("Ready!"); ``` - + The program in the example works as follows. The user's inputs are marked in red. @@ -186,10 +186,10 @@ Ready! - + - + Write a program by using the loop example that asks "Shall we carry on?" until the user inputs the string "no". @@ -208,7 +208,7 @@ Shall we carry on? - + In the previous example, the program read inputs of type string from the user. The program can also be implemented with other types of variables. The program below asks numbers from the user until the user inputs a zero. ```java @@ -227,7 +227,7 @@ while (true) { System.out.println("Done, thank you!"); ``` - + The output of the program can be as follows: @@ -244,10 +244,10 @@ Done, thank you! - + - + Write a program, according to the preceding example, that asks the user to input values until they input the value 4. @@ -268,14 +268,14 @@ Give a number: - + ## Returning to the Start of the Loop - + When the execution reaches the end of the loop, the execution starts again from the start of the loop. This means that all the commands in the loop have been executed. You can also return to the beginning from other places besides the end with the command `continue`. When the computer executes the command `continue`, the execution of the program moves to the beginning of the loop. - - + + The example below demonstrates the use of the `continue` command. The program asks the user to input positive numbers. If the user inputs a negative number or a zero, the program prints the message "Unfit number, try again", after which the execution returns to the beginning of the loop. In the previous example, the program read inputs of type string from the user. Similar programs with different input types are also possible. In the example below, the user is asked for numbers until they input a zero. ```java @@ -294,10 +294,10 @@ while (true) { } ``` - + The program in the example above is repeated infinitely since the `break` command used for exiting the loop is not used. To exit the loop, the `break` command must be added to it. - + In the example below, the program is modified in such a way that the user is asked to input positive numbers. If the user inputs a negative number, the program informs them that the number was unfit and returns to the beginning of the loop. If the number was zero, the program exits the loop. ```java @@ -320,15 +320,15 @@ while (true) { } ``` - - + + - + - + Write a program that asks the user for numbers. If the number is negative (smaller than zero), the program prints for user "Unsuitable number" and asks the user for a new number. If the number is zero, the program exits the loop. If the number is positive, the program prints the number to the power of two. @@ -352,7 +352,7 @@ Give a number: - + In the previous exercise, you made a program that asks the user for numbers. If the user entered a negative number, the program would inform them that the number was unfit, and if the user entered a zero, the program would exit. A possible solution to the exercise is the following. ```java @@ -375,7 +375,7 @@ while (true) { } ``` - + The program could be made by modifying the if-statement to another form. In the example below, the conditionals have been combined to replace separate if-statements. ```java @@ -396,10 +396,10 @@ while (true) { } ``` - + Which of the previous examples was more clear? - + Let's examine the clarity of the previous programs through an example. Below, the program asks the user for a number. If the number is negative, the user is informed that the number is unfit and the execution of the program goes to the beginning of the loop. If the number is zero, the program exits the loop. In other cases the program prints the square of the number, i.e., the number times itself. ```java @@ -422,7 +422,7 @@ while (true) { } ``` - + This program can also be done by combining the if-statements. In that case, the implementations would be the following. ```java @@ -442,7 +442,7 @@ while (true) { } ``` - + Let's examine the previous programs with comments. Before each command, there's a comment that aims to explain what's happening in the program. Below is a program that's written with separate if-statements. ```java @@ -473,10 +473,10 @@ while (true) { } ``` - + Note that every if-statement has a single, clear task. - + When we comment on a program containing combined if-statements, the comments take the following form. ```java @@ -502,25 +502,25 @@ while (true) { } ``` - + We notice that it's difficult to define a single, clear task for `if-else if-else`-block. During the design and implementation of a program, it's desirable to aim for a situation in which every part of the program has a a single, clear task. This theme repeats throughout the course. - - + + ## Calculation with Loops - + Loops are used in computing many different things. For example, programs that process indefinite numbers of user-inputted values make use of loops. These kinds of programs typically print out some sort of statistics about the numbers that were read or other inputs after the end loop. - + For the program to print out information from the loop execution after the loop, the information must be saved and modified during the loop. - + If the variable used to store the data is introduced within the loop, the variable is only available within that loop and nowhere else. - + Let's create a program to count and print out the number of ones entered by the user. Let's first create a non-working version and examine the action of the blocks. ```java @@ -555,7 +555,7 @@ while (true) { System.out.println("The total of ones: " + ones); ``` - + The previous program does not work because the variable `ones` is introduced within the loop, and an attempt is made to use it after the loop at the end of the program. The variable only exists inside the loop. If the print statement `System.out.println("The total of ones: " + ones);` was inside the loop, the program would work, but not in the desired way. Let's examine this next. @@ -589,7 +589,7 @@ while (true) { } ``` - + The example above works, but not in a way we hoped it would. Below the example output of the program @@ -611,10 +611,10 @@ Insert a number (0 exits) - + If you wish to use a variable after a loop, it needs to be introduced before the loop. - + In the example below, the program computes the total of number ones inputted. The inputs are read until the user inputs a zero after which the program prints the total count of number ones entered. The program uses variable `ones` to keep track of the number ones. ```java @@ -646,7 +646,7 @@ while (true) { System.out.println("The total of ones: " + ones); ``` - + Below is an example output of the program. @@ -666,13 +666,13 @@ Total of ones: 2 - + - + Write a program that reads values from the user until they input a 0. After this, the program prints the total number of inputted values. The zero that's used to exit the loop should not be included in the total number count. - + Example output of the program: @@ -694,13 +694,13 @@ Number of numbers: 4 - + - + Write a program that reads values from the user until they input a 0. After this, the program prints the total number of inputted values that are negative. The zero that's used to exit the loop should not be included in the total number count. - + Example output of the program: @@ -721,15 +721,15 @@ Number of negative numbers: 1 - + The programs written in the previous exercises have read input from the user and kept track of the count of certain types of numbers. In the next exercise, the requested sum of numbers is not much different -- this time, rather than keeping track of the number of values entered, you add the number entered by the user to the sum. - + - + Write a program that reads numbers from the user until the user inputs a number 0. After this the program outputs the sum of the numbers. The number zero does not need to be added to the sum, even if it does not change the results. - + Example output of the program: @@ -812,13 +812,13 @@ if (numberOfPositives + numberOfNegatives > 0) { - + Write a program that asks the user for input until the user inputs 0. After this the program prints the amount of numbers inputted and the sum of the numbers. The number zero does not need to be added to the sum, but adding it does not change the results. - + _You need two variables to keep track of the information. Use one for keeping track of the numbers inputted and other for keeping track of the sum_ - + Example output of the program: @@ -843,13 +843,13 @@ Sum of the numbers: 34 - + Write a program that asks the user for input until the user inputs 0. After this, the program prints the average of the numbers. The number zero does not need to be counted to the average. You may assume that the user inputs at least one number. - + _The average of the numbers can be calculated by dividing the sum of numbers with the amount of the numbers_ - + Example output of the program: @@ -873,14 +873,14 @@ Average of the numbers: 8.5 - + Write a program that asks the user for input until the user inputs 0. After this, the program prints the average of the positive numbers (numbers that are greater than zero). - + If no positive number is inputted, the program prints "Cannot calculate the average" - + Below a few examples of the programs output diff --git a/data/part-2/3-more-loops.md b/data/part-2/3-more-loops.md index a2d6fb782..9a21ea651 100644 --- a/data/part-2/3-more-loops.md +++ b/data/part-2/3-more-loops.md @@ -7,9 +7,9 @@ hidden: false - - - + + + - You're familiar with the condition of the `while` loop condition. - You know how to use the `for` loop. - You recognize situations where a `while` loop should be used and those where a `for` loop is more appropriate. @@ -22,22 +22,22 @@ Here, you will answer a questionnaire about motivation and study strategies. The - + The "while-true" loop we've been using is very handy when the program has to repeat a functionality until the user provides certain input. - + Next, we'll come to know a few other ways to implement loops. ## While Loop with a Condition - + So far we have been using a loop with the boolean `true` in its parenthesis, meaning the loop continues forever (or until the loop is ended with the `break` command ). - + Actually, the parenthesis of a loop can contain a conditional expression, or a condition, just like the parenthesis of an `if` statement. The `true` value can be replaced with an expression, which is evaluated as the program is executed. The expression is defined the same way as the condition of a conditional statement. - + The following code prints the numbers 1,2,...,5. When the value of the variable `number` is more than 5, the `while`-condition evaluates to false and the execution of the loop ends for good. @@ -50,17 +50,17 @@ while (number < 6) { } ``` - + The code above can be read "As long as the value of the variable number is less than 6, print the value of the variable number and increase the value of the variable number by one". - + Above, the value of the variable `number` is increased by one every time the loop body is executed. - + Below is a video about using loops. @@ -68,10 +68,10 @@ Below is a video about using loops. ## For Loop - + Above, we learned how a `while` loop with a condition can be used to go through numbers in a certain interval. - + The structure of this kind of loop is the following. ```java @@ -82,10 +82,10 @@ while (i < 10) { } ``` - + The above loop can be split into three parts. First we introduce the variable `i`, used to count the number of times the loop has been executed so far, and set its value to 0: `int i = 0;`. This is followed by the definition of the loop -- the loop's condition is `i < 10` so the loop is executed as long as the value of the variable `i` is less than 10. The loop body contains the functionality to be executed `System.out.println(i);`, which is followed by increasing the value of the variable `i++`. The command `i++` is shorthand for `i = i + 1`. - + The same can be achieved with a `for` loop like so. ```java @@ -94,7 +94,7 @@ for (int i = 0; i < 10; i++) { } ``` - + A `for` loop contains four parts: (1) introducing the variable for counting the number of executions; (2) the condition of the loop; (3) increasing (or decreasing or changing) the value of the counter variable; and (4) the functionality to be executed. @@ -104,12 +104,12 @@ for (*introducing a variable*; *condition*; *increasing the counter*) { } ``` - + Loop execution is shown below step by step. - + The example above prints the numbers from zero to four. The interval can also be defined using variables -- the example below uses variables `start` and `end` to define the interval of numbers the loop goes through. @@ -124,13 +124,13 @@ for (int i = start; i < end; i++) { - + We will continue practicing loops in the following exercises. You can use either a `while` loop with a condition, or a `for` loop. - + Write a program that reads an integer from the user. Next, the program prints numbers from 0 to the number given by the user. You can assume that the user always gives a positive number. Below are some examples of the expected functionality. @@ -157,7 +157,7 @@ Write a program that reads an integer from the user. Next, the program prints nu - + Write a program, which reads an integer from the user. Then the program prints numbers from that number to 100. You can assume that the user always gives a number less than 100. Below are some examples of the expected functionality. @@ -192,7 +192,7 @@ Write a program, which reads an integer from the user. Then the program prints n - + Note, that from now on exercises can have multiple parts. All of the parts are counted as separate exercises, so for example the following exercise counts as two separate exercises. Exercises with multiple parts can also typically be submitted even if all parts are not ready -- points for the completed parts are added to your points count. Submitting a partial solution does not prevent you from submitting the full solution later on. @@ -201,13 +201,13 @@ Note, that from now on exercises can have multiple parts. All of the parts are c - + This exercise is the first two-part exercise. When you complete both parts, you will get two exercise points. You can also submit the exercise after completing only the first part.

Where to

- + Write a program which prints the integers from 1 to a number given by the user. @@ -230,13 +230,13 @@ Where to? **5** - + **hint** the number read from the user is now the upper limit of the condition. Remember that in Java `a <= b` means _a is smaller or equal to b_.

Where from

- + Ask the user for the starting point as well. @@ -250,7 +250,7 @@ Where from? **5** - + If the upper limit is larger than the starting point, nothing is printed: @@ -260,7 +260,7 @@ Where from? **16** - + **NB** remember that the lower and upper limits can be negative!
@@ -268,10 +268,10 @@ Where from? **16** ## On Stopping a Loop Execution - + A loop does not stop executing immediately when its condition evaluates to true. A loop's condition is evaluated at the start of a loop, meaning when (1) the loop starts for the first time or (2) the execution of a previous iteration of the loop body has just finished. - + Let's look at the following loop. ```java @@ -285,7 +285,7 @@ while (number != 2) { } ``` - + It prints the following: @@ -300,15 +300,15 @@ It prints the following: - + Even though `number` equals 2 at one point, the loop runs forever. - + **The condition of a loop is evaluated when the execution of a loop starts and when the execution of the loop body has reached the closing curly bracket.** If the condition evaluates to `true`, execution continues from the top of the loop body. If the condition evaluates to `false`, execution continues from the first statement following the loop. - + This also applies to `for` loops. In the example below, it would be incorrect to assume that the loop execution ends when `i` equals 100. However, it doesn't. ```java @@ -320,17 +320,17 @@ for (int i = 0; i != 100; i++) { } ``` - + The loop above never stops executing. ## Repeating Functionality - + One common subproblem type is to "do something a certain amount of times". What's common to all these programs is repetition. Some functionality is done repeatedly, and a counter variable is used to keep track of the repetitions. - + The following program calculates the product 4*3 somewhat clumsily, i.e., as the sum 3 + 3 + 3 + 3: ```java @@ -349,7 +349,7 @@ while (true) { System.out.println(result); ``` - + The same functionality can be achieved with the following code. ```java @@ -365,7 +365,7 @@ while (i < 4) { System.out.println(result); ``` - + Or by using a for loop as seen in the following. ```java @@ -378,7 +378,7 @@ for (int i = 0; i < 4; i++) { System.out.println(result); ``` - + The program execution using a while loop is visualized below. @@ -387,13 +387,13 @@ The program execution using a while loop is visualized below. - + As the number of variables increases, understanding a program becomes harder. Simulating program execution can help in understanding it. - + You can simulate program execution by drawing a table containing a column for each variable and condition of a program, and a separate space for program output. You then go through the source code line by line, and write down the changes to the state of the program (the values of each variable or condition), and the program output. - + The values of variables `result` and `i` from the previous example have been written out onto the table below at each point the condition `i < 4` is evaluated.
@@ -434,34 +434,34 @@ The values of variables `result` and `i` from the previous example have been wri - + Implement a program, which calculates the sum 1+2+3+...+n where n is given as user input. - + Sample output: - - + + Last number? **3** The sum is 6 - + The previous example calculated 1 + 2 + 3 = 6 - - + + Last number? **7** The sum is 28 - + And this one calculated 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28 @@ -469,41 +469,41 @@ And this one calculated 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28 - + Implement a program which calculates the sum of a closed interval, and prints it. Expect the user to write the smaller number first and then the larger number. - + You can base your solution to this exercise to the solution of last exercise -- add the functionality for the user to enter the starting point as well. - + Sample output: - - - + + + First number? **3** Last number? **5** The sum is 12 - + The above example internally calculated 3 + 4 + 5 = 12 - - - + + + First number? **2** Last number? **8** The sum is: 35 - + And now the internal calculation was 2 + 3 + 4 + 5 + 6 + 7 + 8 = 35 @@ -511,41 +511,41 @@ And now the internal calculation was 2 + 3 + 4 + 5 + 6 + 7 + 8 = 35 - + Implement a program which calculates the factorial of a number given by the user. - + Factorial of n, denoted `n!`, is calculated as 1 * 2 * 3 * ... * n. For example, the factorial of 4 is 24 or 4! = 1 * 2 * 3 * 4 = 24. Additionally, it has been specified that the factorial of 0 is 1, so 0! = 1. - + Sample output: - - + + Give a number: **3** Factorial: 6 - - + + The internal calculation here was 1 * 2 * 3 = 6 - - + + Give a number: **10** Factorial: 3628800 - + And now the internal calculation was 1 * 2 * 3 * ... * 8 * 9 * 10 = 3628800 - + _Additional info_: Factorials are used especially in probability calculus when examining different possible orders of a set. For example, a group of five people can form 5! different lines, and a pack of 52 cards can be in 52! different orders. Factorial can also be used to calculate combinations; For example it is possible to deal 52! / (5! * (52-5)!) different hands from a 52 card pack, and you can form 40! / (7! * (40 - 7)!) different 7 number lottery lines from 40 numbers. @@ -553,16 +553,16 @@ _Additional info_: Factorials are used especially in probability calculus when e ## On the Structure of Programs Using Loops - + In the previous examples, we have concentrated on cases where the loop is executed a predetermined number of times. The number of repetitions can be based on user input -- in these cases, the for loop is quite handy. - + In programs where the loop body has to be executed until the user gives certain input, the for loop is not too great. In these cases, the while-true loop we practiced earlier works well. - + Let's take a look at a somewhat more complex program that reads integers from the user. The program handles negative numbers as invalid, and zero stops the loop. When the user enters zero, the program prints the sum of valid numbers, the number of valid numbers and the number of invalid numbers. - + A possible solution is detailed below. However, the style of the example is not ideal. ```java @@ -593,10 +593,10 @@ while (true) { } ``` - + In the code above, the computation executed after the loop has ended has been implemented inside of the loop. This approach is not recommended as it can easily lead to very complex program structure. If something else -- for example, reading more input -- is to be done when the loop ends, it could also easily end up being placed inside of the loop. As more and more functionality is needed, the program becomes increasingly harder to read. - + Let's stick to the following loop structure: ```java @@ -617,7 +617,7 @@ while (true) { // functionality to execute after the loop ends ``` - + In other words, the program structure is cleaner if the things to be done after the loop ends are placed outside of it. ```java @@ -652,21 +652,21 @@ System.out.println("Invalid numbers: " + invalidNumbers); - + Next, we'll implement a program one piece at a time. This is always strongly recommended when coding. - + The series of exercises form a larger program whose functionality is implemented in small pieces. If you do not finish the whole series, you can still submit the parts you've completed to be checked. This can be done by clicking the "submit" button (the arrow pointing up) to the right of the "test" button. Although the submission system complains about the tests of unfinished parts, you get points for the parts you have finished. - + NB: Remember that each sub-part of the series is equivalent to one individual exercise. As such, the series is equivalent to five individual exercises. **Note:** the tests might fail a correct solution. This is a known bug that will be fixed in the future. In the meantime, you can avoid the error by printing "Give numbers:" without **any** spaces after ':'

Reading

- + Implement a program that asks the user for numbers (the program first prints "Write numbers: ") until the user gives the number -1. When the user writes -1, the program prints "Thx! Bye!" and ends. @@ -683,7 +683,7 @@ Thx! Bye!

Sum of numbers

- + Extend the program so that it prints the sum of the numbers (not including the -1) the user has written. @@ -701,7 +701,7 @@ Sum: 11

Sum and the number of numbers

- + Extend the program so that it also prints the number of numbers (not including the -1) the user has written. @@ -720,7 +720,7 @@ Numbers: 3

Average of numbers

- + Extend the program so that it prints the mean of the numbers (not including the -1) the user has written. @@ -740,7 +740,7 @@ Average: 3.666666666666

Even and odd numbers

- + Extend the program so that it prints the number of even and odd numbers (excluding the -1). @@ -764,16 +764,16 @@ Odd: 1 - + In the previous exercise, we used a series of exercises to practice implementing a program one piece at a time. - + When you are writing a program, whether it's an exercise or a personal project, figure out the types of parts the program needs to function and proceed by implementing them one part at a time. Make sure to test the program right after implementing each part. - + Never try solving the whole problem at once, because that makes running and testing the program in the middle of the problem-solving process difficult. Start with something easy that you know you can do. When one part works, you can move on to the next. - + Some of the exercises are already split into parts. However, it's often the case in programming that these parts need to be split into even smaller parts. You should almost always run the program after every new line of code. This ensures that the solution is moving in the right direction. diff --git a/data/part-2/4-methods.md b/data/part-2/4-methods.md index 41b7b7753..a7a8bbe95 100644 --- a/data/part-2/4-methods.md +++ b/data/part-2/4-methods.md @@ -5,59 +5,48 @@ title: 'Methods and dividing the program into smaller parts' hidden: false --- - + - + - You are familiar with the concepts of a method parameter, a method's return value, and a program's call stack. - + - You know how to create methods and how to call them from both the main program (the `main` method) as well as from inside other methods. - + - You can create parameterized and non-parameterized methods, and you can create methods that return a value. - + So far, we've used various commands: value assignment, calculations, conditional statements, and loops. - + Printing to the screen has been done with the statement `System.out.println()`, and the reading of values with `Integer.valueOf(scanner.nextLine())`. `if` has been used in conditional statements, and `while` and `for` in loops. We notice that printing and reading operations somewhat differ from `if`, `while`, and `for` in that the print and read commands are followed by parentheses, which may include parameters passed to the command. The ones that "end in parentheses" are not actually commands, but methods. - + Technically speaking, **a method** is a named set of statements. It's a piece of a program that can be called from elsewhere in the code by the name given to the method. For instance `System.out.println("I am a parameter given to the method!")` calls a methods that performs printing to the screen. The internal implementation of the method -- meaning the set of statements to be executed -- is hidden, and the programmer does not need to concern themselves with it when using the method. - + So far all the methods we have used have been ready-made Java methods. Next we will learn to create our own methods. - + ## Custom Methods - + **A method** means a named set consisting of statements that can be called from elsewhere in the program code by its name. Programming languages offer pre-made methods, but programmers can also write their own ones. It would, in fact, be quite exceptional if a program used no methods written by the programmer, because methods help in structuring the program. From this point onward nearly every program on the course will therefore contain custom-created methods. - -In the code boilerplate, methods are written outside of the curly braces of the `main`, yet inside out the "outermost" curly braces. They can be located above or below the main. - ```java import java.util.Scanner; @@ -72,15 +61,11 @@ public class Example { } ``` - + Let's observe how to create a new method. We'll create the method `greet`. - + ```java public static void greet() { @@ -88,25 +73,11 @@ public static void greet() { } ``` - + And then we'll insert it into a suitable place for a method. - ```java import java.util.Scanner; @@ -124,37 +95,15 @@ public class Example { } ``` - -The definition of the method consists of two parts. The first line of the definition includes the name of the method, i.e. `greet`. On the left side of the name are the keywords `public static void`. Beneath the line containing the name of the method is a code block surrounded by curly brackets, inside of which is the code of the method -- the commands that are executed when the method is called. The only thing our method `greet` does is write a line of text on the screen. - - -Calling a custom method is simple: write the name of the methods followed by a set of parentheses and the semicolon. In the following snippet the main program (main) calls the greet method four times in total. +The definition of the method consists of two parts. The first line of the definition includes the name of the method, i.e. `greet`. On the left side of the name are the keywords `public static void`. Beneath the line containing the name of the method is a code block surrounded by curly brackets, inside of which is the code of the method -- the commands that are executed when the method is called. The only thing our method `greet` does is write a line of text on the screen. - ```java import java.util.Scanner; @@ -180,20 +129,11 @@ public class ProgramStructure { } ``` - -The execution of the program produces the following output: - @@ -206,39 +146,31 @@ Greetings from the method world! - + The order of execution is worth noticing. The execution of the program happens by executing the lines of the main method (`main`) in order from top to bottom, one at a time. When the encountered statement is a method call, the execution of the program moves inside the method in question. The statements of the method are executed one at a time from top to bottom. After this the execution returns to the place where the method call occured, and then proceeds to the next statement in the program. - + - + Strictly speaking, the main program (`main`) itself is a method. When the program starts, the operating system calls `main`. The main method is the starting point for the program, since the execution begins from its first line. The execution of a program ends at the end of the main method. - + - + Create a method called `printText` which prints the phrase "In a hole in the ground there lived a method" and a newline. - ```java public static void main(String[] args) { @@ -250,15 +182,11 @@ public static void printText() { } ``` - -The output of the program: - @@ -269,25 +197,16 @@ In a hole in the ground there lived a method - + - + Expand the previous program so that the main program asks the user for the number of times the phrase will be printed (i.e. how many times the method will be called). - ```java public static void main(String[] args) { @@ -300,22 +219,10 @@ public static void printText() { } ``` - -Sample output: - @@ -331,7 +238,7 @@ In a hole in the ground there lived a method - + **NB:** print the prompt `How many times?` on its own separate line! @@ -339,27 +246,23 @@ In a hole in the ground there lived a method - + From here on out, when introducing methods, we will not explicitly mention that they must be located in the correct place. Methods cannot be defined e.g. inside other methods. - + On Naming Methods - + The names of methods begin with a word written entirely with lower-case letters, and the rest of the words begin with an upper-case letter - this style of writing is known as camelCase. Additionally, the code inside methods is indented by four characters. - + In the code example below the method is poorly named. It begins with an upper-case letter and the words are separated by \_ characters. The parentheses after the method name have a space between and indentation in the code block is incorrect. - + ```java public static void This_method_says_woof ( ) { @@ -367,15 +270,11 @@ System.out.println("woof"); } ``` - + In contrast the method below is correctly named: The name begins with a lower-case letter and the words are joined together with the camelCase style, meaning that each word after the first begins with an upper-case letter. The parentheses sit next to one another and the contents are correctly indented (the method has its own code block, so the indentation of the code is four characters). - + ```java public static void thisMethodSaysWoof() { @@ -385,15 +284,15 @@ public static void thisMethodSaysWoof() { - + ## Method Parameters - + **Parameters** are values given to a method that can be used in its execution. The parameters of a method are defined on the uppermost line of the method within the parentheses following its name. The values of the parameters that the method can use are copied from the values given to the method when it is executed. - + In the following example a parameterized method `greet` is defined. It has an `int` type parameter called `numOfTimes`. @@ -407,17 +306,11 @@ public static void greet(int numOfTimes) { } ``` - + We will call the method `greet` with different values. The parameter `numOfTimes` is assigned the value `1`on the first call, and `3`on the second. - + ```java public static void main(String[] args) { @@ -427,15 +320,7 @@ public static void main(String[] args) { } ``` - @@ -448,15 +333,11 @@ Greetings! - + Just like when calling the predefined method `System.out.println`, you can pass an expression as a parameter. - + ```java public static void main(String[] args) { @@ -465,13 +346,7 @@ public static void main(String[] args) { ``` - @@ -481,25 +356,21 @@ Greetings! - + If an expression is used as a parameter for a method, the expression is evaluated prior to the method call. Above, the expression evaluates to `3` and the final method call is of the form `greet(3);`. - + - + Create the following method in the exercise template: `public static void printUntilNumber(int number)`. It should print the numbers from one to the number passed as a parameter. Two examples of the method's usage are given below. - + ```java public static void main(String[] args) { @@ -517,11 +388,7 @@ public static void main(String[] args) { - + ```java public static void main(String[] args) { @@ -539,13 +406,13 @@ public static void main(String[] args) {
- + - + Create the following method in the exercise template: `public static void printFromNumberToOne(int number)`. It should print the numbers from the number passed as a parameter down to one. Two examples of the method's usage are given below. @@ -566,13 +433,7 @@ public static void main(String[] args) { - ```java @@ -591,19 +452,15 @@ public static void main(String[] args) { - + ### Multiple Parameters - + A method can be defined with multiple parameters. When calling such a method, the parameters are passed in the same order. - + ```java public static void sum(int first, int second) { @@ -611,14 +468,7 @@ public static void sum(int first, int second) { } ``` - ```java sum(3, 5); @@ -629,12 +479,7 @@ int number2 = 4; sum(number1, number2); ``` - @@ -647,32 +492,28 @@ The sum of numbers 2 and 4 is 6 - + - + Write a method `public static void division(int numerator, int denominator)` that prints the result of the division of the numerator by the denominator. Keep in mind that the result of the division of the integers is an integer -- in this case we want the result to be a floating point number. - + - + Write a method `public static void divisibleByThreeInRange(int beginning, int end)` that prints all the numbers divisible by three in the given range. The numbers are to be printed in order from the smallest to the greatest. - + ```java public static void main(String[] args) { @@ -688,13 +529,7 @@ public static void main(String[] args) { - ```java @@ -715,36 +550,15 @@ public static void main(String[] args) { - -### Parameter Values Are Copied in a Method Call - - -As a method is called **the values of its parameters are copied**. In practice, this means that both the main method and the method to be called can use variables with the same name. However, changing the value of the variables inside the method does not affect the value of the variable in the main method that has the same name. Let's examine this behavior with the following program. +### Parameter Values Are Copied in a Method Call - ```java public class Example { @@ -769,7 +583,7 @@ public class Example { } ``` - + The output of the program is: @@ -786,7 +600,7 @@ The output of the program is: - + Beneath, you'll find the same program visualized step-by-step. Changing the values of the variables in the method printNumbers does not affect the values in the main method, even though they have the same names. @@ -794,30 +608,15 @@ Beneath, you'll find the same program visualized step-by-step. Changing the valu - + So, method parameters are distinct from the variables (or parameters) of other methods, even if they had the same name. As a variable is passed to a method during a method call, the value of that variable gets copied to be used as the value of the parameter variable declared in the method definition. Variables in two separate methods are independent of one another. - + To further demonstrate this point, let's consider the following example. We define a variable called `number` in the main method. That variable is passed as a parameter to the method `incrementByThree`. - ```java // main program @@ -836,18 +635,11 @@ public static void incrementByThree(int number) { } ``` - -The execution of the program produces the following output. - @@ -858,19 +650,18 @@ The value of the variable 'number' in the main program: 1 - + When the variable `number` is incremented inside the method, there's no issue. This, however, is not reflected in the `number` variable of the main program. The `number` variable living in the main program is different from the `number` variable of the method. - + - + The parameter `number` is copied for the method's use, i.e., a new variable called `number` is created for `incrementByThree` method, to which the value of the variable`number` in the main program is copied during the method call. The variable `number` inside the method `incrementByThree` exists only for the duration of the method's execution and has no relation to the variable of the same name in the main program. @@ -878,19 +669,15 @@ The parameter `number` is copied for the method's use, i.e., a new variable call - + ## Methods Can Return Values - + The definition of a method tells whether that method returns a value or not. If it does, the method definition has to include the type of the returned value. Otherwise the keyword `void` is used in the definition. The methods we've created so far have been defined with the keyword `void`, meaning that they have not returned values. - + ```java public static **void** incrementByThree() { @@ -898,19 +685,15 @@ public static **void** incrementByThree() { } ``` - + The keyword `void` means that the method returns nothing. If we want the method to return a value, the keyword must be replaced with the type of the return variable. In the following example, there is a method called `alwaysReturnsTen` which returns an integer-type (`int`) variable (in this case the value 10). - + To actually return a value, we use the command `return` followed by the value to be returned (or the name of the variable whose value is to be returned). - + ```java public static int alwaysReturnsTen() { @@ -918,16 +701,10 @@ public static int alwaysReturnsTen() { } ``` - + The method defined above returns an `int`-type value of `10` when called. For the return value to be used, it must be stored in a variable. This is done the same way as regular value assignment to a variable, by using an equals sign. - ```java public static void main(String[] args) { @@ -937,16 +714,12 @@ public static void main(String[] args) { } ``` - + The return value of the method is placed in an `int` type variable as with any other `int` value. The return value can also be used in any other expression. - ```java double number = 4 * alwaysReturnsTen() + (alwaysReturnsTen() / 2) - 8; @@ -954,27 +727,23 @@ double number = 4 * alwaysReturnsTen() + (alwaysReturnsTen() / 2) - 8; System.out.println("the result of the calculation " + number); ``` - + All the variable types we've encountered so far can be returned from a method.
- + - + - + - + - +
Type of return valueExample
Method returns no value - + ```java public static void methodThatReturnsNothing() { @@ -984,14 +753,10 @@ public static void methodThatReturnsNothing() {
Method returns `int` type variable - + ```java public static int methodThatReturnsInteger() { @@ -1001,14 +766,10 @@ public static int methodThatReturnsInteger() {
Method returns `double` type variable - + ```java public static double methodThatReturnsFloatingPointNumber() { @@ -1022,41 +783,36 @@ public static double methodThatReturnsFloatingPointNumber() { - + Write a method `public static int numberUno()` that returns the value 1. - + - + Write a method `public static String word()`. The method must return a string of your choice. - + When execution inside a method reaches the command `return`, the execution of that method ends and the value is returned to the calling method. - + The lines of source code following the command `return` are never executed. If a programmer adds source code after the return to a place which can never be reached during the method's execution, the IDE will produce an error message. - + For the IDE, a method such as the following is faulty. - + ```java public static int faultyMethod() { @@ -1065,21 +821,11 @@ public static int faultyMethod() { } ``` - -The next method works since it is possible to reach every statement in it -- even though there is source code below the return command. - ```java public static int functioningMethod(int parameter) { @@ -1093,21 +839,12 @@ public static int functioningMethod(int parameter) { } ``` - + If a method has the form `public static void nameOfMethod()` it is possible to return from it -- in other words, to stop its execution in that place -- with the `return` command that is not followed by a value. For instance: - ```java public static void division(int numerator, int denominator) { @@ -1120,22 +857,15 @@ public static void division(int numerator, int denominator) { } ``` - + ## Defining Variables Inside Methods - + Defining variables inside methods is done in the same manner as in the "main program". The following method calculates the average of the numbers it receives as parameters. Variables `sum` and `avg` are used to help in the calculation. - ```java public static double average(int number1, int number2, int number3) { @@ -1146,28 +876,11 @@ public static double average(int number1, int number2, int number3) { } ``` - -One way to call the method is as follows. - ```java public static void main(String[] args) { @@ -1188,23 +901,12 @@ public static void main(String[] args) { } ``` - + Variables defined in a method are only visible inside that method. In the example above, this means that the variables `sum` and `avg` defined inside the method `average` are not visible in the main program. A typical mistake while learning programming is to try and use a method in the following way. - ```java public static void main(String[] args) { @@ -1219,24 +921,15 @@ public static void main(String[] args) { } ``` - + In the above example, an attempt is made to use the variable `avg` that has been defined inside the method `average` and print its value. However, the variable `avg` only exists inside the method `average`, and it cannot be accessed outside of it. - + The following mistakes are also commonplace. - ```java public static void main(String[] args) { @@ -1249,24 +942,15 @@ public static void main(String[] args) { } ``` - + Above, there is an attempt to use the name of the method `average` as if it were a variable. However, a method has to be called. - + As well as placing the method result into a helper variable, another way that works is to execute the method call directly inside the print statement: - ```java public static void main(String[] args) { @@ -1279,7 +963,7 @@ public static void main(String[] args) { } ``` - + Here, the method call occurs first returning the value 5.0, which is then printed with the help of the print statement. @@ -1287,24 +971,19 @@ Here, the method call occurs first returning the value 5.0, which is then printe - + ## Calculating the Return Value Inside a Method - + The return value does not need to be entirely pre-defined - it can also be calculated. The return command that returns a value from the method can also be given an expression that is evaluated before the value is returned. - + In the following example, we'll define a method sum that adds the values of two variables and returns their sum. The values of the variables to be summed are received as method parameters. - + ```java public static int sum(int first, int second) { @@ -1312,45 +991,26 @@ public static int sum(int first, int second) { } ``` - + When the execution of the method reaches the statement `return first + second;`, the expression `first + second` is evaluated, and then its value is returned. - + The method is called in the following way. Below, the method is used to add the numbers 2 and 7 together. The value resulting from the method call is placed into the variable `sumOfNumbers`. - + ```java int sumOfNumbers = sum(2, 7); // sumOfNumbers is now 9 ``` - -Let's expand the previous example so that the numbers are entered by a user. - ```java public static void main(String[] args) { @@ -1370,30 +1030,14 @@ public static int sum(int first, int second) { } ``` - - -In the example above, the method's return value is not stored in a variable but is instead directly used as part of the print operation. The print command's execution is done by the computer first evaluating the string `"The combined sum of the numbers is: "+ sum(first, second)`. The computer first looks for the variables `first` and `second` and copies their values as the values ​​of the method `sum`'s parameters. The method then adds the values of the parameters ​​together, after which it returns a value. This value takes the place of the `sum` method call, whereby the sum is appended to the string `"The combined sum of the numbers is: "`. - -Since the values passed to a method are copied to its parameters, the names of the parameters and the names of the variables defined on the side of the caller have, in fact, nothing to do with each other. In the previous example, both the variables of the main program and the method parameters were named the same (`first` and `second`) "by accident". The code below will function in precisely the same manner even though the variables are named differently: - ```java public static void main(String[] args) { @@ -1413,7 +1057,7 @@ public static int sum(int first, int second) { } ``` - + Now the value of the variable `number1` is copied as the value of the method parameter `first`, and the value of the variable `number2` is copied as the value of the parameter `second`. @@ -1424,30 +1068,20 @@ Now the value of the variable `number1` is copied as the value of the method par - + - + Expand the method `sum` in the exercise template so that it calculates and returns the sum of the numbers that are given as the parameters. - + Create the method using the following structure: - ```java public static int sum(int number1, int number2, int number3, int number4) { @@ -1461,15 +1095,11 @@ public static void main(String[] args) { } ``` - -The output of the program: - @@ -1477,35 +1107,23 @@ Sum: 14 - + **NB:** when an exercise describes a method that should _return_ something, this means that the type of the return value must be declared in the method definition, and that the method contains a `return` command that returns the wanted data. The method itself will print nothing (i.e. will not use the command `System.out.println`) - that task is left to the method caller, which in this case is the main program. - + - -Define a two-parameter method `smallest` that returns the smaller of the two numbers passed to it as parameters. - ```java public static int smallest(int number1, int number2) { @@ -1522,15 +1140,11 @@ public static void main(String[] args) { ``` - -The output of the program: - @@ -1541,25 +1155,16 @@ Smallest: 2 - + - + Define a method called `greatest` that takes three numbers and returns the greatest of them. If there are multiple greatest values, returning one of them is enough. Printing will take place in the main program. - ```java public static int greatest(int number1, int number2, int number3) { @@ -1572,15 +1177,11 @@ public static void main(String[] args) { } ``` - -The output of the program: - @@ -1591,34 +1192,20 @@ Greatest: 7 - + - + Create a method called `average` that calculates the average of the numbers passed as parameters. The previously created method `sum` must be used inside this method! - + Define the method in the following template: - ```java public static int sum(int number1, int number2, int number3, int number4) { @@ -1636,15 +1223,11 @@ public static void main(String[] args) { } ``` - -The output of the program: - @@ -1652,50 +1235,40 @@ Average: 3.5 - + Make sure to remember how to convert an integer (`int`) into a decimal number (`double`)! - + ## Execution of Method Calls and the Call Stack - + How does the computer remember where to return after the execution of a method? - + The environment that executes Java source code keeps track of the method being executed in the call stack. **The call stack** contains frames, each of which includes information about a specific method's internal variables and their values. When a method is called, a new frame containing its variables is created in the call stack. When the execution of a method ends, the frame relating to a method is removed from the call stack, which leads to execution resuming at the previous method of the stack. - + The right side of the visualization below displays the functioning of the call stack. When a method is called, a new frame is created in the stack, which is removed upon exit from the method call. - + - + When a method is called, the execution of the calling method is left waiting for the execution of the called method to end. This can be visualized with the help of a call stack. The call stack refers to the stack formed by the method calls -- the method currently being executed is always on the top of the stack, and when that method has finished executing the execution moves on to the method that is next on the stack. Let's examine the following program: - ```java public static void main(String[] args) { @@ -1709,7 +1282,7 @@ public static void printNumber() { } ``` - + The execution begins from the first line of the `main` method when the program is run. The command on this line prints the text `"Hello world!"`. The call stack of the program looks as follows: @@ -1719,16 +1292,11 @@ main - -Once the print command has been executed, we move on to the next command, which calls the method `printNumber`. Calling this method moves the execution of the program to the beginning of the method `printNumber`. Meanwhile, the `main` method will await for the execution of the method `printNumber` to end. While inside the method `printNumber`, the call stack looks like this: - @@ -1737,7 +1305,7 @@ main - + Once the method `printNumber` completes, we return to the method that is immediately below the method `printNumber` in the call stack -- which in this case is the method `main`. `printNumber` is removed from the call stack, and the execution continues from the line after the `printNumber` method call in the `main` method. The state of the call stack is now the following: @@ -1748,28 +1316,14 @@ main - + ## Call Stack and Method Parameters - -Let's examine the call stack in a situation where parameters have been defined for the method. - ```java public static void main(String[] args) { @@ -1787,7 +1341,7 @@ public static void printStars(int beginning, int end) { } ``` - + The execution of the program begins on the first line of the `main` method. The next two lines create the variables `beginning` and `end`, and also assign values to them. The state of the program prior to calling the method `printStarts`: @@ -1797,18 +1351,11 @@ main end = 5 - + When `printStars` is called, the `main` method enters a waiting state. The method call causes new variables `beginning` and `end` to be created for the method `printStars`, to which the values passed as parameters are assigned to. These values are copied from the variables `beginning` and `end` of the `main` method. The state of the program on the first line of the execution of the method `printStars` is illustrated below. - + printStars @@ -1819,18 +1366,11 @@ main end = 5 - + When the command `beginning++` is executed within the loop, the value of the variable `beginning` that belongs to the method currently being executed changes. - + printStars @@ -1841,7 +1381,7 @@ main end = 5 - + As such, the values of the variables in the method `main` remain unchanged. The execution of the method `printStart` would continue for some time after this. When the execution of that method ends, the execution resumes inside the `main` method. @@ -1852,41 +1392,24 @@ main - + Let's observe the same program by visualizing its execution step-by-step. The application used for visualization grows the call stack downwards -- on the right side, the method on top is always `main`, under which go the methods being called. - - + - -## Call Stack and Returning a Value from a Method - -Let's now study an example where the method returns a value. The `main` method of the program calls a separate `start` method, inside of which two variables are created, the `sum` method is called, and the the value returned by the `sum` method is printed. +## Call Stack and Returning a Value from a Method - ```java public static void main(String[] args) { @@ -1907,30 +1430,22 @@ public static int sum(int number1, int number2) { } ``` - + At the beginning of the `start` method's execution the call stack looks as in the following illustration since it was called from the `main` method. The method `main` has no variables of its own in this example: - + start main - + When the variables `first` and `second` have been created in the `start` method (i.e., the first two rows of that method have been executed), the situation is the following: - + start @@ -1939,20 +1454,11 @@ start main - + The command `int sum = sum(first, second);` creates the variable `sum` in the method `start` and calls the method `sum`. The method `start` enters a waiting state. Since the parameters `number1` and `number2` are defined in the method `sum`, they are created right at the beginning of the method's execution, after which the values of the variables given as parametes are copied into them. - + sum @@ -1965,17 +1471,11 @@ start main - + The execution of the method `sum` adds together the values of the variables `number1` and `number2`. The command `return` returns the sum of the numbers to the method that is one beneath it in the call stack - the method `start` in this case. The returned value is set as the value of the variable `sum`. - + start @@ -1985,47 +1485,27 @@ start main - + After that, the print command is executed, and then we return to the `main` method. Once the execution reaches the end of the `main` method, the execution of the program ends. - + - -## Method Calling Another Method - +## Method Calling Another Method -As we noticed earlier, other methods can be called from within methods. An additional example of this technique is given below. We'll create the method `multiplicationTable` that prints the multiplication table of the given number. The multiplication table prints the rows with the help of the `printMultiplicationTableRow` method. - ```java public static void multiplicationTable(int max) { @@ -2049,7 +1529,7 @@ public static void printMultiplicationTableRow(int number, int coefficient) { } ``` - + The output of the method call `multiplicationTable(3)`, for instance, looks like this. @@ -2059,50 +1539,36 @@ The output of the method call `multiplicationTable(3)`, for instance, looks like 3 6 9 - + Below is a visualization of the method call `multiplicationTable(3)`. Notice how the information about the internal state of the calling method is stored in the call stack. - + - + - +

Printing stars

- + Define a method called `printStars` that prints the given number of stars and a line break. - + Write the method in the following template: - ```java public static void printStars(int number) { @@ -2120,7 +1586,7 @@ public static void main(String[] args) { } ``` - + The output of the program: @@ -2130,15 +1596,15 @@ The output of the program: ********* - + **N.B** multipart exercises can be uploaded to the server (click the button to the right of the testing button) even if some parts are unfinished. In this case the server will complain about the tests for the parts that haven't been completed, but it will mark down the finished parts. - +

Printing a square

- + Define a method called `printSquare(int size)` that prints a suitable square with the help of the `printStars` method. So the method call `printSquare(4)` results in the following output: @@ -2149,20 +1615,20 @@ Define a method called `printSquare(int size)` that prints a suitable square wit **** - + **N.B.:** producing the correct output is not enough; the rows of the square must be produced by calling the `printStars` method inside the `printSquare`method. - + When creating the program, you can use the code in the main to test that the methods behave as required. - +

Printing a rectangle

- + Write a method called `printRectangle(int width, int height)` that prints the correct rectangle by using the `printStars` method. So the method call `printRectangle(17, 3)` should produce the following output: @@ -2173,11 +1639,11 @@ Write a method called `printRectangle(int width, int height)` that prints the co - +

Printing a triangle

- + Create a method called `printTriangle(int size)` that prints a triangle by using the `printStars` method. So the call `printTriangle(4)` should print the following: @@ -2191,29 +1657,29 @@ Create a method called `printTriangle(int size)` that prints a triangle by using
- + - +

Printing stars and spaces

- + Define a method called `printSpaces(int number)` that produces the number of spaces specified by `number`. The method does not print the line break. - + You will also have to either copy the `printStars` method your previous answer or reimplement it in this exercise template. - +

Printing a right-leaning triangle

- + Create a method called `printTriangle(int size)` that uses `printSpaces` and `printStars` to print the correct triangle. So the method call `printTriangle(4)` should print the following: @@ -2225,15 +1691,15 @@ Create a method called `printTriangle(int size)` that uses `printSpaces` and `pr - +

Printing a Christmas tree

- + Define a method called `christmasTree(int height)` that prints the correct Christmas tree. The Christmas tree consists of a triangle with the specified height as well as the base. The base is two stars high and three stars wide, and is placed at the center of the triangle's bottom. The tree is to be constructed by using the methods `printSpaces` and `printStars`. - + For example, the call `christmasTree(4)` should print the following: @@ -2247,7 +1713,7 @@ For example, the call `christmasTree(4)` should print the following: - + The call `christmasTree(10)` should print: @@ -2267,7 +1733,7 @@ The call `christmasTree(10)` should print: - + **NB:** heights shorter than 3 don't have to work correctly! diff --git a/data/part-2/5-end-questionnaire.md b/data/part-2/5-end-questionnaire.md index fb99b2fd0..3c0c02c65 100644 --- a/data/part-2/5-end-questionnaire.md +++ b/data/part-2/5-end-questionnaire.md @@ -4,11 +4,11 @@ title: 'End questionnaire' hidden: false --- - + Programs grow in size as we add more functionality to them. When the program size increases, so does the complexity. This results in source code that is more difficult to understand. In this part, we took our first steps towards managing program complexity: loop structures can be used to execute program code time and again and custom methods allow for dividing a program into smaller, more manageable parts. - + Please take a moment to answer a self-reflective questionnaire on the learning goals of the second part. diff --git a/data/part-2/index.md b/data/part-2/index.md index 0ef8f0ab2..6d202247a 100644 --- a/data/part-2/index.md +++ b/data/part-2/index.md @@ -5,7 +5,7 @@ overview: true hidden: false --- - + The second part of the material focuses on repetition in programs and on how to divide functionality into distinct units. @@ -13,7 +13,7 @@ The second part of the material focuses on repetition in programs and on how to - + The table of contents above lists the topics of the second part of the course. The second part has been designed to cover the second week of the course. You should reserve well above 10 hours for each part of the course, depending on previous experience with computers. If you've tried programming before, you might advance faster in the beginning. diff --git a/data/part-3/1-discovering-errors.md b/data/part-3/1-discovering-errors.md index f022b67f1..07ff873e4 100644 --- a/data/part-3/1-discovering-errors.md +++ b/data/part-3/1-discovering-errors.md @@ -5,7 +5,7 @@ title: 'Discovering errors' hidden: false --- - + - Know the term perceptual blindness, and can learn to recognize essential (and non-essential) information with practice. @@ -14,59 +14,37 @@ hidden: false - + We've so far been practicing the fundamentals of the language, such as variables, conditionals, loops, and methods. Let's now move on to look at some of the factors affecting the understandability of programs, and how errors are found. - + ## A Programmer Blind to Their Own Code - + A programmer often becomes blind to their code. Let's familiarize ourselves with this effect with the aid of the short video below. Count how many times the white-shirted players pass the ball between each other. The video contains instructions in English. - + There's something else that also happens in the video that may go unnoticed at first. This effect is known as perceptual blindness, and is explained by the fact that as we focus on a specific task, our brains tend to filter out information that is irrelevant to that task. However, we don't always know what information is, in fact, essential and what is not - an example of this being when we study. Concentrating on a specific part of a study exercise can lead to relevant information being filtered out. - + Fortunately, applying oneself to a given task lessens the occurrence of perceptual blindness. In other words, practice develops one's ability to distinguish between relevant and irrelevant information. - -One way in which perceptual blindness manifests itself in programming practice is when concentrating on a specific part of a program draws attention away from seemingly correct, yet erroneous parts. For instance, while inspecting the correctness of a program's output, a programmer may fixate on the print statements, and mistakenly neglect some aspects of the logic. - +One way in which perceptual blindness manifests itself in programming practice is when concentrating on a specific part of a program draws attention away from seemingly correct, yet erroneous parts. For instance, while inspecting the correctness of a program's output, a programmer may fixate on the print statements, and mistakenly neglect some aspects of the logic. -Likewise, a programmer may focus on the most complicated aspect of a program featuring a loop, when in fact the error lies somewhere else completely. An example of this is the program below, which is used to calculate the average of user-inputted values. It contains an error, and when searching for it, the loop is typically the first target of focus. - ```java Scanner scanner = new Scanner(System.in); @@ -93,41 +71,19 @@ if (sum == 0) { - + Perceptual blindness is something that one cannot be eliminated completely. However, there are ways by which a programmer can lessen its effect - the first one being taking breaks, which requires that work is begun early. Code comments, proper naming of things, and "debugging" prints are additional examples of things that are also helpful. - + ## Commenting the Source Code - + Comments have many purposes, and one of them is explaining how the code works to oneself when searching for bugs. The execution of a relatively simple program is described below through the use of comments. - ```java @@ -154,37 +110,19 @@ while (value > 0) { } ``` - + Comments have no impact on the execution of the program, i.e., the program works in the same way with the comments as it does without them. - + The comment style displayed above that is intended for learning purposes is, however, too elaborate for real development, where the goal is for the source code to be **self documenting**. This means that the functionality of the program should be evident from the way classes, methods, and variables are named. - + The example can be "commented out" by encapsulating the code into an appropriately named method. Below are two examples of methods that do this - one of the methods is more general in its purpose compared to the other. The more general method assumes, however, that the user knows which of the two parameters is assigned the higher value and which the lower. - ```java public static void printValuesFromTenToOne() { @@ -205,40 +143,19 @@ public static void printValuesFromLargestToSmallest(int start, int end) { } ``` - + ## Searching for Errors with Print Debugging - -One required skill in programming is the ability to test and debug when searching for errors. The simplest way to search for errors is to use so-called print debugging, which in practice involves adding messages to certain lines of code. These messages are used to follow the flow of the program's execution, and can also contain values of variables that live in the program. - +One required skill in programming is the ability to test and debug when searching for errors. The simplest way to search for errors is to use so-called print debugging, which in practice involves adding messages to certain lines of code. These messages are used to follow the flow of the program's execution, and can also contain values of variables that live in the program. -Let's inspect the program already familiar to us from the previous question that was used to calculate the average of non-negative values. - ```java Scanner scanner = new Scanner(System.in); @@ -263,40 +180,11 @@ if (sum == 0) { } ``` - -Had the program contained an error, print debugging could have been used to unravel its functionality by adding print statements in the appropriate places. The example below contains one possible example of a program containing print-debug statements. - - ```java Scanner scanner = new Scanner(System.in); @@ -327,7 +215,7 @@ if (sum == 0) { } ``` - + When a program is executed multiple times with appropriate inputs the hidden error is often found. Coming up with relevant inputs is a skill in its own right. It's essential to test the so-called corner cases, i.e., circumstances where the program execution could be exceptional. An example scenario would be one where the user does not enter a single acceptable value or enters zeros or very large values. diff --git a/data/part-3/2-lists.md b/data/part-3/2-lists.md index 1f4ae73dd..6e270b9cb 100644 --- a/data/part-3/2-lists.md +++ b/data/part-3/2-lists.md @@ -5,43 +5,37 @@ title: "Lists" hidden: false --- - + - + - You are familiar with the list structure and know how to use a list in a program. - + - You are familiar with the concept of an index, you can add values to a list, and you know how to retrieve information from a list's indices. - + - You know how to iterate over a list with multiple different loop types. - + - You know how to check if a value exists in a list, and also know how to remove values from a list. - + - You are aware of the list being a reference-type variable, and become familiar with using lists as method parameters. - + In programming, we often encounter situations where we want to handle many values. The only method we've used so far has been to define a separate variable for storing each value. This is impractical. - + ```java String word1; @@ -51,37 +45,27 @@ String word3; String word10; ``` - + The solution presented above is useless in effect -- consider a situation in which there are thousands of words to store. - + Programming languages offer tools to assist in storing a large quantity of values. We will next take a peek at perhaps the single most used tool in Java, the [ArrayList](https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html), which is used for storing many values that are of the same type. - + ArrayList is a pre-made tool in Java that helps dealing with lists. It offers various methods, including ones for adding values to the list, removing values from it, and also for the retrieval of a value from a specific place in the list. The concrete implementations -- i.e., how the list is actually programmed -- has beed abstracted behind the methods, so that a programmer making use of a list doesn't need to concern themselves with its inner workings. - + ## Using and Creating Lists - -For an ArrayList to be used, it first needs be imported into the program. This is achieved by including the command `import java.util.ArrayList;` at the top of the program. Below is an example program where an ArrayList is imported into the program. - ```java // import the list to make it available to the program @@ -95,24 +79,11 @@ public class Program { } ``` - - -Creating a new list is done with the command `ArrayList list = new ArrayList<>()`, where _Type_ is the type of the values to be stored in the list (e.g. `String`). We create a list for storing strings in the example below. - ```java // import the list so the program can use it @@ -129,83 +100,63 @@ public class Program { } ``` - + The type of the ArrayList variable is `ArrayList`. When a list variable is initialized, the type of the values to be stored is also defined in addition to the variable type -- **all the variables stored in a given list are of the same type**. As such, the type of an ArrayList that stores strings is `ArrayList`. A new list is created with the command `new ArrayList<>();`. - + ## Defining the Type of Values That a List Can Contain - + When defining the type of values that a list can include, the first letter of the element type has to be capitalized. A list that includes int-type variables has to be defined in the form `ArrayList`; and a list that includes double-type variables is defined in the form `ArrayList`. - + The reason for this has to do with how the ArrayList is implemented. Variables in Java can be divided into two categories: value type (primitive) and reference type (reference type) variables. **Value-type** variables such as `int` or `double` hold their actual values. **Reference-type** variables such as `ArrayList`, in contrast, contain a reference to the location that contains the value(s) relating to that variable. - + Value-type variables can hold a very limited amount of information, whereas references can store a near limitless amount of it. - + You'll find examples below of creating lists that contain different types of values. - + ```java ArrayList list = new ArrayList<>(); list.add(1); ``` - + ```java ArrayList list = new ArrayList<>(); list.add(4.2); ``` - + ```java ArrayList list = new ArrayList<>(); list.add(true); ``` - + ```java ArrayList list = new ArrayList<>(); list.add("String is a reference-type variable"); ``` - + Once a list has been created, ArrayList assumes that all the variables contained in it are reference types. Java automatically converts an `int` variable into `Integer` when one is added to a list, and the same occurs when a variable is retrieved from a list. The same conversion occurs for `double`-type variables, which are converted to `Double`. This means that even though a list is defined to contain `Integer`-type variables, variables of type `int` can also be added to it. - ```java ArrayList integers = new ArrayList<>(); @@ -217,41 +168,23 @@ double d = 4.2; doubles.add(d); ``` - + We'll be returning to this theme since the categorization of variables into value and reference types affects our programs in other ways as well. - -## Adding to a List and Retrieving a Value from a Specific Place - +## Adding to a List and Retrieving a Value from a Specific Place -The next example demonstrates the addition of a few strings into an ArrayList containing strings. Addition is done with the list method `add`, which takes the value to be added as a parameter. We then print the value at position zero. To retrieve a value from a certain position, you use the list method `get`, which is given the place of retrieval as a parameter. - -To call a list method you first write the name of the variable describing the list, followed by a dot and the name of the method. +The next example demonstrates the addition of a few strings into an ArrayList containing strings. Addition is done with the list method `add`, which takes the value to be added as a parameter. We then print the value at position zero. To retrieve a value from a certain position, you use the list method `get`, which is given the place of retrieval as a parameter. - ```java // import list so that the program can use it @@ -273,11 +206,7 @@ public class WordListExample { } ``` - @@ -285,25 +214,11 @@ First - - -As can be seen, the `get` method retrieves the first value from the list when it is given the parameter `0`. This is because **list positions are counted starting from zero**. The first value is found by `wordList.get(0)`, the second by `wordList.get(1)`, and so on. - - ```java import java.util.ArrayList; @@ -321,11 +236,7 @@ public class WordListExample { } ``` - @@ -333,28 +244,19 @@ Second - + - -The exercise contains a base that asks the user for strings and adds them to a list. The program stops reading when the user enters an empty string. The program then prints the first element of the list. - +The exercise contains a base that asks the user for strings and adds them to a list. The program stops reading when the user enters an empty string. The program then prints the first element of the list. -Your assignment is to modify the program so that instead of the first value, the third value on the list is printed. Remember that programmers start counting from zero! The program is allowed to malfunction if there are fewer than three entries on the list, so you don't need to prepare for such an event at all. - @@ -367,15 +269,7 @@ Alex - @@ -389,15 +283,15 @@ Mary - + - + In the exercise template there is a program that reads integers from the user and adds them to a list. This ends when the user enters 0. The program then prints the first value on the list. - + Modify the program so that instead of the first value, the program prints the sum of the second and third numbers. The program is allowed to malfunction if there are fewer than three entries on the list, so you don't need to prepare for such an event at all. @@ -424,29 +318,15 @@ Modify the program so that instead of the first value, the program prints the su - - -## Retrieving Information from a "Non-Existent" Place - -If you try to retrieve information from a place that does not exist on the list, the program will print a `IndexOutOfBoundsException` error. In the example below, two values are added to a list, after which there is an attempt to print the value at place two on the list. +## Retrieving Information from a "Non-Existent" Place - ```java import java.util.ArrayList; @@ -464,19 +344,11 @@ public class Example { } ``` - -Since the numbering (i.e., **indexing**) of the list elements starts with zero, the program isn't able to find anything at place two and its execution ends with an error. Below is a description of the error message caused by the program. - **Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 2, Size: 2 @@ -487,43 +359,43 @@ Java Result: 1** - + The error message provides hints of the internal implementation of an ArrayList object. It lists all the methods that were called leading up to the error. First, the program called the `main` method, whereupon ArrayList's `get` method was called. Subsequently, the `get` method of ArrayList called the `rangeCheck` method, in which the error occurred. This also acts as a good illustration of proper method naming. Even if we'd never heard of the `rangeCheck` method, we'd have good reason to guess that it checks if a searched place is contained within a given desired range. The error likely occurred because this was not the case. - + A list is extremely useful for storing the values of variables for later use. That said, making mistakes is also relatively easy with a list. - + There is a program that uses a list in the exercise template. Modify it so that its execution always produces the error `IndexOutOfBounds`. The user should not have to give any inputs to the program (e.g. write something on the keyboard) - + You can also see a means for going through the values of a list -- we will return to this topic a bit later. - + - + Numbering places, i.e., indexing, always begins with zero. The list's first value is located at index 0, the second value at index 1, the third value at index 2, and so on. In programs, an index is denoted with a variable called `i`.
- + In the list above, the first value is 6 and the second value 1. If a new value was added to the list by calling the `add` method of `numbers` with 8 as parameter, the number 8 would be placed at index 6. It would be the seventh number in the list.
- + Similarly, by calling the method `get` with the parameter 4 the fifth number in the list would be retrieved. @@ -531,27 +403,15 @@ Similarly, by calling the method `get` with the parameter 4 the fifth number in - - - + -Each tool offered by Java has a name and location. The program can use a tool after it has been imported with the `import` command. The command is given the location and the name of the desired class. For example, the use of an ArrayList necessitates placing the command `import java.util.ArrayList;` to the top of the program. - ```java import java.util.ArrayList; @@ -567,29 +427,15 @@ public class ListProgram { } ``` - -The same is generally true for all Java classes. We've been using the Scanner class for reading input by importing it with `import java.util.Scanner;`. - +The same is generally true for all Java classes. We've been using the Scanner class for reading input by importing it with `import java.util.Scanner;`. -Bringing of multiple tools to use is straightforward. The tools to be imported are simply listed at the top of the program. - ```java import java.util.ArrayList; @@ -609,27 +455,15 @@ public class ListProgram { - + ## Iterating Over a List - -We'll next be examining methods that can be used to go through the values on a list. Let's start with a simple example where we print a list containing four values. - ```java ArrayList teachers = new ArrayList<>(); @@ -645,14 +479,7 @@ System.out.println(teachers.get(2)); System.out.println(teachers.get(3)); ``` - @@ -663,26 +490,15 @@ Anna - -The example is obviously clumsy. What if there were more values on the list? Or fewer? What if we didn't know the number of values on the list? - +The example is obviously clumsy. What if there were more values on the list? Or fewer? What if we didn't know the number of values on the list? -The number of values on a list is provided by the list's **size** method which returns the number of elements the list contains. The number is an integer (`int`), and it can be used as a part of an expression or stored in an integer variable for later use. - ```java ArrayList list = new ArrayList<>(); @@ -697,13 +513,7 @@ list.add("Second"); System.out.println("Number of values on the list: " + values); ``` - @@ -713,24 +523,15 @@ Number of values on the list: 1 - - - + -In the exercise template is a program that reads input from the user. Modify its working so that when the program quits reading, the program prints the number of values on the list. - @@ -743,23 +544,7 @@ In total: 4 - @@ -779,56 +564,21 @@ In total: 11 - + **NB!** Be sure to use the `size` method of the list. - - -## Iterating Over a List Continued - - - -Let's make a new version of the program that prints each index manually. In this intermediate version we use the `index` variable to keep track of the place that is to be outputted. - - ```java ArrayList teachers = new ArrayList<>(); @@ -867,30 +617,15 @@ if (index < index.size()) { } ``` - + We can see that there's repetition in the program above. - -We can convert the `if` statements into a `while` loop that is repeated until the condition `index < teachers.size()` no longer holds (i.e., the value of the variable `index` grows too great). - ```java ArrayList teachers = new ArrayList<>(); @@ -909,26 +644,15 @@ while (index < teachers.size()) { } ``` - + Now the printing works regardless of the number of elements. - -The for-loop we inspected earlier used to iterate over a known number of elements is extremely handy here. We can convert the loop above to a `for`-loop, after which the program looks like this. - ```java ArrayList teachers = new ArrayList<>(); @@ -943,14 +667,7 @@ for (int index = 0; index < teachers.size(); index++) { } ``` - @@ -961,15 +678,11 @@ Anna - + The index variable of the for-loop is typically labelled `i`: - + ```java for (int i = 0; i < teachers.size(); i++) { @@ -977,24 +690,11 @@ for (int i = 0; i < teachers.size(); i++) { } ``` - -Let's consider using a list to store integers. The functionality is largely the same as in the previous example. The greatest difference has to do with the initialization of the list -- the type of value to be stored is defined as `Integer`, and the value to be printed is stored in a variable called `number` before printing. - ```java ArrayList numbers = new ArrayList<>(); @@ -1020,25 +720,11 @@ for (int i = 0; i < numbers.size(); i++) { - -Printing the numbers in the list in reverse order would also be straightforward. - ```java ArrayList numbers = new ArrayList<>(); @@ -1065,50 +751,41 @@ while (index >= 0) { - + The execution of the program is visualized below. However, the visualization does not show the internal state of the ArrayList (i.e., the values contained by it). - + - + Try and recreate the previous example with the for loop! - + - + The next exercises are meant for learning to use lists and indices. Even if you could complete the exercises without a list, concentrate on training to use it. The functionality in the exercises is to be implemented after reading the input numbers. - + - -In the exercise template there is a program that reads inputs from the user and adds them to a list. Reading is stopped once the user enters an empty string. - +In the exercise template there is a program that reads inputs from the user and adds them to a list. Reading is stopped once the user enters an empty string. -Your task is to modify the method to print the last read value after it stops reading. Print the value that was read last from the list. Use the method that tells the size of a list to help you. - @@ -1121,23 +798,7 @@ Mary - @@ -1159,29 +820,19 @@ Oscar - + - -In the exercise template there is a program that reads inputs from the user and adds them to a list. Reading is stopped once the user enters an empty string. - +In the exercise template there is a program that reads inputs from the user and adds them to a list. Reading is stopped once the user enters an empty string. -Modify the program to print both the first and the last values after the reading ends. You may suppose that at least two values are read into the list. - @@ -1195,22 +846,7 @@ Mary - @@ -1233,15 +869,15 @@ Oscar - + - + The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. - + Expand the functionality of the program so that after reading the numbers, it prints all the numbers received from the user. The number used to indicate stopping should not be printed. @@ -1261,31 +897,17 @@ Expand the functionality of the program so that after reading the numbers, it pr - + The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. - - -Expand the program to ask for a start and end indices once it has finished asking for numbers. After this the program shall prints all the numbers in the list that fall in the specified range (between the indices given by the user, inclusive). You may assume that the user gives indices that match some numbers in the list. - @@ -1303,19 +925,7 @@ To where? **2** - **72** **2** @@ -1332,30 +942,19 @@ To where? **2** - + - -The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. - +The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. -Continue developing the program so that it finds the greatest number in the list and prints its value after reading all the numbers. The programming should work in the following manner. - @@ -1370,24 +969,11 @@ The greatest number: 93 - - -You can use the source code below as an example. It is used to find the smallest number. - ```java // assume we have a list that contains integers @@ -1406,31 +992,19 @@ System.out.println("The smallest number: " + smallest); - + - -The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. - +The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. -Expand the program by adding a functionality that asks the user for a number, and reports that number's index in the list. If the number is not found, the program should not print anything. - @@ -1446,20 +1020,7 @@ Search for? **2** - @@ -1478,27 +1039,15 @@ Search for? **8** - - - + -Write a program that reads numbers from the user. When number 9999 is entered, the reading process stops. After this the program will print the smallest number in the list, and also the indices where that number is found. Notice: the smallest number can appear multiple times in the list. - @@ -1514,21 +1063,7 @@ Found at index: 1 - @@ -1545,32 +1080,21 @@ Found at index: 3 - + Hint: combine the programs you wrote for the exercises "Greatest number in the list" and "Index of the requested number". First find the smallest number, and then find the index of that number. - + ## Iterating Over a List with a For-Each Loop - -If you don't need to keep track of the index as you're going through a list's values, you can make use of the **for-each** loop. It differs from the previous loops in that it has no separate condition for repeating or incrementing. - ```java ArrayList teachers = new ArrayList<>(); @@ -1586,24 +1110,11 @@ for (String teacher: teachers) { } ``` - -In practical terms, the for-each loop described above hides some parts of the for-loop we practiced earlier. The for-each loop would look like this if implemented as a for-loop: - ```java ArrayList teachers = new ArrayList<>(); @@ -1619,35 +1130,25 @@ for (int i = 0; i < teachers.size(); i++) { } ``` - + In practice, the for-each loop examines the values of the list in order one at a time. The expression is defined in the following format: `for (TypeOfVariable nameOfVariable: nameOfList)`, where `TypeOfVariable` is the list's element type, and `nameOfVariable` is the variable that is used to store each value in the list as we go through it. - + - -The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. - +The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. -Modify the program so that after reading the numbers it calculates and prints the sum of the numbers in the list. - @@ -1663,29 +1164,19 @@ Sum: 93 - + - -The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. - +The exercise template contains a base that reads numbers from the user and adds them to a list. Reading is stopped once the user enters the number -1. -When reading ends, calculate the average of the numbers in it, and then print that value. - @@ -1701,26 +1192,15 @@ Average: 23.25 - -## Removing from a List and Checking the Existence of a Value - +## Removing from a List and Checking the Existence of a Value -The list's **remove** method removes the value that is located at the index that's given as the parameter. The parameter is an integer. - ```java ArrayList list = new ArrayList<>(); @@ -1735,12 +1215,7 @@ System.out.println("Index 0 so the first value: " + list.get(0)); System.out.println("Index 1 so the second value: " + list.get(1)); ``` - @@ -1749,22 +1224,11 @@ Index 1 so the second value: Third - - -If the parameter given to `remove` is the same type as the values in the list, but not an integer, (integers are used to remove from a given index), it can be used to remove a value directly from the list. - ```java ArrayList list = new ArrayList<>(); @@ -1779,12 +1243,7 @@ System.out.println("Index 0 so the first value: " + list.get(0)); System.out.println("Index 1 so the second value: " + list.get(1)); ``` - @@ -1793,24 +1252,11 @@ Index 1 so the second value: Third - - -If the list contains integers, you cannot remove a number value by giving an `int` type parameter to the remove method. This would remove the number from the index that the parameter indicates, instead of an element on the list that has the same value as the parameter. To remove an integer type value you can convert the parameter to Integer type; this is achieved by the `valueOf` method of the Integer class. - ```java ArrayList list = new ArrayList<>(); @@ -1838,29 +1284,11 @@ Index 1 so the second value: 24 - - -The list method **contains** can be used to check the existence of a value in the list. The method receives the value to be searched as its parameter, and it returns a boolean type value (`true` or `false`) that indicates whether or not that value is stored in the list. - - ```java ArrayList list = new ArrayList<>(); @@ -1882,13 +1310,7 @@ if (list.contains("Second")) { } ``` - @@ -1898,25 +1320,15 @@ Second can still be found - - - + -In the exercise template there is a program that reads inputs from the user until an empty string is entered. Add the following functionality to it: after reading the inputs one more string is requested from the user. The program then tell whether that string was found in the list or not. - @@ -1930,17 +1342,7 @@ Mary was found! - @@ -1956,21 +1358,15 @@ Logan was not found! - + ## List as a Method Parameter - + Like other variables, a list can be used as a parameter to a method too. When the method is defined to take a list as a parameter, the type of the parameter is defined as the type of the list and the type of the values contained in that list. Below, the method `print` prints the values in the list one by one. - + ```java public static void print(ArrayList list) { @@ -1980,19 +1376,11 @@ public static void print(ArrayList list) { } ``` - -We're by now familiar with methods, and it works in the same way here. In the example below we use the `print` method that was implemented above. - ```java ArrayList strings = new ArrayList<>(); @@ -2004,13 +1392,7 @@ strings.add("Third"); print(strings); ``` - @@ -2020,23 +1402,15 @@ Third - + The chosen parameter in the method definition is not dependent on the list that is passed as parameter in the method call. In the program that calls `print`, the name of the list variable is `string`, but inside the method `print` the variable is called `list` -- the name of the variable that stores the list could also be `printables`, for instance. - + It's also possible to define multiple variables for a method. In the example the method receives two parameters: a list of numbers and a threshold value. It then prints all the numbers in the list that are smaller than the second parameter. - + ```java public static void printSmallerThan(ArrayList numbers, int threshold) { @@ -2048,17 +1422,7 @@ public static void printSmallerThan(ArrayList numbers, int threshold) { } ``` - ```java ArrayList list = new ArrayList<>(); @@ -2081,29 +1445,15 @@ printSmallerThan(list, 3); - + - -Create the method `public static void printNumbersInRange(ArrayList numbers, int lowerLimit, int upperLimit)` in the exercise template. The method prints the numbers in the given list whose values are in the range [lowerLimit, upperLimit]. A few examples of using the method are supplied below. - ```java ArrayList numbers = new ArrayList<>(); @@ -2121,19 +1471,7 @@ System.out.println("The numbers in the range [3, 10]"); printNumbersInRange(numbers, 3, 10); ``` - @@ -2151,15 +1489,11 @@ The numbers in the range [3, 10] - + As before, a method can also return a value. The methods that return values have the type of the return value in place of the `void` keyword, and the actual returning of the value is done by the `return` command. The method below returns the size of the list. - + ```java public static int size(ArrayList list) { @@ -2167,24 +1501,11 @@ public static int size(ArrayList list) { } ``` - -You can also define own variables for methods. The method below calculates the average of the numbers in the list. If the list is empty, it returns the number -1. - ```java public static double average(ArrayList numbers) { @@ -2201,26 +1522,15 @@ public static double average(ArrayList numbers) { } ``` - + - + Create the method `public static int sum(ArrayList numbers)` in the exercise template. The method is to return the sum of the numbers in the parameter list. - ```java ArrayList numbers = new ArrayList<>(); @@ -2244,35 +1554,27 @@ System.out.println(sum(numbers)); - + ## On Copying the List to a Method Parameter - + Earlier we have used integers, floating point numbers, etc. as method parameters. When variables such as `int` are used as method parameters, the value of the variable is copied for the method's use. The same occurs in the case that the parameter is a list. - + Lists, among practically all the variables that can store large amounts of information, are _reference-type variables_. This means that the value of the variable is a reference that points to the location that contains the information. - + When a list (or any reference-type variable) is copied for a method's use, the method receives the value of the list variable, i.e., a _reference_. In such a case the **method receives a reference to the real value of a reference-type variable**, and the method is able to modify the value of the original reference type variable, such as a list. In practice, the list that the method receives as a parameter is the same list that is used in the program that calls the method. - + Let's look at this briefly with the following method. - ```java public static void removeFirst(ArrayList numbers) { @@ -2284,25 +1586,7 @@ public static void removeFirst(ArrayList numbers) { } ``` - ```java ArrayList numbers = new ArrayList<>(); @@ -2330,28 +1614,15 @@ System.out.println(numbers); [] - - - - -Create the method `public static void removeLast(ArrayList strings)` in the exercise template. The method should remove the last value in the list it receives as a parameter. If the list is empty, the method does nothing. + - ```java ArrayList strings = new ArrayList<>(); @@ -2368,10 +1639,7 @@ removeLast(strings); System.out.println(strings); ``` - + [First, Second, Third] @@ -2380,31 +1648,15 @@ System.out.println(strings); - - -## A Summary of List Methods - -The ArrayList contains a bunch of useful methods. The method always operates on the list object that is connected to the method call -- this connection is established with a dot. The example below illustrates that a program can contain multiple lists, which also holds true for other variables. Two separate lists are created below. +## A Summary of List Methods - ```java ArrayList exercises1 = new ArrayList<>(); @@ -2424,14 +1676,7 @@ System.out.println("The first value of the first list " + exercises1.get(0)); System.out.println("The last value of the second list " + exercises2.get(exercises2.size() - 1)); ``` - @@ -2442,33 +1687,26 @@ The last value of the second list Employee's pension insurance - + Each list is its own separate entity, and the list methods always concern the list that was used to call the method. A summary of some list methods is provided below. It's assumed that the created list contains variables of type string. - + - Adding to a list is done with the method `add` that receives the value to be added as a parameter. - + ```java ArrayList list = new ArrayList<>(); list.add("hello world!"); ``` - + - The number of elements in a list can be discovered with the non-parameterized method `size`; it returns an integer. - + ```java ArrayList list = new ArrayList<>(); @@ -2476,16 +1714,11 @@ int size = list.size(); System.out.println(size); ``` - + - You can retrieve a value from a certain index with the method `get` that is given the index at which the value resides as a parameter. - + ```java ArrayList list = new ArrayList<>(); @@ -2494,17 +1727,11 @@ String string = list.get(0); System.out.println(string); ``` - + - Removing elements from a list is done with the help of `remove`. It receives as a parameter either the value that is to be removed, or the index of the value to be removed. - + ```java ArrayList list = new ArrayList<>(); @@ -2514,14 +1741,11 @@ list.remove("hello world!"); list.remove(3); ``` - + - Checking for the existence of a value is done with the method `contains`. It's provided the value being searched for as a parameter, and it returns a boolean value. - + ```java ArrayList list = new ArrayList<>(); diff --git a/data/part-3/3-arrays.md b/data/part-3/3-arrays.md index 817926466..d3f0c8d52 100644 --- a/data/part-3/3-arrays.md +++ b/data/part-3/3-arrays.md @@ -6,9 +6,7 @@ hidden: false - + - You know what an Array is and how to use it. - You can create an Array, assign a value to a given index and iterate over it. @@ -16,66 +14,55 @@ hidden: false - + We've gotten familiar with the ArrayList, which has a lot of functionality to make the life of a programmer easier. Perhaps the most important is about adding elements. From the point of view of the programmer, the size of the ArrayList is unlimited. In reality there are no magic tricks in the ArrayList -- they have been programmed like any other programs or tools offered by the programming language. When you create a list, a limited space is reserved in the memory of the computer. When the ArrayList runs out of space, a larger space is reserved and the data from the previous space is copied to the new one. - + Even though the ArrayList is simple to use, sometimes we need the ancestor of the ArrayList, the Array. - + An Array contains a limited amount of numbered spots (indices) for values. The length (or size) of an Array is the amount of these spots, i.e. how many values can you place in the Array. The values in an Array are called **elements**. - + ## Creating an Array - + There are two ways to create an Array. In the first one you have to explicitly define the size upon the creating. This is how you create an Array to hold three integers: - + ```java int[] numbers = new int[3]; ``` - + An array is declared by adding square brackets after the type of the elements it contains (typeofelements[]). A new Array is created by calling `new` followed by the type of the elements, square brackets and the number of the elements in the square brackets. - + An Array to hold 5 Strings can be created like this: - + ```java String[] strings = new String[5]; ``` - + ## Assigning and accessing elements - + An element of an Array is referred to by its index. In the example below we create an Array to hold 3 integers, and then assign values to indices 0 and 2. After that we print the values. - ```java int[] numbers = new int[3]; @@ -86,38 +73,19 @@ System.out.println(numbers[0]); System.out.println(numbers[2]); ``` - - - -Assigning a value to a specific spot of an Array works much like assigning a value in a normal variable, but in the Array you must specify the index, i.e. to which spot you want to assign the value. The index is specified in square brackets. The ArrayList `get`-method works very similarly to accessing an element of an Array. Just the syntax, i.e. the way things are written, is different. - +Assigning a value to a specific spot of an Array works much like assigning a value in a normal variable, but in the Array you must specify the index, i.e. to which spot you want to assign the value. The index is specified in square brackets. The ArrayList `get`-method works very similarly to accessing an element of an Array. Just the syntax, i.e. the way things are written, is different. -The index is an integer, and its value is between [0, length of the Array - 1]. For example an Array to hold 5 elements has indices 0, 1, 2, 3, and 4. - ```java Scanner reader = new Scanner(System.in); @@ -135,26 +103,11 @@ int index = Integer.valueOf(reader.nextLine()); System.out.println(numbers[index]); ``` - - -The value held in an Array can also be assigned to be the value of another variable. - ```java Scanner reader = new Scanner(System.in); @@ -177,7 +130,7 @@ System.out.println(number); - + The exercise template already contains a program, that creates an array and prints the values of the array twice. Modify the program to do following: After the first printing, the program should ask for two indices from the user. The values in these two indices should be swapped, and in the end the values of the array should be printed once again. @@ -189,7 +142,7 @@ The exercise template already contains a program, that creates an array and prin 7 9 - + Give two indices to swap: **2** **4** @@ -211,7 +164,7 @@ Give two indices to swap: 7 9 - + Give two indices to swap: **0** **1** @@ -224,7 +177,7 @@ Give two indices to swap: - + You can assume that the array contains the given indices. Tip! You'll need an additional variable to store one of the values for a little while. @@ -233,33 +186,19 @@ Tip! You'll need an additional variable to store one of the values for a little - + ## Size of an array and iterating - + You can find the size of the array through the associated variable `length`. You can access this associated variable by writing name of the array dot name of the variable, i.e. `numbers.length`. Note, that this is not a method call, so `numbers.length()` doesn't work. - -You can iterate over the array, i.e. go through each element of the array with a while loop. - ```java int[] numbers = new int[4]; @@ -288,7 +227,7 @@ The array has 4 elements. - + The example above iterates over indices 0, 1, 2 and 3, and at each index prints the value held in the index. So first it prints `numbers[0]`, then `numbers[1]` etc. The iteration stops, once the condition of the loop `index < number.length` is false, i.e. once the index variable is greater or equal to the length of the array. NB! The iteration doesn't stop the moment the index variable grows too big; the condition is evaluated only in the beginning of the while loop. @@ -298,14 +237,13 @@ The example above iterates over indices 0, 1, 2 and 3, and at each index prints - + The exercise template already has an array containing numbers. Complete the program so that it asks the user for a number to search in the array. If the array contains the given number, the program tells the index containing the number. If the array doesn't contain the given number, the program will advise that the number wasn't found. - + Search for? **3** 3 is at index 4. @@ -315,8 +253,7 @@ Search for? **3** - + Search for? **7** 7 is at index 7. @@ -326,8 +263,7 @@ Search for? **7** - + Search for? **22** 22 was not found. @@ -337,38 +273,16 @@ Search for? **22** - - -If the index is pointing outside the Array, i.e. the element doesn't exist, we get an **ArrayIndexOutOfBoundsException**. This error tells, that the Array doesn't contain the given index. You cannot access outside of the Array, i.e. index that's less than 0 or greater or equal to the size of the Array. - - - -The next example is a program that initially asks the user to enter how many numbers, and then enter the numbers. Finally it prints back the numbers in the same order. The numbers are stored in an Array. - ```java System.out.print("How many numbers? "); @@ -394,22 +308,12 @@ while (index < numbers.length) { } ``` - + An execution of the program might look like this: - + How many numbers? **4** Enter the numbers: @@ -426,20 +330,14 @@ Here are the numbers again: - + ## Type of the elements - + You can create an array stating the type of the elements of the array followed by square brackets (typeofelements[]). Therefore the elements of the array can be of any type. Here's a few examples: - ```java String[] months = new String[12]; @@ -449,51 +347,39 @@ months[0] = "January"; approximations[0] = 3.14; ``` - + - + Every programmer should know a bit about the structure of the memory used by a computer program. Each variable -- let it be primitive or reference type -- is saved in the memory. Each variable has size i.e. a defined number of bits (zeros and ones) it takes in the memory. The value of the variable is also represented in bits. - + The reference of the array object is actually information about the location of the data. By stating `array[0]` we're referring to the first element of the array. The statement `array[0]` can also be read "Go to the beginning of the array and move forward 0 times the size of the variable contained in the array -- and return a chunk of data the size of the variable. - + The size of an int variable in java is 32 bits. One bit is reserved for the sign, so the largest possible number to present in int is 231-1. When you create an int array of 4 elements, 4 * 32 bits of memory is allocated to hold the integers. When you access `array[2]`, 32 bits are read starting from beginning of the array + 2 * 32 bits. - + Some programming languages try to make sure that the programmer doesn't go "in the wrong area". If java didn't cause the exception when we say `array[-1]`, we would find the data located just before the array in the memory of the program. In such case there wouldn't be anything preventing us from writing a program reading the whole memory reserved for the program. - + ## Array as a parameter of a method - + You can use arrays as a parameter of a method just like any other variable. As an array is a reference type, the value of the array is a reference to the information contained in the array. When you use array as a parameter of a method, the method receives a copy of the reference to the array. - ```java public static void listElements(int[] integerArray) { @@ -509,14 +395,7 @@ public static void listElements(int[] integerArray) { } ``` - ```java int[] numbers = new int[3]; @@ -534,28 +413,25 @@ the elements of the array are: 1 2 3 - + As noticed earlier, you can freely choose the name of the parameter inside the method, the name doesn't have to be the same as the name of the variable when you call the method. In the example above, we call the array `integerArray`, meanwhile the caller of the method has named the same array `numbers`. - + Array is an object, so when you change the array inside the method, the changes persist after the execution of the method. - + The class SumOfArray has a method `public static int sumOfNumbersInArray(int[] array)`. Complete the method so that it computes and returns the sum of the numbers in the array it receives as parameter. - + You can try out the computation of the sum with this example: - + ```java int[] numbers = {5, 1, 3, 4, 2}; @@ -574,19 +450,16 @@ sumOfNumbersInArray(numbers); - + Complete the method `public static void printNeatly(int[] array)` in the class named 'ArrayPrinter' to make it print the numbers of the array it receives more neatly. There should be a whitespace and a comma between each number. don't put a comma after the last number. - + Print the numbers on one line using `System.out.print`. - + You can try out your printing with this example: - + ```java int[] array = {5, 1, 3, 4, 2}; @@ -605,17 +478,14 @@ printNeatly(array); - + Complete the method `public static void printArrayInStars(int[] array)` in the class named 'Printer' to make it print a row of stars for each number in the array. The amount of stars on each row is defined by the corresponding number in the array. - + You can try out the printing with this example: - + ```java int[] array = {5, 1, 3, 4, 2}; @@ -630,38 +500,29 @@ printArrayInStars(array); ** - + The 0th element of the array is 5, so the first line has 5 stars. The next one has 1 etc. - + ## The shorter way to create an array - + Just like for Strings, there's also a shortcut to create an array. Here we create an array to hold 3 integers, and initiate it with values 100, 1 and 42 in it: - + ```java int[] numbers = {100, 1, 42}; ``` - + So apart from calling for `new`, we can also initialize an array with a block, that contains comma-separated values to be assigned in the array. This works for all the types: below we initialize an array of strings, then an array of floating-point numbers. Finally the values are printed. - ```java String[] arrayOfStrings = {"Matti L.", "Matti P.", "Matti V."}; @@ -680,19 +541,11 @@ Matti V. 100.0 - + When you initialize an array with a block, the length of the array is precisely the number of the values specified in the block. The values of the block are assigned to the array in the order, eg. the first value is assigned to index 0, the second value to index 1 etc. - ```java // index 0 1 2 3 4 5 6 7 int[] numbers = {100, 1, 42, 23, 1, 1, 3200, 3201}; @@ -703,18 +556,11 @@ System.out.println(numbers[0]); System.out.println(numbers[2]); ``` - + Just like in ArrayLists, you can't access an index outside of the array. You can try out the following example on your own computer, for example in the sandbox. - ```java String[] arrayOfStrings = {"Matti L.", "Matti P.", "Matti V."}; diff --git a/data/part-3/4-strings.md b/data/part-3/4-strings.md index 3fb51ee6f..493ac7fc9 100644 --- a/data/part-3/4-strings.md +++ b/data/part-3/4-strings.md @@ -6,8 +6,7 @@ hidden: false - + - Revising reading, printing and comparing Strings - Knowing how to split a string into several pieces @@ -15,26 +14,21 @@ hidden: false - + Let's first revise what we already know about Strings and see how to split them. Below we create a String variable `magicWord`, that contains value `"abracadabra"`. - + ```java String magicWord = "abracadabra"; ``` - + Passing a String as a parameter to a print command (or, for that matter, any method that takes a String parameter) happens in the familiar way: - + ```java String magicWord = "abracadabra"; @@ -43,27 +37,19 @@ System.out.println(magicWord); - + abracadabra - + ## Reading and Printing Strings - -You can read a string using the nextLine-method offered by Scanner. The program below reads the name of the user and prints it: - ```java Scanner reader = new Scanner(System.in); @@ -77,25 +63,16 @@ System.out.println(name); - + What's your name? **Vicky** Vicky - -Strings can also be concatenated. If you place a `+`-operator between two strings, you get a new string that's a combination of those two strings. Be mindful of any white spaces in your variables! - ```java String greeting = "Hi "; @@ -109,7 +86,7 @@ System.out.println(phrase); - + Hi Lily and see you later! @@ -118,14 +95,12 @@ Hi Lily and see you later! - + Write a program, that reads a string from the user and then prints it three times. - Give a word: **cake** @@ -134,29 +109,21 @@ cakecakecake - + NB! The program should ask for only one string. Don't use a loop here. - + ## String Comparisons And "Equals" - + Strings can't be compared with with the equals operator - `==`. For strings, there exists a separate `equals`-command, which is always appended to the end of the string that we want to compare. - ```java String text = "course"; @@ -168,19 +135,10 @@ if (text.equals("marzipan")) { } ``` - + The `equals` command is always appended to the end of the string that we want to compare, "string variable dot equals some text". You can also compare a string variable to another string variable. - ```java String text = "course"; @@ -193,22 +151,13 @@ if (text.equals(anotherText)) { } ``` - + When comparing strings, you should make sure the string variable has some value assigned to it. If it doesn't have a value, the program will produce a _NullPointerException_ error, which means that no value has been assigned to the variable, or that it is empty (_null_). - + As we've come to know, a boolean value can be inverted through negation - `!`. - ```java System.out.println("Make sure the text is not 'cake'"); @@ -223,7 +172,7 @@ if (!(text.equals("cake"))) { // true if the condition text.equals("cake") is f - + it wasn't! @@ -231,13 +180,12 @@ it wasn't! - + Write a program that asks the user for a string. If the user writes the string "true", the program prints "You got it right!", otherwise it prints "Try again!". - + Give a string: **true** You got it right! @@ -246,8 +194,7 @@ You got it right! - + Give a string: **trueish** Try again! @@ -258,12 +205,7 @@ Try again! - Write a program that recognizes the following users: @@ -273,15 +215,13 @@ Write a program that recognizes the following users: | emma | haskell | - + The program either shows a personal message or informs of an incorrect username or password. - + Enter username: **alex** Enter password: **sunshine** @@ -291,9 +231,7 @@ You have successfully logged in! - + Enter username: **emma** Enter password: **haskell** @@ -303,9 +241,7 @@ You have successfully logged in! - + Enter username: **alex** Enter password: **thunderstorm** @@ -314,36 +250,23 @@ Incorrect username or password! - + **NB!** You can't compare strings with `==`! - + **NB!** Logins should not be implemented like this in real life! You can become familiar with safer ways to implement logins on courses focusing on web programming. - + ## Splitting a String - + You can split a string to multiple pieces with the `split`-method of the String class. The method takes as a parameter a string denoting the place around which the string should be split. The `split` method returns an array of the resulting sub-parts. In the example below, the string has been split around a space. - ```java String text = "first second third fourth"; @@ -362,15 +285,7 @@ for (int i = 0; i < pieces.length; i++) { - first second @@ -387,21 +302,13 @@ fourth - + Write a program that reads strings from the user. If the input is empty, the program stops reading input and halts. For each non-empty input it splits the string input by whitespaces ` ` and prints each part of the string on a new line. - + **once upon a time** once upon @@ -421,16 +328,13 @@ halted - + Write a program that reads user input until an empty line. For each non-empty string, the program splits the string by spaces ` ` and then prints the pieces that contain `av`, each on a new line. - + **java is a programming language** java **navy blue shirt** @@ -440,12 +344,7 @@ navy - + **Do you have a favorite flavor** have @@ -455,20 +354,10 @@ flavor - + Tip! Strings have a `contains`-method, which tells if a string contains another string. It works like this: - ```java String text = "volcanologist"; @@ -484,8 +373,7 @@ if (!text.contains("tin")) { - + can was found tin wasn't found @@ -493,18 +381,16 @@ tin wasn't found - + ## Data of Fixed Format - + Splitting strings is used particularly when the data is of a fixed format. This refers to data that adheres to some predefined format. An example of this of this is the comma-separated values (`csv`) format, where commas are used to separate values. Below you'll find an example of data in csv form containing names and ages. The first column contains names and the second one ages. The columns are separated by a comma. - + sebastian,2 lucas,2 lily,1 @@ -512,27 +398,13 @@ lily,1 - + Let's assume the user enters the data above row by row, ending with an empty line. - + A program to print the names and ages looks like the following: - ```java Scanner reader = new Scanner(System.in); @@ -551,10 +423,7 @@ while (true) { - + **sebastian,2** Name: sebastian, age: 2 @@ -568,15 +437,12 @@ Name: lily, age: 1 - + Write a program that reads user input until an empty line is entered. For each non-empty line the program splits the string by spaces ` ` and prints the first part of the string. - + **one two three four** one **this is a very important message** @@ -589,15 +455,12 @@ this - + Write a program that reads user input until an empty line is entered. For each non-empty line the program splits the string by spaces ` ` and prints the last part of the string. - + **one two three four** four @@ -607,13 +470,10 @@ message - + Tip! You can find out the length of the array like this: - + ```java String[] parts = {"one", "two", "three"}; @@ -628,21 +488,15 @@ Number of parts: 3 - + - + In the exercises above, we actually implemented a very simple decrypting method for secret messages. One variant of these hidden messages consists of the first character of each line. For example, the secret message "program" is hidden in the (somewhat cryptic) text below. - + Polymorphous computations elaborate. Real calculators honour. @@ -656,14 +510,10 @@ Many microcomputers letter. - + Let's continue along the same theme! You can get a character at a specified index of a string with the `charAt` method. - + ```java String text = "Hello world!"; @@ -681,45 +531,28 @@ H ### Using Diverse Text - + We've printed strings in the examples above. Some of the data contained in a fixed-format string can be numerical. In the previous data we used that contained names and ages, the ages were integers. - + sebastian,2 lucas,2 lily,1 - -Splitting a string always produces an array of strings. If the text is of fixed format, we can assume the data in a specific index to always be of the a specific type -- e.g., in the example above, age at index 1 is an integer. - +Splitting a string always produces an array of strings. If the text is of fixed format, we can assume the data in a specific index to always be of the a specific type -- e.g., in the example above, age at index 1 is an integer. -The program below computes the sum of ages in this fixed format data. In order to compute the sum, the age must first be converted to a number (the familiar command `Integer.valueOf()`) - ```java Scanner reader = new Scanner(System.in); @@ -740,10 +573,7 @@ System.out.println("Sum of the ages is " + sum); - **sebastian,2** **lucas,2** **lily,1** @@ -752,31 +582,10 @@ Sum of the ages is 5 - -We can write a program to compute the average of the ages in the same way: - ```java Scanner reader = new Scanner(System.in); @@ -803,9 +612,7 @@ if (count > 0) { - + **sebastian,2** **lucas,2** @@ -818,21 +625,15 @@ Age average: 1.666 - + Write a program that reads names and ages from the user until an empty line is entered. The name and age are separated by a comma. - + After reading all user input, the program prints the age of the oldest person. You can assume that the user enters at least one person, and that one of the users is older than the others. - **sebastian,2** **lucas,2** @@ -848,22 +649,16 @@ Age of the oldest: 10 - + Write a program that reads names and ages from the user until an empty line is entered. The name and age are separed by a comma. - + After reading all user input, the program prints the name of the oldest person. You can assume that the user enters at least one person, and the that one of the users is older than the others. - **sebastian,2** **lucas,2** @@ -879,14 +674,10 @@ Name of the oldest: gabriel - + In the next exercise you'll be asked for the length of the names. You can find out the length of a string with `length()`-method: - + ```java String word = "equisterian"; @@ -896,7 +687,7 @@ System.out.println("The length of the word" + word + " is " + length); - + The length of the word equisterian is 11 @@ -907,28 +698,23 @@ The length of the word equisterian is 11 - + Write a program that reads names and birth years from the user until an empty line is entered. The name and birth year are separated by a comma. - + After that the program prints the longest name and the average of the birth years. If multiple names are equally longest, you can print any of them. You can assume that the user enters at least one person. - + **sebastian,2017** **lucas,2017** **lily,2017** **hanna,2014** **gabriel,2009** - + Longest name: sebastian Average of the birth years: 2014.8 @@ -943,8 +729,7 @@ Average of the birth years: 2014.8 **mauno,1923** **urho,1900** - + Longest name: martti Average of the birth years: 1930.0 diff --git a/data/part-4/1-introduction-to-object-oriented-programming.md b/data/part-4/1-introduction-to-object-oriented-programming.md index 79d11b524..67ef8d578 100644 --- a/data/part-4/1-introduction-to-object-oriented-programming.md +++ b/data/part-4/1-introduction-to-object-oriented-programming.md @@ -5,13 +5,11 @@ title: "Introduction to object-oriented programming" hidden: false --- - + - + - You're familiar with the concepts of class, object, constructor, object methods, and object variables. @@ -21,48 +19,35 @@ hidden: false - + We'll now begin our journey into the world of object-oriented programming. We'll start with focusing on describing concepts and data using objects. From there on, we'll learn how to add functionality, i.e., methods to our program. - + Object-oriented programming is concerned with isolating concepts of a problem domain into separate entities and then using those entities to solve problems. Concepts related to a problem can only be considered once they've been identified. In other words, we can form abstractions from problems that make those problems easier to approach. - + Once concepts related to a given problem have been identified, we can also begin to build constructs that represent them into programs. These constructs, and the individual instances that are formed from them, i.e., objects, are used in solving the problem. The statement "programs are built from small, clear, and cooperative objects" may not make much sense yet. However, it will appear more sensible as we progress through the course, perhaps even self-evident. - + ## Classes and Objects - + We've already used some of the classes and objects provided by Java. A **class** defines the attributes of objects, i.e., the information related to them (instance variables), and their commands, i.e., their methods. The values of instance (i.e., object) variables define the internal state of an individual object, whereas methods define the functionality it offers. - + A **Method** is a piece of source code written inside a class that's been named and has the ability to be called. A method is always part of some class and is often used to modify the internal state of an object instantiated from a class. - -As an example, `ArrayList` is a class offered by Java, and we've made use of objects instantiated from it in our programs. Below, an `ArrayList` object named `integers` is created and some integers are added to it. - ```java // we create an object from the ArrayList class named integers @@ -78,21 +63,20 @@ integers.add(111); System.out.println(integers.size()); ``` - + An object is always instantiated by calling a method that created an object, i.e., a **constructor** by using the `new` keyword. - + - + A class lays out a blueprint for any objects that are instantiated from it. Let's draw from an analogy from outside the world of computers. Detached houses are most likely familiar to most, and we can safely assume the existence of drawings somewhere that determine what exactly a detached house is to be like. A class is a blueprint. In other words, it specifies what kinds of objects can be instantiated from it: - + Individual objects, detached houses in this case, are all created based on the same blueprints - they're instances of the same class. The states of individual objects, i.e., their attributes (such as the wall color, the building material of the roof, the color of its foundations, the doors' materials and color, ...) may all vary, however. The following is an "object of a detached-house class": @@ -100,32 +84,15 @@ Individual objects, detached houses in this case, are all created based on the s - - - + -The exercise template comes with a ready-made class named `Account`. The `Account` object represents a bank account that has balance (i.e. one that has some amount of money in it). The accounts are used as follows: - ```java Account artosAccount = new Account("Arto's account", 100.00); @@ -145,24 +112,16 @@ System.out.println(artosAccount); System.out.println(artosSwissAccount); ``` - + Write a program that creates an account with a balance of 100.0, deposits 20.0 in it, and finally prints the balance. **NB!** Perform all the operations in this exact order. - - - The `Account` from the previous exercise class is also available in this exercise. @@ -178,20 +137,11 @@ Write a program that: - - -## Creating Classes - - A class specifies what the objects instantiated from it are like. @@ -213,14 +163,12 @@ public class Main { } ``` - + - - + In NetBeans, a new class can be created by going to the _projects_ section located on the left, right-clicking _new_, and then _java class_. The class is provided a name in the dialog that opens. @@ -228,15 +176,11 @@ As with variables and methods, the name of a class should be as descriptive as p - + Let's create a class named `Person`. For this class, we create a separate file named `Person.java`. Our program now consists of two separate files since the main program is also in its own file. The `Person.java` file initially contains the class definition **public class Person** and the curly brackets that confine the contents of the class. - ```java public class Person { @@ -244,29 +188,23 @@ public class Person { } ``` - + After creating a new file in NetBeans, the current state is as follows. In the image below, the class `Person` has been added to the SandboxExercise. - + You can also draw a class diagram to depict a class. We'll become familiar with its notations as we go along. An empty person-named class looks like this: - + A class defines the attributes and behaviors of objects that are created from it. Let's decide that each person object has a name and an age. It's natural to represent the name as a string, and the age as an integer. We'll go ahead and add these to our blueprint: - + ```java public class Person { @@ -275,11 +213,7 @@ public class Person { } ``` - We specify above that each object created from the `Person` class has a `name` and an `age`. Variables defined inside a class are called **instance variables**, or object fields or object attributes. Other names also seem to exist. @@ -289,20 +223,14 @@ In the class diagram, the variables associated with the class are defined as "va - -We have now defined a blueprint -- a class -- for the person object. Each new person object has the variables `name` and `age`, which are able to hold object-specific values. The "state" of a person consists of the values assigned to their name and age. - - +We have now defined a blueprint -- a class -- for the person object. Each new person object has the variables `name` and `age`, which are able to hold object-specific values. The "state" of a person consists of the values assigned to their name and age. - In this exercise, you'll practice creating a class. @@ -314,26 +242,21 @@ You have now created a class called `Dog`. Add the variables `private String nam [Koira|-nimi:String;-rotu:String;-ika:int] - + The class doesn't do much yet. However, practicing this step is valuable for what is to come. - + ## Defining a Constructor - + We want to set an initial state for an object that's created. Custom objects are created the same way as objects from pre-made Java classes, such as `ArrayList`, using the `new` keyword. It'd be convenient to pass values ​​to the variables of that object as it's being created. For example, when creating a new person object, it's useful to be able to provide it with a name: - + ```java public static void main(String[] args) { @@ -342,22 +265,11 @@ public static void main(String[] args) { } ``` - + This is achieved by defining the method that creates the object, i.e., its constructor. The constructor is defined after the instance variables. In the following example, a constructor is defined for the Person class, which can be used to create a new Person object. The constructor sets the age of the object being created to 0, and the string passed to the constructor as a parameter as its name: - ```java public class Person { @@ -371,15 +283,9 @@ public class Person { } ``` - - - The constructor's name is always the same as the class name. The class in the example above is named Person, so the constructor will also have to be named Person. The constructor is also provided, as a parameter, the name of the person object to be created. The parameter is enclosed in parentheses and follows the constructor's name. The parentheses that contain optional parameters are followed by curly brackets. In between these brackets is the source code that the program executes when the constructor is called (e.g., `new Person ("Ada")`). @@ -389,14 +295,10 @@ A few things to note: the constructor contains the expression `this.age = 0`. Th - - - Create a class named `Room`. Add the variables `private String code` and `private int seats` to the class. Then create a constructor `public Room(String classCode, int numberOfSeats)` through which values are assigned to the instance variables. @@ -406,25 +308,17 @@ This class doesn't do much either. However, in the following exercise the object - + - If the programmer does not define a constructor for a class, Java automatically creates a default one for it. A default constructor is a constructor that doesn't do anything apart from creating the object. The object's variables remain uninitialized (generally, the value of any object references will be `null`, meaning that they do not point to anything, and the values of primitives will be `0`) For example, an object can be created from the class below by making the call `new Person()` - + ```java public class Person { @@ -433,21 +327,11 @@ public class Person { } ``` - + If a constructor has been defined for a class, no default constructor exists. For the class below, calling `new Person` would cause an error, as Java cannot find a constructor in the class that has no parameters. - ```java public class Person { @@ -463,31 +347,15 @@ public class Person { - + ## Defining Methods For an Object - We know how to create an object and initialize its variables. However, an object also needs methods to be able to do anything. As we've learned, a **method** is a named section of source code inside a class which can be invoked. - ```java public class Person { @@ -505,17 +373,14 @@ public class Person { } ``` - + A method is written inside of the class beneath the constructor. The method name is preceded by `public void`, since the method is intended to be visible to the outside world (`public`), and it does not return a value (`void`). - + - We've used the modifier `static` in some of the methods that we've written. The `static` modifier indicates that the method in question does not belong to an object and thus cannot be used to access any variables that belong to objects. @@ -523,34 +388,19 @@ Going forward, our methods will not include the `static` keyword if they're used - + In addition to the class name, instance variables and constructor, the class diagram now also includes the method `printPerson`. Since the method comes with the `public` modifier, the method name is prefixed with a plus sign. No parameters are defined for the method, so nothing is put inside the method's parentheses. The method is also marked with information indicating that it does not return a value, here `void`. - The method `printPerson` contains one line of code that makes use of the instance variables `name` and `age` -- the class diagram says nothing about its internal implementations. Instance variables are referred to with the prefix `this`. All of the object's variables are visible and available from within the method. Let's create three persons in the main program and request them to print themselves: - ```java public class Main { @@ -567,17 +417,11 @@ public class Main { } ``` - -Prints: - @@ -587,7 +431,7 @@ Martin, age 0 years - + This as a screencast: @@ -595,26 +439,15 @@ This as a screencast:   - - - Create a class named `Whistle`. Add the variable `private String sound` to the class. After that, create the constructor `public Whistle(String whistleSound)`, which is used to create a new whistle that's given a sound. - ```java Whistle duckWhistle = new Whistle("Kvaak"); @@ -635,11 +468,7 @@ Kvaak - @@ -647,19 +476,7 @@ Create a class named `Door`. The door does not have any variables. Create for it The door should work as follows. - ```java Door alexander = new Door(); @@ -677,24 +494,7 @@ Who's there? - @@ -715,34 +515,15 @@ The output above is based on the product being assigned the name `banana`, with - -## Changing an Instance Variable's Value in a Method - +## Changing an Instance Variable's Value in a Method -Let's add a method to the previously created person class that increments the age of the person by a year. - ```java public class Person { @@ -765,10 +546,7 @@ public class Person { } ``` - The method is written inside the `Person` class just as the `printPerson` method was. The method increments the value of the instance variable `age` by one. @@ -776,30 +554,7 @@ The class diagram also gets an update. [Henkilo|-nimi:String;-ika:int|+Henkilo(String);+tulostaHenkilo():void;+vanhene():void] - Let's call the method and see what happens: @@ -823,7 +578,7 @@ public class Main { } ``` - + The program's print output is as follows: @@ -837,36 +592,13 @@ Antti, age 0 years - That is to say that when the two objects are "born" they're both zero-years old (`this.age = 0;` is executed in the constructor). The `ada` object's `growOlder` method is called twice. As the print output demonstrates, the age of Ada is 2 years after growing older. Calling the method on an object corresponding to Ada has no impact on the age of the other person object since each object instantiated from a class has its own instance variables. The method can also contain conditional statements and loops. The growOlder method below limits aging to 30 years. - ```java public class Person { @@ -891,37 +623,16 @@ public class Person { } ``` - + - This exercise consists of multiple parts. Each part corresponds to one exercise point. The exercise template comes with a partially executed class `decreasingCounter`: - ```java public class DecreasingCounter { @@ -944,25 +655,11 @@ public class DecreasingCounter { } ``` - - -The following is an example of how the main program uses the decreasing counter: - ```java public class MainPorgram { @@ -980,17 +677,11 @@ public class MainPorgram { } ``` - -The program above should have the following print output. - @@ -1000,41 +691,23 @@ value: 8 - - + +

Implementation of the decrement() method

- -Implement the `decrement()` method in the class body in such a way that it decrements the `value` variable of the object it's being called on by one. Once you're done with the `decrement()` method, the main program of the previous example should work to produce the example output. - -

The counter's value cannot be negative

+Implement the `decrement()` method in the class body in such a way that it decrements the `value` variable of the object it's being called on by one. Once you're done with the `decrement()` method, the main program of the previous example should work to produce the example output. - -Implement the `decrement()` in such a way that the counter's value never becomes negative. This means that if the value of the counter is 0, it cannot be decremented. A conditional statement is useful here. +

The counter's value cannot be negative

- ```java public class MainProgram { @@ -1055,18 +728,11 @@ public class MainProgram { } ``` - -Prints: - @@ -1077,28 +743,14 @@ value: 0 - -

Resetting the counter value

- +

Resetting the counter value

-Create the method `public void reset()` for the counter that resets the value of the counter to 0. For example: - ```java public class MainProgram { @@ -1116,17 +768,11 @@ public class MainProgram { } ``` - -Prints: - @@ -1138,17 +784,10 @@ value: 0
- - - - Create the class `Debt` that has double-typed instance variables of `balance` and `interestRate`. The balance and the interest rate are passed to the constructor as parameters `public Debt(double initialBalance, double initialInterestRate)`. @@ -1158,27 +797,7 @@ The debt is increased by multiplying the balance by the interest rate. The class should do the following: - ```java public class MainProgram { @@ -1202,9 +821,7 @@ public class MainProgram { } ``` - The example above illustrates the development of a mortgage with an interest rate of one percent. @@ -1218,7 +835,7 @@ Prints:
- + When you've managed to get the program to work, check the previous example with the early 1900s recession interest rates as well. @@ -1226,21 +843,15 @@ Once you get the program to work, try out the previous example with the interest
- + ## Returning a Value From a Method - + A method can return a value. The methods we've created in our objects haven't so far returned anything. This has been marked by typing the keyword _void_ in the method definition. - + ```java public class Door { @@ -1250,21 +861,13 @@ public class Door { } ``` - The keyword **void** means that the method does not return a value. If we want the method to return a value, we need to replace the `void` keyword with the type of the variable to be returned. In the following example, the Teacher class has a method `grade` that always returns an integer-type (`int`) variable (in this case, the value 10). The value is always returned with the **return** command: - + ```java public class Teacher { @@ -1274,20 +877,12 @@ public class Teacher { } ``` - - -The method above returns an `int` type variable of value 10 when called. For the return value to be used, it needs to be assigned to a variable. This happens the same way as regular value assignment, i.e., by using the equals sign: - ```java public static void main(String[] args) { @@ -1299,11 +894,7 @@ public static void main(String[] args) { } ``` - @@ -1311,21 +902,11 @@ The grade received is 10 - -The method's return value is assigned to a variable of type `int` value just as any other int value would be. The return value could also be used to form part of an expression. - ```java public static void main(String[] args) { @@ -1339,11 +920,7 @@ public static void main(String[] args) { } ``` - @@ -1351,16 +928,11 @@ Grading average 10.0 - + All the variables we've encountered so far can also be returned by a method. To sum: - + - A method that returns nothing has the `void` modifier as the type of variable to be returned. @@ -1370,12 +942,7 @@ public void methodThatReturnsNothing() { } ``` - + - A method that returns an integer variable has the `int` modifier as the type of variable to be returned. @@ -1385,12 +952,7 @@ public int methodThatReturnsAnInteger() { } ``` - + - A method that returns a string has the `String` modifier as the type of the variable to be returned @@ -1400,13 +962,7 @@ public String methodThatReturnsAString() { } ``` - + - A method that returns a double-precision number has the `double` modifier as the type of the variable to be returned. @@ -1416,37 +972,11 @@ public double methodThatReturnsADouble() { } ``` - - -Let's continue with the Person class and add a `returnAge` method that returns the person's age. - - ```java public class Person { @@ -1474,37 +1004,17 @@ public class Person { ``` - + The class in its entirety: [Henkilo|-nimi:String;-ika:int|+Henkilo(String);+tulostaHenkilo():void;+vanhene():void;+palautaIka():int] - - -Let's illustrate how the method works: - - ```java public class Main { @@ -1527,14 +1037,7 @@ public class Main { } ``` - @@ -1547,22 +1050,16 @@ Pekka's and Antti's combined age 3 years - + - Create a class called `Song`. The song has the instance variables `name` (string) and `length` in seconds (integer). Both are set in the `public Song(String name, int length)` constructor. Also, add to the object the methods `public String name()`, which returns the name of the song, and `public int length()`, which returns the length of the song. The class should work as follows. - + ```java Song garden = new Song("In The Garden", 10910); @@ -1577,31 +1074,16 @@ The song In The Garden has a length of 10910 seconds. - + - Create a film class with the instance variables `name` (String) and `ageRating` (int). Write the constructor `public Film(String filmName, int filmAgeRating)` for the class, and also the methods `public String name()` and `public int ageRating()`. The first of these returns the film title and the second returns its rating. Below is an example use case of the class. - ```java Film chipmunks = new Film("Alvin and the Chipmunks: The Squeakquel", 0); @@ -1619,14 +1101,7 @@ if (age >= chipmunks.ageRating()) { } ``` - @@ -1639,35 +1114,13 @@ You may watch the film Alvin and the Chipmunks: The Squeakquel - As we came to notice, methods can contain source code in the same way as other parts of our program. Methods can have conditionals or loops, and other methods can also be called from them. Let's now write a method for the person that determines if the person is of legal age. The method returns a boolean - either `true` or `false`: - ```java public class Person { @@ -1691,42 +1144,11 @@ public class Person { } ``` - - -And let's test it out: - - ```java public static void main(String[] args) { @@ -1761,12 +1183,7 @@ public static void main(String[] args) { } ``` - @@ -1775,19 +1192,11 @@ of legal age: Pekka, age 30 years - + Let's fine-tune the solution a bit more. In its current form, a person can only be "printed" in a way that includes both the name and the age. Situations exist, however, where we may only want to know the name of an object. Let's write a separate method for this use case: - ```java public class Person { @@ -1799,9 +1208,7 @@ public class Person { } ``` - The `getName` method returns the instance variable `name` to the caller. The name of this method is somewhat strange. It is the convention in Java to name a method that returns an instance variable exactly this way, i.e., `getVariableName`. Such methods are often referred to as "getters". @@ -1809,38 +1216,11 @@ The class as a whole: [Henkilo|-nimi:String;-ika:int|+Henkilo(String);+tulostaHenkilo():void;+vanhene():void;+palautaIka():int;+taysiIkainen():boolean;+getNimi():String] - -Let's mould the main program to use the new "getter" method: - - ```java public static void main(String[] args) { @@ -1871,16 +1251,11 @@ public static void main(String[] args) { } ``` - -The print output is starting to turn out quit neat: - @@ -1889,17 +1264,10 @@ Pekka is of legal age - - - Create the class `Gauge`. The gauge has the instance variable `private int value`, a constructor without parameters (sets the initial value of the meter variable to 0), and also the following four methods: @@ -1910,19 +1278,7 @@ Create the class `Gauge`. The gauge has the instance variable `private int value An example of the class in use. - ```java Gauge g = new Gauge(); @@ -1938,17 +1294,7 @@ System.out.println("Not full! Value: " + g.value()); ``` - @@ -1964,23 +1310,15 @@ Not full! Value: 4 - + ## A string representation of an object and the toString-method - + We are guilty of programming in a somewhat poor style by creating a method for printing the object, i.e., the `printPerson` method. A preferred way is to define a method for the object that returns a "string representation" of the object. The method returning the string representation is always `toString` in Java. Let's define this method for the person in the following example: - ```java public class Person { @@ -1992,48 +1330,14 @@ public class Person { } ``` - The `toString` functions as `printPerson` does. However, it doesn't itself print anything but instead returns a string representation, which the calling method can execute for printing as needed. The method is used in a somewhat surprising way: - - ```java public static void main(String[] args) { @@ -2053,7 +1357,7 @@ public static void main(String[] args) { } ``` - + In principle, the `System.out.println` method requests the object's string representation and prints it. The call to the `toString` method returning the string representation does not have to be written explicitly, as Java adds it automatically. When a programmer writes: @@ -2061,7 +1365,7 @@ In principle, the `System.out.println` method requests the object's string repre System.out.println(antti); ``` - + Java extends the call at run time to the following form: @@ -2069,11 +1373,7 @@ Java extends the call at run time to the following form: System.out.println(antti.toString()); ``` - As such, the call `System.out.println(antti)` calls the `toString` method of the `antti` object and prints the string returned by it. @@ -2085,19 +1385,15 @@ The second part of the screencast:   - + - + The exercise template defines an Agent class, having a first name and last name. A `print` method is defined for the class that creates the following string representation. - + ```java Agent bond = new Agent("James", "Bond"); @@ -2110,23 +1406,13 @@ My name is Bond, James Bond - Remove the class' `print` method, and create a `public String toString()` method for it, which returns the string representation shown above. The class should function as follows. - ```java Agent bond = new Agent("James", "Bond"); @@ -2147,44 +1433,15 @@ My name is Bond, Ionic Bond
- - -## Method parameters - -Let's continue with the `Person` class once more. We've decided that we want to calculate people's body mass indexes. To do this, we write methods for the person to set both the height and the weight, and also a method to calculate the body mass index. The new and changed parts of the Person object are as follows: +## Method parameters - ```java public class Person { @@ -2217,25 +1474,11 @@ public class Person { } ``` - -The instance variables `height` and `weight` were added to the person. Values for these can be set using the `setHeight` and `setWeight` methods. Java's standard naming convention is used once again, that is, if the method's only purpose is to set a value to an instance variable, then it's named as `setVariableName`. Value-setting methods are often called "setters". The new methods are put to use in the following case: - - ```java public static void main(String[] args) { @@ -2253,16 +1496,11 @@ public static void main(String[] args) { } ``` - -Prints: - @@ -2271,20 +1509,15 @@ Juhana, body mass index is 20.897959183673468 - + ## A parameter and instance variable having the same name! - + In the preceding example, the `setHeight` method sets the value of the parameter `newHeight` to the instance variable `height`: - + ```java public void setHeight(int newHeight) { @@ -2292,15 +1525,11 @@ public void setHeight(int newHeight) { } ``` - + The parameter's name could also be the same as the instance variable's, so the following would also work: - + ```java public void setHeight(int height) { @@ -2308,23 +1537,11 @@ public void setHeight(int height) { } ``` - + In this case, `height` in the method refers specifically to a parameter named _height_ and `this.height` to an instance variable of the same name. For example, the following example would not work as the code does not refer to the instance variable _height_ at all. What the code does in effect is set the `height` variable received as a parameter to the value it already contains: - ```java public void setHeight(int height) { @@ -2340,17 +1557,10 @@ public void setHeight(int height) { } ``` - - - - Create a class Multiplier that has a: @@ -2361,17 +1571,7 @@ You also need to create an instance variable in this exercise. An example of the class in use: - ```java Multiplier multiplyByThree = new Multiplier(3); @@ -2385,18 +1585,11 @@ System.out.println("multiplyByThree.multiply(1): " + multiplyByThree.multiply(1) System.out.println("multiplyByFour.multiply(1): " + multiplyByFour.multiply(1)); ``` - -Output - @@ -2409,20 +1602,15 @@ multiplyByFour.multiply(1): 4 - + ## Calling an internal method - + The object may also call its methods. For example, if we wanted the string representation returned by toString to also tell of a person's body mass index, the object's own `bodyMassIndex` method should be called in the `toString` method: - + ```java public String toString() { @@ -2430,15 +1618,11 @@ public String toString() { } ``` - + So, when an object calls an internal method, the name of the method and this prefix suffice. An alternative way is to call the object's own method in the form `bodyMassIndex()`, whereby no emphasis is placed on the fact that the object's own bodyMassIndex method is being called: - + ```java public String toString() { @@ -2446,7 +1630,7 @@ public String toString() { } ``` - + The screencast's third part: @@ -2454,20 +1638,13 @@ The screencast's third part:   - - - -

Count

+ - Create a class `Statistics` that has the following functionality (the file for the class is provided in the exercise template): @@ -2478,24 +1655,7 @@ The class does not need to store the added numbers anywhere, it is enough for it The method's body is the following: - ```java public class Statistics { @@ -2515,22 +1675,11 @@ public class Statistics { } ``` - + The following program introduces the class' use: - + ```java public class MainProgram { @@ -2545,15 +1694,11 @@ public class MainProgram { } ``` - -The program prints the following: - @@ -2561,15 +1706,10 @@ Count: 4 - -

Sum and average

- Expand the class with the following functionality: @@ -2578,32 +1718,7 @@ Expand the class with the following functionality: The class' template is the following: - ```java public class Statistics { @@ -2632,24 +1747,11 @@ public class Statistics { } ``` - + The following program demonstrates the class' use: - + ```java public class Main { @@ -2666,17 +1768,11 @@ public class Main { } ``` - -The program prints the following: - @@ -2686,14 +1782,10 @@ Average: 2.75 - -

Sum of user input

- Write a program that asks the user for numbers until the user enters -1. The program will then provide the sum of the numbers. @@ -2701,17 +1793,7 @@ The program should use a `Statistics` object to calculate the sum. **NOTE:** Do not modify the Statistics class in this part. Instead, implement the program for calculating the sum by making use of it. - @@ -2725,18 +1807,10 @@ Sum: 15 - -

Multiple sums

- - Change the previous program so that it also calculates the sum of even and odd numbers. @@ -2748,17 +1822,7 @@ Change the previous program so that it also calculates the sum of even and odd n The program should work as follows: - @@ -2776,31 +1840,23 @@ Sum of odd numbers: 5
- + - + At the University of Helsinki student canteen, i.e. Unicafe, students pay for their lunch using a payment card. The final PaymentCard will look like the following as a class diagram: [Maksukortti|-saldo:double|+Maksukortti(double);+syoEdullisesti():void;+syoMaukkaasti():void;+lataaRahaa(double):void;+toString():String] - -In this exercise series, a class called `PaymentCard` is created which aims to mimic Unicafe's payment process - - -

The class template

- The project will include two code files: @@ -2812,19 +1868,7 @@ First, create the `PaymentCard` object's constructor, which is passed the openin The following is the template of the `PaymentCard` class: - ```java public class PaymentCard { @@ -2840,18 +1884,11 @@ public class PaymentCard { } ``` - + The following main program tests the class: - + ```java public class MainProgram { @@ -2862,15 +1899,11 @@ public class MainProgram { } ``` - -The program should print the following: - @@ -2878,23 +1911,14 @@ The card has a balance of 50.0 euros - +

Making transactions

- + Complement the `PaymentCard` class with the following methods: - ```java public void eatAffordably() { @@ -2906,29 +1930,13 @@ public void eatHeartily() { } ``` - The method `eatAffordably` should reduce the card's balance by € 2.60, and the method `eatHeartily` should reduce the card's balance by € 4.60. The following main program tests the class: - ```java public class MainProgram { @@ -2946,17 +1954,11 @@ public class MainProgram { } ``` - -The program should print approximately the following: - @@ -2966,30 +1968,16 @@ The card has a balance of 40.199999999999996 euros - +

Non-negative balance

- What happens if the card runs out of money? It doesn't make sense in this case for the balance to turn negative. Change the methods `eatAffordably` and `eatHeartily` so that they don't reduce the balance should it turn negative. The following main program tests the class: - ```java public class MainProgram { @@ -3006,17 +1994,11 @@ public class MainProgram { } ``` - -The program should print the following: - @@ -3026,22 +2008,18 @@ The card has a balance 0.40000000000000036 euros - + The second call to the method `eatHeartily` above did not affect the balance, since the balance would have otherwise become negative. - +

Topping up the card

- + Add the following method to the `PaymentCard` class: - + ```java public void addMoney(double amount) { @@ -3049,31 +2027,13 @@ public void addMoney(double amount) { } ``` - The purpose of the method is to increase the card's balance by the amount of money given as a parameter. However, the card's balance may not exceed 150 euros. As such, if the amount to be topped up exceeds this limit, the balance should, in any case, become exactly 150 euros. The following main program tests the class: - ```java public class MainProgram { @@ -3093,18 +2053,11 @@ public class MainProgram { } ``` - -The program should print the following: - @@ -3115,27 +2068,16 @@ The card has a balance of 150.0 euros - +

Topping up the card with a negative value

- Change the `addMoney` method further, so that if there is an attempt to top it up with a negative amount, the value on the card will not change. The following main program tests the class: - + ```java public class MainProgram { @@ -3148,16 +2090,11 @@ public class MainProgram { } ``` - -The program should print the following: - @@ -3166,26 +2103,10 @@ Paul: The card has a balance of 10.0 euros - -

Multiple cards

- - Write code in the `main` method of the `MainProgram` class that contains the following sequence of events: @@ -3204,16 +2125,7 @@ Write code in the `main` method of the `MainProgram` class that contains the fol The main program's template is as follows: - ```java public class Main { @@ -3226,20 +2138,11 @@ public class Main { } ``` - -The program should produce the following print output: - @@ -3254,14 +2157,10 @@ Matt: The card has a balance of 72.8 euros
- - - You probably noticed that some of the figures have rounding errors. In the previous exercise, for example, Pekka's balance of 30.7 may be printed as `30.700000000000003`. This is because floating-point numbers, such as `double`, are actually stored in binary form. That is, in zeros and ones using only a limited number of numbers. As the number of floating-point numbers is infinite -- (in case you're wondering "how infinite?", think how many floating-point or decimal values fit between the numbers 5 and 6 for instance). All of the floating-point numbers simply cannot be represented by a finite number of zeros and ones. Thus, the computer must place a limit on the accuracy of stored numbers. diff --git a/data/part-4/2-objects-in-a-list.md b/data/part-4/2-objects-in-a-list.md index 63fe598a3..e70315c2f 100644 --- a/data/part-4/2-objects-in-a-list.md +++ b/data/part-4/2-objects-in-a-list.md @@ -6,67 +6,32 @@ hidden: false --- - + - + - You can add objects to a list - + - You can go through objects in a list - - -The type parameter used in creating a list defines the type of the variables that are added to the list. For instance, `ArrayList` includes strings, `ArrayList` integers, and `ArrayList` floating point numbers - - - -In the example below we first add strings to a list, after which the strings in the list are printed one by one. - ```java ArrayList names = new ArrayList<>(); @@ -131,64 +96,19 @@ Ruth Lichterman
- - -## Adding object to a list - -Strings are objects, so it should come as no surprise that other kinds of objects can also be found in lists. Next, let's examine the cooperation of lists and objects in more detail. - - - -Let's assume we have access to the class defined below, describing a person. - - ```java public class Person { @@ -236,30 +156,15 @@ public class Person { } ``` - -Handling objects in a list is not really different in any way from the previous experience we have with lists. The essential difference is only to define the type for the stored elements when you create the list. - +Handling objects in a list is not really different in any way from the previous experience we have with lists. The essential difference is only to define the type for the stored elements when you create the list. -In the example below we first create a list meant for storing Person type object, after which we add persons to it. Finally the person objects are printed one by one. - ```java ArrayList persons = new ArrayList<>(); @@ -277,13 +182,7 @@ for (Person person: persons) { } ``` - @@ -296,40 +195,15 @@ Martin, age 0 years - -## Adding user-inputted objects to a list - +## Adding user-inputted objects to a list -The structure we used earlier for reading inputs is still very useful. - ```java Scanner scanner = new Scanner(System.in); @@ -359,19 +233,7 @@ for (Person person: persons) { } ``` - @@ -387,36 +249,27 @@ Kristen Nygaard, age 0 years - + - + Implement the class `Items` described here. **NB!** Don't modify the class `Item`. - + Write a program that reads names of items from the user. If the name is empty, the program stops reading. Otherwise, the given name is used to create a new item, which you will then add to the `items` list. - + Having read all the names, print all the items by using the `toString` method of the `Item` class. The implementation of the `Item` class keeps track of the time of creation, in addition to the name of the item. An example of the working program is given below: - @@ -431,32 +284,15 @@ Collar (created at: 06.07.2018 12:34:57) - -## Multiple constructor parameters - +## Multiple constructor parameters -If the constructor demands more than one parameter, you can query the user for more information. Let's assume we have the following constructor for the class `Person`. - ```java public class Person { @@ -477,49 +313,20 @@ public class Person { } ``` - -In this case, an object is created by calling the two-parameter constructor. - +In this case, an object is created by calling the two-parameter constructor. -If we want to query the user for this kind of object, they must be asked for each parameter separately. In the example below, name and age parameters are asked separately from the user. Entering an empty name will end the reading part. - -The persons are printed after they have been read. +If we want to query the user for this kind of object, they must be asked for each parameter separately. In the example below, name and age parameters are asked separately from the user. Entering an empty name will end the reading part. - ```java Scanner scanner = new Scanner(System.in); @@ -552,17 +359,7 @@ for (Person person: persons) { } ``` - @@ -576,39 +373,26 @@ Grace Hopper, age 85 years - + - + The program described here should be implemented in the class `PersonalInformationCollection`. **NB!** Do not modify the class `PersonalInformation`. - - -After the user has entered the last set of details (they enter an empty first name), exit the repeat statement. - -Then print the collected personal information so that each entered object is printed in the following format: first and last names separated by a space (you don't print the identification number). An example of the working program is given below: +After the user has entered the last set of details (they enter an empty first name), exit the repeat statement. - @@ -627,47 +411,20 @@ Betty Holberton - - + - -In the example and exercise below, the required information was entered line by line. By no means is it impossible to ask for input in a specific format, e.g. separated by a comma. - -If the name and age were separated by a comma, the program could work in the following manner. +In the example and exercise below, the required information was entered line by line. By no means is it impossible to ask for input in a specific format, e.g. separated by a comma. - ```java Scanner scanner = new Scanner(System.in); @@ -698,22 +455,7 @@ for (Person person: persons) { } ``` - @@ -734,27 +476,15 @@ Sylvi, age 0 years - + ## Filtered printing from the list - -You can also examine the objects on the list as you go through it. In the example below, we first ask the user for an age restriction, after which we print all the objects whose age is at least the number given by the user. - ```java // Assume we have a 'persons' list @@ -771,39 +501,24 @@ for (Person person: persons) { ``` - + - + In the exercise template there is a ready-made class TelevisionProgram, representing a television program. The class has object variables name and duration, a constructor, and a few methods. - -Implement a program that begins by reading television programs from the user. When the user inputs an empty string as the name of the program, the program stops reading programs. - +Implement a program that begins by reading television programs from the user. When the user inputs an empty string as the name of the program, the program stops reading programs. -After this the user is queried for a maximum duration. Once the maximum is given, the program proceeds to list all the programs whose duration is smaller or equal to the specified maximum duration. - @@ -825,45 +540,24 @@ Two and a Half Men, 30 minutes - + - + Write a program that first reads book information from the user. The details to be asked for each book include the title, the number of pages and the publication year. Entering an empty string as the name of the book ends the reading process. - + After this the user is asked for what is to be printed. If the user inputs "everything", all the details are printed: the book titles, the numbers of pages and the publication years. However, if the user enters the string "name", only the book titles are printed. - + It is probably worthwhile to implement a class called `Book` to represent a book. There are two points in total available for this exercise. - + @@ -890,28 +584,7 @@ The Name of the Wind, 662 pages, 2007 - diff --git a/data/part-4/3-files-and-reading-data.md b/data/part-4/3-files-and-reading-data.md index 6edd9ef9a..b219d9023 100644 --- a/data/part-4/3-files-and-reading-data.md +++ b/data/part-4/3-files-and-reading-data.md @@ -4,50 +4,36 @@ title: "Files and reading data" hidden: false --- - + - + - You'll review reading keyboard input. - + - You know what a file and a filesystem are, and are able to add an empty text file into the filesystem. - + - You know how to create a write a program that reads data from a file. - -A considerable amount of software is in one way or another based on handling data. Software created for playing music handles music files and those created for the purpose of image manipulation handle image files. Applications that run on the internet and mobile devices, such as Facebook, WhatsApp, and Telegram, handle user information that is stored in file-based databases. What these all have in common is that they read and manipulate data in one way or another. Also, the data being handled is ultimately stored in some format in one or more files. - +A considerable amount of software is in one way or another based on handling data. Software created for playing music handles music files and those created for the purpose of image manipulation handle image files. Applications that run on the internet and mobile devices, such as Facebook, WhatsApp, and Telegram, handle user information that is stored in file-based databases. What these all have in common is that they read and manipulate data in one way or another. Also, the data being handled is ultimately stored in some format in one or more files. -## Reading From the Keyboard - -We've been using the `Scanner`-class since the beginning of this course to read user input. The block in which data is read has been a while-true loop where the reading ends at a specific input. +## Reading From the Keyboard - ```java Scanner scanner = new Scanner(System.in); @@ -65,35 +51,19 @@ while (true) { } ``` - + In the example above, we pass system input (`System.in`) as a parameter to the constructor of the Scanner-class. In text-based user interfaces, the input of the user is directed into the input stream one line at a time, which means that the information is sent to be handled every time the user enters a new line. - + - + Write a program that reads strings from the user until the user inputs the string "end". At that point, the program should print how many strings have been read. The string "end" should not be included in the number strings read. You can find some examples below of how the program works. - @@ -113,11 +83,7 @@ Write a program that reads strings from the user until the user inputs the strin - @@ -128,24 +94,11 @@ Write a program that reads strings from the user until the user inputs the strin - - -The user input is read in string form. If we wanted to handle the input as integers, for instance, we'd have to convert it to another form. An example program has been provided below - it reads input from the user until the user inputs "end". As long as the user input is not "end" the inputs are handled as integers -- in this case, the number is simply printed. - ```java Scanner scanner = new Scanner(System.in); @@ -162,24 +115,14 @@ while (true) { } ``` - + - -Write a program that reads strings from the user until the user inputs the string "end". As long as the input is not "end", the program should handle the input as an integer and print the cube of the number provided (i.e., number _ number _ number). Below are some sample outputs - @@ -193,11 +136,7 @@ Write a program that reads strings from the user until the user inputs the strin - @@ -207,81 +146,61 @@ Write a program that reads strings from the user until the user inputs the strin - + ## Files and the Filesystem - + **Files** are collections of data that live in computers. These files can contain, among other things, text, images, music, or any combination of these. The file format determines the content of the file as well as the program required to read the file. For example, PDF files are read with a program suited for reading PDF files, and music files are read with a program suited for reading music files. Each of these programs is made by humans, and the creators of these programs -- i.e., programmers -- also specify the file format as part of the work. - + Computers have several different programs for browsing files. These programs are specific to the operating system. All programs used for browsing files make use of the filesystem of the computer in one way or another. - + Our development environment provides us with the ability to browse the files of a project. In NetBeans you can take a look at all the files attached to a project by selecting the `Files` tab, which is found in the same place as the `Projects` tab. If the tab cannot be be found, it can be opened from the `Window` menu. Clicking the project to open it will reveal all its files. - + - + **NB!** In this exercise, we won't be programming. Instead, you'll familiarize yourself with the `Files`-tab in NetBeans and how to create a new file. - + Create a file called `file.txt` in the root folder (the folder containing the folder `src` and the file `pom.xml`) of the exercise template using the `Files`-tab in NetBeans. Edit the file and write the message `Hello, world!` on the first line of the file. - + - + Files exist on the hard drive of a computer, which is, in reality, a large set of ones and zeros, i.e., bits. Information is made up of these bits, e.g., one variable of type int takes up 32 bits (i.e., 32 ones or zeros). Modern terabyte-sized hard drives hold about 8 trillion bits (written out the number is 8,000,000,000,000). On this scale, a single integer is very small. - + Files can exist practically anywhere on a hard drive, even separated into multiple pieces. The computer's **filesystem** has the responsibility of keeping track of the locations of files on the hard drive as well as providing the ability to create new files and modify them. The filesystem's main responsibility is abstracting the true structure of the hard drive; a user or a program using a file doesn't need to care about how, or where, the file is actually stored. - + ## Reading From a File - -**Reading a file** is done using the Scanner-class. When we want to read a file using the Scanner-class, we give the path for the file we want to read as a parameter to the constructor of the class. The path to the file can be acquired using Java's `Paths.get` command, which is given the file's name in string format as a parameter: `Paths.get("filename.extension")`. - +**Reading a file** is done using the Scanner-class. When we want to read a file using the Scanner-class, we give the path for the file we want to read as a parameter to the constructor of the class. The path to the file can be acquired using Java's `Paths.get` command, which is given the file's name in string format as a parameter: `Paths.get("filename.extension")`. -When the `Scanner`-object that reads the file has been created, the file can be read using a while-loop. The reading proceeds until all the lines of the file have been read, i.e., until the scanner finds no more lines to read. Reading a file may result in an error, and it's for this reason that the process requires separate blocks - one for the `try`, and another to `catch` potential errors. We'll be returning to the topic of error handling later. - ```java // first @@ -305,27 +224,22 @@ try (Scanner scanner = new Scanner(Paths.get("file.txt"))) { } ``` - + A file is read from the project root by default ( when `new Scanner(Paths.get("file.txt"))` is called), i.e., the folder that contains the folder `src` and the file `pom.xml` (and possibly other files as well). The contents of this folder can the inspected using the `Files`-tab in NetBeans. - + - + Write a program that prints the contents of a file called "data.txt", such that each line of the file is printed on its own line. - -If the file content looks like so: - @@ -334,16 +248,11 @@ world - -Then the program should print the following: - @@ -354,36 +263,18 @@ world - + - -Write a program that asks the user for a string, and then prints the contents of a file with a name matching the string provided. You may assume that the user provides a file name that the program can find. - +Write a program that asks the user for a string, and then prints the contents of a file with a name matching the string provided. You may assume that the user provides a file name that the program can find. -The exercise template contains the files "data.txt" and "song.txt", which you may use when testing the functionality of your program. The output of the program can be seen below for when a user has entered the string "song.txt". The content that is printed comes from the file "song.txt". Naturally, the program should also work with other filenames, assuming the file can be found. - @@ -407,27 +298,11 @@ Tieto is here allright! - -In the example below, we read all the lines of the file "file.txt", which are then added to an ArrayList. - ```java ArrayList lines = new ArrayList<>(); @@ -447,32 +322,18 @@ try (Scanner scanner = new Scanner(Paths.get("file.txt"))) { System.out.println("Total lines: " + lines.size()); ``` - - - - -The exercise template comes ready with functionality for the guest list application. It checks whether names entered by the user are on the guest list. + - -However, the program is missing the functionality needed for reading the guest list. Modify the program so that the names on the guest list are read from the file. - @@ -493,11 +354,11 @@ Thank you! - + **NB!** The exercise template comes with two files, `names.txt` and `other-names.txt`, which have the following contents. Do not change the contents of the files! - + names.txt: @@ -510,7 +371,7 @@ test - + other-names.txt: @@ -524,25 +385,18 @@ alicia - + - + The exercise template comes with two files, `names.txt` and `other-names.txt`. Write a program that first asks the user for the name of the file to be read, after which the user is prompted for the string that they're looking for. The program then reads the file and searches for the desired string. - -If the string is found, the program should print "Found!". If not, the program should print "Not found.". If reading the file fails (the reading ends in an error) the program should print the message "Reading the file " + file + " failed.". - @@ -554,14 +408,7 @@ Not found. - @@ -573,15 +420,7 @@ Found! - @@ -595,25 +434,18 @@ Reading the file nonexistent.txt failed. - + - + Write a program that prompts the user for a filename, as well as the upper and lower bounds for the accepted range of numbers. Then the program reads the numbers contained in the file (each number is on its own line) and only accounts for the numbers which are inside the given range. Finally, the program should print the number of numbers that were inside the given range. - -You can convert a string-type integer read from a file into a proper integer using the command `Integer.valueOf` (just as when handling input from a user). - @@ -624,14 +456,7 @@ Numbers: 2 - @@ -642,11 +467,11 @@ Numbers: 4 - + **NB**! The exercise template comes with two files, `numbers-1.txt` and `numbers-2.txt` that have the following contents. Do not change the contents of these files. - + numbers-1.txt: @@ -659,7 +484,7 @@ numbers-1.txt: - + numbers-2.txt: @@ -676,41 +501,22 @@ numbers-2.txt: - + - -Sometimes an empty line finds it way into a file. Skipping an empty line can be done using the command `continue` and the `isEmpty`-method of the string. - +Sometimes an empty line finds it way into a file. Skipping an empty line can be done using the command `continue` and the `isEmpty`-method of the string. -In the example below, we read from a file - -Reading data is straightforward. +In the example below, we read from a file - ```java // we create a scanner for reading the file @@ -735,41 +541,23 @@ try (Scanner scanner = new Scanner(Paths.get("henkilot.csv"))) { - + ## Reading Data of a Specific Format From a File - + The world is full of data that are related to other data -- these form collections. For example, personal information can include a name, date of birth and a phone number. Address information, on the other hand, can include a country, city, street address, postal number and so on. - -Data is often stored in files using a specific format. One such format that's already familiar to us is comma-separated values (CSV) format, i.e., data separated by commas. - +Data is often stored in files using a specific format. One such format that's already familiar to us is comma-separated values (CSV) format, i.e., data separated by commas. - - ```java Scanner scanner = new Scanner(System.in); @@ -791,23 +579,11 @@ while (true) { } ``` - -The program works as follows: - @@ -826,25 +602,11 @@ Age: 20 - -Reading the same data from a file called `records.txt` would look like so: - ```java try (Scanner scanner = new Scanner(Paths.get("records.txt"))) { @@ -862,10 +624,10 @@ try (Scanner scanner = new Scanner(Paths.get("records.txt"))) { } ``` - + - + In this exercise, we'll be working with files stored in CSV-format that contain names and ages separated by commas. The file format may look like this: @@ -878,21 +640,11 @@ amy,1 - -Your task is to write a program that first prompts the user for the name of the file they want to read. The program then prints the content of the file in the following way (we're assuming below that the output is from the above-mentioned file): - @@ -905,42 +657,25 @@ amy, age: 1 year - + **NB**! The word "year" should be formatted based on the age. - -## Reading Objects From a File - +## Reading Objects From a File -Creating objects from data that is read from a file is straightforward. Let's assume that we have a class called `Person`, as well as the data from before. - -Reading objects can be done like so: - - ```java ArrayList people = new ArrayList<>(); @@ -961,14 +696,14 @@ try (Scanner scanner = new Scanner(Paths.get("records.txt"))) { System.out.println("Total amount of people read: " + people.size()); ``` - + Reading objects from a file is a clear responsibility in and of itself, and should for that reason be isolated into a method. This is what we'll be doing in the next exercise. - + - + In this exercise, we'll be working with files stored in CSV format, which contain names and ages separated by commas. The file format may look like this: @@ -981,24 +716,24 @@ amy,1 - + The exercise template already has a `Person` class, and the class `StoringRecords` has a body for the method `public static ArrayList readRecordsFromFile(String file)`. Implement the `readRecordsFromFile` method such that it reads the persons from the file passed as a parameter, and finally returns them in the list returned by the method. - + The exercise template has a `main` method that you can use to test how your program works. In this exercise, only modify the method `readRecordsFromFile`. - + - + In this exercise, we'll be working with files stored in CSV format. Each line of the file contains the home team, visiting team, home team points, and visiting team points, all separated by commas. - + You can see an example below of the file's contents. The file shown below is also included in the exercise template with the name "data.csv". @@ -1015,27 +750,18 @@ FURIA,Prospects,16,1 - + Write a program that prompts the user for a filename, after which it reads the match statistics from the file. The program then prompts the user for the name of a team, and prints the data specified in the following parts for that team. - -

Games Played

- +

Games Played

-Implement the ability to output the number of games played by any given team. We're using the above-mentioned **data.csv** file. - @@ -1047,15 +773,7 @@ Games: 2 - @@ -1069,26 +787,15 @@ Games: 6

Wins and Losses

- -Extend the program so that it has the ability to print the number of wins and losses of a given team. The winner of a game is the team that has gained more points from it. - +Extend the program so that it has the ability to print the number of wins and losses of a given team. The winner of a game is the team that has gained more points from it. -You may assume that the games cannot be tied. Below, we're using the above-mentioned **data.csv** file. - @@ -1102,18 +809,7 @@ Losses: 1 - diff --git a/data/part-4/4-summary.md b/data/part-4/4-summary.md index 7b90dc174..28fc118fc 100644 --- a/data/part-4/4-summary.md +++ b/data/part-4/4-summary.md @@ -5,17 +5,16 @@ title: 'Summary' hidden: false --- - - + + In the fourth part of the course we learned to read data from files, and took our first steps towards object-oriented programming. We learned classes and objects to suit our programming needs. We defined constructors, methods, and object variables for the classes, and grew used to printing object-related information with their `toString` method. We also practised handling objects on a list. - - + + Please take a moment to answer the questionnaire below. diff --git a/data/part-4/index.md b/data/part-4/index.md index ac71e4148..cef14c05c 100644 --- a/data/part-4/index.md +++ b/data/part-4/index.md @@ -6,7 +6,7 @@ overview: true hidden: false --- - + The main theme of the fourth part is object-oriented programming. You will learn to read data from files and to represent and handle information with the help of objects. @@ -14,7 +14,7 @@ The main theme of the fourth part is object-oriented programming. You will learn - + The table of contents above lists the topics of the fourth part of the course. The fourth part has been designed to cover the fourth week of the course. You should reserve well above 10 hours for each part of the course, depending on previous experience with computers. If you've tried programming before, you might advance faster in the beginning. diff --git a/data/part-5/1-learning-object-oriented-programming.md b/data/part-5/1-learning-object-oriented-programming.md index 175486394..9762f3da0 100644 --- a/data/part-5/1-learning-object-oriented-programming.md +++ b/data/part-5/1-learning-object-oriented-programming.md @@ -7,28 +7,20 @@ hidden: false --- - + - + - To revise the concepts of class and object. - To realize that a program that has been written without objects can also be written using objects. - To realize that the use of objects can make a program more understandable. - - - So, what's object-oriented programming all about? @@ -38,52 +30,7 @@ The time is always printed in the form `hours: minutes: seconds`, where two digi The clock has been implemented below using integer variables (the printing could be in a separate method, but that has not been done here). - ```java int hours = 0; int minutes = 0; @@ -132,52 +79,18 @@ while (true) { ``` - + As we can see by reading the example above, how a clock consisting of three `int` variables works is not clear to someone reading the code. By looking at the code, it's difficult to "see" what's going on. A famous programmer once remarked *"Any fool can write code that a computer can understand .Good Programmers write code that humans can understand"*.
- - Our aim is to make the program more understandable. Since a clock hand is a clear concept in its own right, a good way to improve the program's clarity would be to turn it into a class. Let's create a `ClockHand` class that describes a clock hand, which contains information about its value, upper limit (i.e., the point at which the value of the hand returns to zero), and provides methods for advancing the hand, viewing its value, and also printing the value in string form. - ```java @@ -212,31 +125,10 @@ public class ClockHand { } ``` - -Once we've created the ClockHand class, our clock has become clearer. It's now straightforward to print the clock, i.e., the clock hand, and the hand's progression is hidden away in the ClockHand class. Since the the hand returns to the beginning automatically with the help of the upper-limit variable defined by the ClockHand class, the way the hands work together is slightly different than in the implementation that used integers. That one looked at whether the value of the integer that represented the clock hand exceeded the upper limit, after which its value was set to zero and the value of the integer representing the next clock hand was incremented. Using clock-hand objects, the minute hand advances when the second hand's value is zero, and the hour hand advances when the minute hand's value is zero. - - ```java ClockHand hours = new ClockHand(24); ClockHand minutes = new ClockHand(60); @@ -261,13 +153,7 @@ while (true) { ``` - **Object-oriented programming is primarily about isolating concepts into their own entities or, in other words, creating abstractions**. Despite the previous example, one might deem it pointless to create an object containing only a number since the same could be done directly with `int` variables. However, that is not always the case. @@ -279,35 +165,7 @@ We realized that the clock contains three hands, i.e., it consists of three conc - ```java public class Clock { private ClockHand hours; @@ -339,19 +197,12 @@ public class Clock { ``` - + The way the program functions has become increasingly clearer. When you compare our program below to the original one that was made up of integers, you'll find that the program's readability is superior. - ```java Clock clock = new Clock(); @@ -362,34 +213,23 @@ while (true) { ``` - + The clock we implemented above is an object whose functionality is based on "simpler" objects, i.e., its hands. This is precisely the **great idea behind ​​object-oriented programming: a program is built from small and distinct objects that work together** - - + - The exercise template comes with the "ClockHand" class described above. Implement a `Timer` class based on the material's `Clock` class. The timer has two hands, one for hundredths of a second and one for seconds. As it progresses, the number of hundredths of a second grows by one. When the hand corresponding to hundredths of a second reaches a value of 100, its value is set to zero, and the number of seconds grows by one. In the same way, when the value of the hand corresponding to seconds reaches the value of sixty, its value is set to zero. - - `public Timer()` creates a new timer. - `public String toString()` returns a string representation of the timer. The string representation should be in the form "seconds: hundredths of a second", where both the seconds and the hundredths of a second are represented by two numbers. For example, "19:83" would represent the time 19 seconds, 83 hundredths of a second. @@ -402,20 +242,7 @@ Once you've completed the task, return it to the server. You can test out the timer's functionality in the main program whenever you like. The example code below provides you with a program where the timer is printed and it advances once every hundredth of a second. - ```java Timer timer = new Timer(); @@ -431,7 +258,7 @@ while (true) { } ``` - + NB! The program above will never stop running by itself. Press the red square to the left of the program's print window to turn it off. @@ -439,32 +266,11 @@ NB! The program above will never stop running by itself. Press the red square to - -Next, let's review topic terminology. - - - ## Object @@ -483,34 +289,7 @@ In reality, we can relate all kinds of different information and things to a per In the Java programming language, a Person object that keeps track of name, age, weight, and height, and provides the ability to calculate body mass index and maximum heart rate would look like the following. Below, the height and weight are expressed as doubles - the unit of length is one meter. - ```java public class Person { private String name; @@ -541,23 +320,10 @@ public class Person { ``` - + Determining the maximum heart rate and body mass index of a given person is straightforward using the Person class described above. - + ```java Scanner reader = new Scanner(System.in); System.out.println("What's your name?"); @@ -575,15 +341,7 @@ System.out.println(person); - + What's your name? **Napoleone Buonaparte** What's your age @@ -597,50 +355,13 @@ Napoleone Buonaparte, BMI: 27.68166089965398, maximum heart rate: 170.0390000000 - ## Class A class defines the types of objects that can be created from it. It contains instance variables describing the object's data, a constructor or constructors used to create it, and methods that define its behavior. A rectangle class is detailed below which defines the functionality of a rectangle. - ```java // class @@ -678,10 +399,7 @@ public class Rectangle { ``` - Some of the methods defined above do not return a value (methods that have the keyword `void` in their definition), while others do (methods that specify the type of variable to be returned). The class above also defines the `toString` method, which returns the string used to print the object. @@ -689,16 +407,7 @@ Some of the methods defined above do not return a value (methods that have the k Objects are created from the class through constructors by using the `new` command. Below, we'll create two rectangles and print information related to them. - ```java Rectangle first = new Rectangle(40, 80); Rectangle rectangle = new Rectangle(10, 10); @@ -720,19 +429,10 @@ System.out.println(first.surfaceArea());
- - - - Create a "Book" class that describes a book. Each book has an author, title, and page count. @@ -747,7 +447,7 @@ In addition, make a `public String toString()` method for the book that will be - + J. K. Rowling, Harry Potter and the Sorcerer's Stone, 223 pages @@ -755,16 +455,10 @@ J. K. Rowling, Harry Potter and the Sorcerer's Stone, 223 pages - - - - Create a `Cube` class that represents a cube (i.e., a standard hexahedron). Create a `public Cube (int edgeLength)` constructor for the class, that takes the length of the cube's edge as its parameter. @@ -774,17 +468,7 @@ Make a `public int volume()` method for the cube, which calculates and returns t Examples are provided underneath - ```java Cube oSheaJackson = new Cube(4); System.out.println(oSheaJackson.volume()); @@ -799,11 +483,7 @@ System.out.println(salt); - 64 The length of the edge is 4 and the volume 64 @@ -816,30 +496,21 @@ The length of the edge is 2 and the volume 8 - + - -The Karvonen method allows you to calculate your target heart rate for physical exercise. The target heart rate is calculated with the formula `(maximum heart rate - resting heart rate) * (target heart rate percentage) + resting heart rate`, where the target heart rate is given as a percentage of the maximum heart rate. - -For example, if a person has a maximum heart rate of `200`, a resting heart rate of `50`, and a target heart rate of `75%` of the maximum heart rate, the target heart rate should be about `((200-50) * (0.75) + 50)`, i.e., `162.5` beats per minute. +The Karvonen method allows you to calculate your target heart rate for physical exercise. The target heart rate is calculated with the formula `(maximum heart rate - resting heart rate) * (target heart rate percentage) + resting heart rate`, where the target heart rate is given as a percentage of the maximum heart rate. - -Create a class called `Fitbyte`. Its constructor takes both an age and a resting heart rate as its parameters. The exercise assistant should provide a method targetHeartRate, which is passed a number of type double as a parameter that represents a percentual portion of the maximum heart rate. The proportion is given as a number between zero and one. The class should have: - - A constructor `public Fitbyte(int age, int restingHeartRate)` - A method `public double targetHeartRate(double percentageOfMaximum)` that calculates and returns the target heart rate. @@ -850,17 +521,7 @@ Use the `206.3 - (0.711 * age)` formula to calculate the maximum heart rate. Use case: - ```java Fitbyte assistant = new Fitbyte(30, 60); @@ -874,13 +535,7 @@ while (percentage < 1.0) { ``` - + Target 50.0% of maximum: 122.48500000000001 Target 60.0% of maximum: 134.98200000000003 diff --git a/data/part-5/2-method-and-constructor-overloading.md b/data/part-5/2-method-and-constructor-overloading.md index d1e3117fd..9bc41008f 100644 --- a/data/part-5/2-method-and-constructor-overloading.md +++ b/data/part-5/2-method-and-constructor-overloading.md @@ -14,7 +14,7 @@ hidden: false
- + Let's once more return to our Person class. It currently looks like this: @@ -82,7 +82,7 @@ public class Person { ``` - + All person objects are 0 years old when created. This is because the constructor sets the value of the instance variable `age` to 0: ```java @@ -98,7 +98,7 @@ public Person(String name) { ## Constructor Overloading - + We would also like to be able to create persons so that the constructor is provided both the age as well as the name as parameters. This is possible since a class may have multiple constructors. Let's make an alternative constructor. The old constructor can remain in place. @@ -121,7 +121,7 @@ public Person(String name, int age) { ``` - + We now have two alternative ways to create objects: @@ -143,7 +143,7 @@ Ada is 0 years old.
- + The technique of having two (or more) constructors in a class is known as *constructor overloading*. A class can have multiple constructors that differ in the number and/or type of their parameters. It's not, however, possible to have two constructors with the exact same parameters. We cannot, for example, add a `public Person(String name, int weight)` constructor since it would be impossible for Java to differentiate between this and the one that has two parameters where int parameter is used for age. @@ -153,19 +153,19 @@ We cannot, for example, add a `public Person(String name, int weight)` construct ## Calling Your Constructor - + Hold on a moment. We'd previously concluded that "copy-paste" code is not a good idea. When you look at the overloaded constructors above, however, they have a lot in common. We're not happy with this. - + The first constructor - the one that receives a name as a parameter - is in fact a special case of the second constructor - the one that's given both name and age. What if the first constructor could call the second constructor? - + This is possible. A constructor can be called from another constructor using the `this` keyword, which refers to this object in question! - + Let's modify the first constructor so that it does not do anything by itself, but instead calls the second constructor and asks it to set the age to 0. @@ -183,11 +183,11 @@ public Person(String name, int age) { } ``` - + The constructor call `this(name, 0);` might seem a bit weird. A way to think about it is to imagine that the call is automatically replaced with "copy-paste" of the second constructor in such a way that the age parameter is set to 0. NB! If a constructor calls another constructor, the constructor call must be the first command in the constructor. - + New objects can be created just as before: @@ -210,28 +210,28 @@ Eve is 0 years old. - + - + The exercise template has a class `Product`, which represents a product in a shop. Every product has a name, location and weight. - + Add the following three constructors to the `Product` class: - + - `public Product(String name)` creates a product with the given name. Its location is set to "shelf" and its weight is set to 1. - + - `public Product(String name, String location)` creates a product with the given name and the given location. Its weight is set to 1. - + - `public Product(String name, int weight)` creates a product with the given name and the given weight. Its location is set to "shelf". - + You can test your program with the following code: @@ -260,7 +260,7 @@ Tyre (5 kg) can be found from the shelf ## Method Overloading - + Methods can be overloaded in the same way as constructors, i.e., multiple versions of a given method can be created. Once again, the parameters of the different versions must be different. Let's make another version of the `growOlder` method that ages the person by the amount of years given to it as a parameter. @@ -274,7 +274,7 @@ public void growOlder(int years) { } ``` - + In the example below, "Paul" is born 24 years old, ages by a year and then by 10 years: @@ -304,11 +304,11 @@ Paul is 35 years old.
- + A Person now has two methods, both called `growOlder`. The one that gets executed depends on the number of parameters provided. - + We may also modify the program so that the parameterless method is implemented using the method `growOlder(int years)`: @@ -324,7 +324,7 @@ public void growOlder(int years) { - + @@ -336,26 +336,26 @@ public void growOlder(int years) {

Multiple constructors

- + Implement a class called `Counter`. The class contains a number whose value can be incremented and decremented. The class must have the following constructors: - - + + - `public Counter(int startValue)` sets the start value of the counter to startValue. - `public Counter()` sets the start value of the counter to 0. - + And the following methods: - - - + + + - `public int value()` returns the current value of the counter - `public void increase()` increases the value by 1 - `public void decrease()` decreases the value by 1 @@ -363,14 +363,14 @@ And the following methods:

Alternative methods

- + Implement versions which are given one parameter of the methods `increase` and `decrease`. - + - `public void increase(int increaseBy)` increases the value of the counter by the value of increaseBy. If the value of increaseBy is negative, the value of the counter does not change. - + - `public void decrease(int decreaseBy)` decreases the value of the counter by the value of decreaseBy. If the value of decreaseBy is negative, the value of the counter does not change.
diff --git a/data/part-5/3-primitive-and-reference-variables.md b/data/part-5/3-primitive-and-reference-variables.md index f6308d6de..e302f04d4 100644 --- a/data/part-5/3-primitive-and-reference-variables.md +++ b/data/part-5/3-primitive-and-reference-variables.md @@ -7,36 +7,33 @@ hidden: false --- - + - + - You understand the terms primitive and reference variable. - + - You know the types of primitive variables in Java, and also that there can be practically an infinite number of different reference variables. - + - You know the differences in behavior between primitive and reference variables when values are assigned to them, or when they're used as method parameters. - + Variables in Java are classified into primitive and reference variables. From the programmer's perspective, a primitive variable's information is stored as the value of that variable, whereas a reference variable holds a reference to information related to that variable. reference variables are practically always objects in Java. Let's take a look at both of these types with the help of two examples. - + ```java int value = 10; @@ -50,15 +47,7 @@ System.out.println(value);
- ```java public class Name { @@ -70,21 +59,14 @@ public class Name { } ``` - + ```java Name luke = new Name("Luke"); System.out.println(luke); ``` - @@ -92,34 +74,22 @@ Name@4aa298b7 - + In the first example, we create a primitive `int` variable, and the number 10 is stored as its value. When we pass the variable to the `System.out.println` method, the number `10` is printed. In the second example, we create a reference variable called `luke`. A reference to an object is returned by the constructor of the `Name` class when we call it, and this reference is stored as the value of the variable. When we print the variable, we get `Name@4aa298b7` as output. What is causing this? - + The method call `System.out.println` prints the value of the variable. The value of a primitive variable is concrete, whereas the value of a reference variable is a reference. When we attempt to print the value of a reference variable, the output contains the type of the variable and an identifier created for it by Java: the string `Name@4aa298b7` tells us that the given variable is of type `Name` and its identifier is `4aa298b7`. - + The previous example applies whenever the programmer has not altered an object's default print format. You can modify the default print by defining the `toString` method within the class of the given object, where you specify what the objects print should look like. In the example below, we've defined the `public String toString()` method within the `Name` class, which returns the instance variable `name`. Now, when we print any object that is an instance of the `Name` class with the `System.out.println` command, the string returned by the `toString` method is what gets printed. - ```java public class Name { @@ -135,11 +105,7 @@ public class Name { } ``` - + ```java @@ -147,11 +113,7 @@ Name luke = new Name("Luke"); System.out.println(luke); // equal to System.out.println(luke.toString()); ``` - @@ -160,28 +122,20 @@ Luke - + ## Primitive Variables - + Java has eight different primitive variables. These are: `boolean` (a truth value: either `true` or `false`), `byte` (a byte containing 8 bits, between the values `-128` and `127`), `char` (a 16-bit value representing a single character), `short` (a 16-bit value that represents a small integer, between the values `-32768` and `32767`), `int` (a 32-bit value that represents a medium-sized integer, between the values -231 and 231-1), `long` (a 64-bit value that represents a large integer, between values -263 and 263-1), `float` (a floating-point number that uses 32 bits), and `double` (a floating-point number that uses 64 bits). - + Out of all of these, we've mainly been using the truth value (`boolean`), integer (`int`) and floating-point variables (`double`). - ```java boolean truthValue = false; @@ -202,19 +156,12 @@ false
- + Declaring a primitive variable causes the computer to reserve some memory where the value assigned to the variable can be stored. The size of the storage container reserved depends on type of the primitive. In the example below, we create three variables. Each one has its own memory location to which the value that is assigned is copied. - + ```java int first = 10; @@ -231,156 +178,124 @@ System.out.println(first + " " + second + " " + third); ``` - + The name of the variable tells the memory location where its value is stored. When you assign a value to a primitive variable with an equality sign, the value on the right side is copied to the memory location indicated by the name of the variable. For example, the statement `int first = 10` reserves a location called `first` for the variable, and then copies the value `10` into it. - + Similarly, the statement `int second = first;` reserves in memory a location called `second` for the variable being created and then copies into it the value stored in the location of variable `first`. - + The values of variables are also copied whenever they're used in method calls. What this means in practice is that the value of a variable that's passed as a parameter during a method call is not mutated in the calling method by the method called. In the example below, we declare a 'number' variable in the main method whose value is copied as the method call's parameter. In the method being called, the value that comes through the parameter is printed, its value is then incremented by one. The value of the variable is then printed once more, and the program execution finally returns to the main method. The value of the 'number' variable in the main method remains unaltered because it has nothing to do with the 'number' variable defined as the parameter of the method that's called. - + - + ## Reference Variables - + All of the variables provided by Java (other than the eight primitive variables mentioned above) are reference type. A programmer is also free to create their own variable types by defining new classes. In practice, any object instanced from a class is a reference variable. - + Let's look at the example from the beginning of the chapter where we created a variable called 'leevi' of type Name. - + ```java Name leevi = new Name("Leevi"); ``` - + The call has the following parts: - + - Whenever a new variable is declared, its type must be stated first. We declare a variable of type `Name` below. For the program to execute successfully, there must be a `Name` class available for the program to use. - + ```java Name ... ``` - + - We state the name of the variable as its declared. You can reference the value of the variable later on by its name. Below, the variable name is defined as leevi. - + ```java Name leevi... ``` - + - Values can be assigned to variables. Objects are created from classes by calling the class constructor. This constructor defines the values assigned to the instance variables of the object being created. We're assuming in the example below that the class `Name` has a constructor that takes a string as parameter. - + ```java ... new Name("Leevi"); ``` - + - The constructor call returns a value that is a reference to the newly-created object. The equality sign tells the program that the value of the right-hand side expression is to be copied as the value of the variable on the left-hand side. The reference to the newly-created object, returned by the constructor call, is copied as the value of the variable `leevi`. - + ```java Name leevi = new Name("Leevi"); ``` - + The most significant difference between primitive and reference variables is that primitives (usually numbers) are immutable. The internal state of reference variables, on the other hand, can typically be mutated. This has to do with the fact that the value of a primitive variable is stored directly in the variable, whereas the value of a reference variable is a reference to the variable's data, i.e., its internal state. - + Arithmetic operations, such as addition, subtraction, and multiplication can be used with primitive variables -- these operations do not change the original values of the variables. Arithmetic operations create new values that can be stored in variables as needed. Conversely, the values of reference variables cannot be changed by these arithmetic expressions. - + The value of a reference variable -- i.e., the reference -- points to a location that contains information relating to the given variable. Let's assume that we have a Person class available to us, containing an instance variable 'age'. If we've instantiated a person object from the class, we can get our hands on the age variable by following the object's reference. The value of this age variable can then be changed as needed. - + ## Primitive and Reference Variable as Method Parameters - + We mentioned earlier that the value of a primitive variable is directly stored in the variable, whereas the value of a reference variable holds a reference to an object. We also mentioned that assigning a value with the equality sign copies the value (possibly of some variable) on the right-hand side and stores it as the value of the left-hand side variable. - + A similar kind of copying occurs during a method call. Regardless of whether the variable is primitive or reference type, the value passed to the method as an argument is copied for the called method to use. With primitive variables, the value of the variable is conveyed to the method. With reference variables, it's a reference. - -Let's look at this in practice and assume that we have the following `Person` class available to us. - ```java public class Person { @@ -406,30 +321,11 @@ public class Person { } ``` - -We'll inspect the execution of the program step by step. - - ```java public class Example { @@ -452,13 +348,7 @@ public class Example { } ``` - @@ -468,12 +358,12 @@ First (1972) - + The program's execution starts off from the first line of the main method. A variable of type Person is declared on its first line, and the value returned by the Person class constructor is copied as its value. The constructor creates an object whose birth year is set to 1970 and whose name is set to the value received as a parameter. The constructor returns a reference. Once the row has been executed, the program's state is the following -- a Person object has been created in memory and the `first` variable defined in the main method contains a reference to it. - + *In the illustrations below, the call stack is on the left-hand side, and the memory of the program on the right. @@ -481,12 +371,12 @@ The program's execution starts off from the first line of the main method. A var - + On the third row of the main method, we print the value of the variable `first`. The method call System.out.println searches for the toString method on the reference variable that has been given to it as the parameter. The Person class has the toString method, so this method is called on the object referenced by the `first` variable. The value of the `name` variable in that object is "First", and the value of the `birthYear` variable is 1970. The output becomes "First (1970)". - + On the fourth row, the program calls the `youthen` method, to which we pass the variable `first` as an argument. When the method `youthen` is called, the value of the parameter variable is copied to be used by the `youthen` method. The execution of the `main` method remains waiting in the call stack. As the variable `first` is a reference type, the reference that was created earlier is copied for the method's use. At the end of the method execution, the situation is as follows -- the method increments the birth year of the object it receives as a parameter by one. @@ -494,18 +384,18 @@ On the fourth row, the program calls the `youthen` method, to which we pass the - + When the execution of the method makeYounger ends, we return back to the main method. The information related to the execution of the makeYounger disappears from the call stack. - + Once we've returned from the method call, we once again print the value of the variable `first`. The object referenced by the variable `first` has been mutated during the `youthen` method call: the `birthYear` variable of the object has been incremented by one. The final value printed is "First (1971)". - + A new Person-type variable called `second` is then declared in the program. The value of the variable `first` is copied to the variable second, i.e., the value of the variable `second` becomes a reference to the already-existing Person object. @@ -513,14 +403,14 @@ A new Person-type variable called `second` is then declared in the program. The - + The program calls the `youthen` method after this, which is given the `second` variable as a parameter. The value of the variable passed during the method call is copied as a value for the method, i.e., the method receives the reference contained in the `second` variable for its use. After the method's execution, the birth year of the object referenced by the method has increased by one. - + Finally, the method execution ends, and the program returns to the main method where the value of the variable first is printed one more time. The final result of the print is "First(1972)". @@ -530,24 +420,24 @@ Finally, the method execution ends, and the program returns to the main method w - + - + In the course's material, concrete details related to variables and computer memory are simplified. Topics related to memory are dealt with on a level of abstraction that's suitable for learning programming. As an example, the description that the statement `int number = 5` reserves a location for the variable `number` in the memory, and copies the value 5 into it, is sufficient with regard to the learning objectives of this course. - + From the perspective of the operating system, a lot more happens when the statement `int number = 5` is executed. A locker of size 32-bits is reserved in memory for the value `5`, and another one for the `number` variable. The size of the location is determined by the type of variable in question. Once this is done, the contents of the memory location storing the value 5 are copied into the memory location of the `number` variable. - + To add to the above, the `number` variable is technically not a memory location or a container. The value of the variable `number` is an address in memory -- information attached to the variable about its type specifies how much data should be retrieved from its address. As an example, this is 32 bits for an integer. - + We'll return to this briefly in the advanced programming course. The topic is dealt with in depth in the Computer Organization course. diff --git a/data/part-5/4-objects-and-references.md b/data/part-5/4-objects-and-references.md index c29ec8117..96075c764 100644 --- a/data/part-5/4-objects-and-references.md +++ b/data/part-5/4-objects-and-references.md @@ -6,95 +6,40 @@ title: 'Objects and references' hidden: false --- - + - + - You will brush up on using classes and objects. - + - You know what a `null` reference is, and what causes the NullPointerException error. - + - You can use an object as an object variable and a method parameter. - + - You can create a method that returns an object. - + - You can create the method equals, which can be used to check if two objects of the same type have the same contents or state. - - -Let's continue working with objects and references. Assume we can use the class that represents a person, shown below. Person has object variables name, age, weight and height. Additionally, it contains methods to calculate the body mass index, among other things. - - - ```java public class Person { @@ -154,26 +99,24 @@ public class Person { ``` - + Precisely what happens when a new object is created? - + ```java Person joan = new Person("Joan Ball"); ``` - + Calling a constructor with the command `new` causes several things to happen. First, space is reserved in the computer memory for storing object variables. Then default or initial values are set to object variables (e.g. an `int` type variable receives an initial value of 0). Lastly, the source code in the constructor is executed. - + A constructor call returns a reference to an object. A **reference** is information about the location of object data. @@ -181,26 +124,21 @@ A constructor call returns a reference to an object. A **reference** is informat - + So the value of the variable is set to be a reference, i.e. knowledge about the location of related object data. The image above also reveals that strings -- the name of our example person, for instance -- are objects, too. - + ## Assigning a reference type variable copies the reference - + Let's add a `Person` type variable called `ball` into the program, and assign `joan` as its initial value. What happens then? - ```java Person joan = new Person("Joan Ball"); @@ -209,7 +147,7 @@ System.out.println(joan); Person ball = joan; ``` - + The statement `Person ball = joan;` creates a new Person variable `ball`, and copies the value of the variable `joan` as its value. As a result, `ball` refers to the same object as `joan`. @@ -217,21 +155,12 @@ The statement `Person ball = joan;` creates a new Person variable `ball`, and co - -Let's inspect the same example a little more thoroughly. +Let's inspect the same example a little more thoroughly. - ```java Person joan = new Person("Joan Ball"); @@ -244,12 +173,7 @@ ball.growOlder(); System.out.println(joan); ``` - @@ -258,12 +182,12 @@ Joan Ball, age 2 years - + Joan Ball -- i.e. the Person object that the reference in the `joan` variable points at -- starts as 0 years old. After this the value of the `joan` variable is assigned (so copied) to the `ball` variable. The Person object `ball` is aged by two years, and Joan Ball ages as a consequence! - + An object's internal state is not copied when a variable's value is assigned. A new object is not being created in the statement `Person ball = joan;` -- the value of the variable ball is assigned to be the copy of joan's value, i.e. a reference to an object. @@ -271,23 +195,11 @@ An object's internal state is not copied when a variable's value is assigned. A - - -Next, the example is continued so that a new object is created for the `joan` variable, and a reference to it is assigned as the value of the variable. The variable `ball` still refers to the object that we created earlier. - ```java Person joan = new Person("Joan Ball"); @@ -304,18 +216,12 @@ System.out.println(joan); ``` - -The following is printed: +The following is printed: - @@ -326,38 +232,24 @@ Joan B., age 0 years - + So in the beginning the variable `joan` contains a reference to one object, but in the end a reference to another object has been copied as its value. Here is a picture of the situation after the last line of code. - - -## `null` value of a reference variable - +## `null` value of a reference variable -Let's extend the example further by setting the value of the reference variable `ball` to `null`, i.e. a reference "to nothing". The `null` reference can be set as the value of any reference type variable. - ```java Person joan = new Person("Joan Ball"); @@ -375,39 +267,24 @@ System.out.println(joan); ball = null; ``` - + The situation of the program after the last line is depicted below. - - -The object whose name is Joan Ball is referred to by nobody. In other words, the object has become "garbage". In the Java programming language the programmer need not worry about the program's memory use. From time to time, the automatic garbage collector of the Java language cleans up the objects that have become garbage. If the garbage collection did not happen, the garbage objects would reserve a memory location until the end of the program execution. - +The object whose name is Joan Ball is referred to by nobody. In other words, the object has become "garbage". In the Java programming language the programmer need not worry about the program's memory use. From time to time, the automatic garbage collector of the Java language cleans up the objects that have become garbage. If the garbage collection did not happen, the garbage objects would reserve a memory location until the end of the program execution. -Let's see what happens when we try to print a variable that references "nothing" i.e. `null`. - ```java Person joan = new Person("Joan Ball"); @@ -426,14 +303,7 @@ ball = null; System.out.println(ball); ``` - @@ -445,18 +315,12 @@ null - + Printing a `null` reference prints "null". How about if we were to try and call a method, say `growOlder`, on an object that refers to nothing: - ```java Person joan = new Person("Joan Ball"); @@ -466,17 +330,14 @@ joan = null; joan.growOlder(); ``` - + The result: - + Joan Ball, age 0 years **Exception in thread "main" java.lang.NullPointerException @@ -486,22 +347,22 @@ Joan Ball, age 0 years - + Bad things follow. This could be the first time you have seen the text **NullPointerException**. In the course of the program, there occured an error indicating that we called a method on a variable that refers to nothing. - + We promise that this is not the last time you will encounter the previous error. When you do, the first step is to look for variables whose value could be `null`. Fortunately, the error message is useful: it tells which row caused the error. Try it out yourself! - + - + Implement a program that causes the NullPointerException error. The error should occur directly after starting the program -- don't wait to read input from the user, for instance. @@ -509,36 +370,22 @@ Implement a program that causes the NullPointerException error. The error should - + ## Object as a method parameter - + We have seen both primitive and reference variables act as method parameters. Since objects are reference variables, any type of object can be defined to be a method parameter. Let's take a look at a practical demonstration. - -Amusement park rides only permit people who are taller than a certain height. The limit is not the same for all attractions. Let's create a class representing an amusement park ride. When creating a new object, the constructor receives as parameters the name of the ride, and the smallest height that permits entry to the ride. +Amusement park rides only permit people who are taller than a certain height. The limit is not the same for all attractions. Let's create a class representing an amusement park ride. When creating a new object, the constructor receives as parameters the name of the ride, and the smallest height that permits entry to the ride. - ```java public class AmusementParkRide { @@ -556,38 +403,16 @@ public class AmusementParkRide { } ``` - -Then let's write a method that can be used to check if a person is allowed to enter the ride, so if they are tall enough. The method returns `true` if the person given as the parameter is permitted access, and `false` otherwise. - - -Below, it is assumed that Person has the method `public int getHeight()` that returns the height of the person. +Then let's write a method that can be used to check if a person is allowed to enter the ride, so if they are tall enough. The method returns `true` if the person given as the parameter is permitted access, and `false` otherwise. - ```java public class AmusementParkRide { @@ -613,40 +438,16 @@ public class AmusementParkRide { } ``` - - -So the method `allowedToRide` of an AmusementParkRide object is given a `Person` object as a parameter. Like earlier, the value of the variable -- in this case, a reference -- is copied for the method to use. The method handles a copied reference, and it calls the `getHeight` method of the person passed as a parameter. - - -Below is an example main program where the amusement park ride method is called twice: first the supplied parameter is a person object `matt`, and then a person object `jasper`: +So the method `allowedToRide` of an AmusementParkRide object is given a `Person` object as a parameter. Like earlier, the value of the variable -- in this case, a reference -- is copied for the method to use. The method handles a copied reference, and it calls the `getHeight` method of the person passed as a parameter. - ```java Person matt = new Person("Matt"); @@ -674,17 +475,11 @@ if (waterTrack.allowedToRide(jasper)) { System.out.println(waterTrack); ``` - -The output of the program is: - @@ -694,42 +489,16 @@ Water track, minimum height: 140 - - -What if we wanted to know how many people have taken the ride? - -Let's add an object variable to the amusement park ride. It keeps track of the number of people that were permitted to enter. +What if we wanted to know how many people have taken the ride? - ```java public class AmusementParkRide { @@ -759,35 +528,11 @@ public class AmusementParkRide { } ``` - - -Now the previously used example program also keeps track of the number of visitors who have experienced the ride. - - ```java Person matt = new Person("Matt"); @@ -815,17 +560,11 @@ if (waterTrack.allowedToRide(jasper)) { System.out.println(waterTrack); ``` - -The output of the program is: - @@ -836,22 +575,22 @@ Water track, minimum height: 140, visitors: 1 - + - + Development environments can help the programmer. If you have created object variables for a class, creating constructors, getters, and setters can be done almost automatically. - + Go inside the code block of the class, but outside of all the methods, and simultaneously press ctrl and space. If your class has e.g. an object variable `balance`, NetBeans offers the option to generate the getter and setter methods for the object variable, and a constuctor that assigns an initial value for that variable. - + On some Linux machines, like on the ones on the Kumpula campus (University of Helsinki), this feature is triggered by simultaneously pressing ctrl, alt, and space. @@ -859,34 +598,26 @@ On some Linux machines, like on the ones on the Kumpula campus (University of He - + - + In the exercise base there is the class `Person`, which we are already quite familiar with. There is also an outline for the class `HealthStation`. Health station objects process people in different ways, they e.g. weigh and feed people. In this exercise we will construct a health station. The code of the Person class should not be modified in this exercise! - +

Weighing people

- + In the outline of the Health station there is an outline for the method `weigh`: - ```java public class HealthStation { @@ -898,27 +629,15 @@ public class HealthStation { } ``` - -The method receives a person as a parameter, and it is meant to return to its caller the weight of that person. The weight information can be found by calling a suitable method of the person `person`. **So your task is to complete the code of the method!** - +The method receives a person as a parameter, and it is meant to return to its caller the weight of that person. The weight information can be found by calling a suitable method of the person `person`. **So your task is to complete the code of the method!** -Here is a main program where a health station weight two people: - ```java public static void main(String[] args) { @@ -935,7 +654,7 @@ public static void main(String[] args) { ``` - + The output should be the following: @@ -947,40 +666,21 @@ Peter's weight: 85 kilos
- - -

Feeding

- +

Feeding

-It is possible to modify the state of the object that is received as a parameter. Write a method called `public void feed(Person person)` for the health station. It should increase the weight of the parameter person by one. - -Following is an example where people are weighed first, and then ethan is fed three times in the children's hospital. After this the people are weighed again: +It is possible to modify the state of the object that is received as a parameter. Write a method called `public void feed(Person person)` for the health station. It should increase the weight of the parameter person by one. - ```java public static void main(String[] args) { @@ -1003,19 +703,11 @@ public static void main(String[] args) { } ``` - - -The output should reveal that Ethan's weight has increased by three: - @@ -1028,41 +720,18 @@ Peter weight: 85 kilos - -

Counting weighings

- - - - - -Create a new method called `public int weighings()` for the health station. It should tell how many weighings the health station has performed. *NB! You will need a new object variable for counting the number of weighings!*. Test main program: +

Counting weighings

- ```java public static void main(String[] args) { @@ -1088,17 +757,11 @@ public static void main(String[] args) { } ``` - -The output is: - @@ -1111,57 +774,36 @@ weighings performed: 6
- + - +

"Dumb" payment card

- + In a previous part we created a class called PaymentCard. The card had methods for eating affordably and heartily, and also for adding money to the card. - -However, there was a problem with the PaymentCard class that is implemented in this fashion. The card knew the prices of the different lunches, and therefore was able to decrease the balance by the proper amount. What about if the prices are raised? Or new items are added to the list of offered products? A change in the pricing would mean that all the existing cards would have to be replaced with new cards that are aware of the new prices. - +However, there was a problem with the PaymentCard class that is implemented in this fashion. The card knew the prices of the different lunches, and therefore was able to decrease the balance by the proper amount. What about if the prices are raised? Or new items are added to the list of offered products? A change in the pricing would mean that all the existing cards would have to be replaced with new cards that are aware of the new prices. -An improved solution is to make the cards "dumb"; unaware of the prices and products that are sold, and only keeping track of their balance. All the intelligence is better placed in separate objects, payment terminals. - -Let's first implement the "dumb" version of the PaymentCard. The card only has methods for asking for the balance, adding money, and taking money. Complete the method `public boolean takeMoney(double amount)` in the class below (and found in the exercise template), using the following as a guide: +An improved solution is to make the cards "dumb"; unaware of the prices and products that are sold, and only keeping track of their balance. All the intelligence is better placed in separate objects, payment terminals. - ```java public class PaymentCard { @@ -1187,26 +829,11 @@ public class PaymentCard { } ``` - -Test main program: - ```java public class MainProgram { @@ -1225,19 +852,11 @@ public class MainProgram { } ``` - -The output should be like below - @@ -1250,48 +869,22 @@ money 2.0 - -

Payment terminal and cash

+

Payment terminal and cash

- -When visiting a student cafeteria, the customer pays either with cash or with a payment card. The cashier uses a payment terminal to charge the card or to process the cash payment. First, let's create a terminal that's suitable for cash payments. - +When visiting a student cafeteria, the customer pays either with cash or with a payment card. The cashier uses a payment terminal to charge the card or to process the cash payment. First, let's create a terminal that's suitable for cash payments. -The outline of the payment terminal. The comments inside the methods tell the wanted functionality: - ```java public class PaymentTerminal { @@ -1321,28 +914,11 @@ public class PaymentTerminal { } ``` - - -The terminal starts with 1000 euros in it. Implement the methods so they work correctly, using the basis above and the example prints of the main program below. - - ```java public class MainProgram { @@ -1363,14 +939,7 @@ public class MainProgram { } ``` - @@ -1382,34 +951,16 @@ money: 1009.3, number of sold afforable meals: 2, number of sold hearty meals: 1 - -

Card payments

+

Card payments

- -Let's extend our payment terminal to also support card payments. We are going to create new methods for the terminal. It receives a payment card as a parameter, and decreases its balance by the price of the meal that was purchased. Here are the outlines for the methods, and instructions for completing them. - ```java public class PaymentTerminal { @@ -1432,37 +983,17 @@ public class PaymentTerminal { ``` - - -**NB:** card payments don't increase the amount of cash in the register - +**NB:** card payments don't increase the amount of cash in the register -Below is a main program to test the classes, and the output that is desired: - ```java public class MainProgram { @@ -1486,15 +1017,7 @@ public class MainProgram { } ``` - @@ -1507,21 +1030,17 @@ money: 1002.5, number of sold afforable meals: 2, number of sold hearty meals: 1 - +

Adding money

- + Let's create a method for the terminal that can be used to add money to a payment card. Recall that the payment that is received when adding money to the card is stored in the register. The basis for the method: - + ```java public void addMoneyToCard(PaymentCard card, double sum) { @@ -1530,35 +1049,12 @@ public void addMoneyToCard(PaymentCard card, double sum) { ``` - + A main program to illustrate: - ```java public class MainProgram { @@ -1585,16 +1081,7 @@ public class MainProgram { } ``` - @@ -1611,49 +1098,20 @@ money: 1100.0, number of sold afforable meals: 0, number of sold hearty meals: 1
- -## Object as object variable +## Object as object variable - -Objects may contain references to objects. - -Let's keep working with people, and add a birthday to the person class. A natural way of representing a birthday is to use a `Date` class. We could use the classname `Date`, but for the sake of avoiding confusion with the [similarly named existing Java class](https://docs.oracle.com/javase/8/docs/api/java/util/Date.html), we will use `SimpleDate` here. - - ```java public class SimpleDate { @@ -1686,19 +1144,11 @@ public class SimpleDate { } ``` - + Since we know the birthday, there is no need to store that age of a person as a separate object variable. The age of the person can be inferred from their birthday. Let's assume that the class `Person` now has the following variables. - ```java public class Person { @@ -1710,16 +1160,11 @@ public class Person { // ... ``` - + Let's create a new Person constructor that allows for setting the birthday: - + ```java public Person(String name, SimpleDate date) { @@ -1728,16 +1173,11 @@ public Person(String name, SimpleDate date) { } ``` - + Along with the constructor above, we could give Person another constructor where the birthday was given as integers. - + ```java public Person(String name, int day, int month, int year) { @@ -1746,21 +1186,17 @@ public Person(String name, int day, int month, int year) { } ``` - + The constructor receives as parameters the different parts of the date (day, month, year). They are used to create a date object, and finally the reference to that date is copied as the value of the object variable `birthday`. - + Let's modify the `toString` method of the Person class so that instead of age, the method returns the birthday: - + ```java public String toString() { @@ -1768,18 +1204,11 @@ public String toString() { } ``` - + Let's see how the updated Person class works. - ```java SimpleDate date = new SimpleDate(1, 1, 780); @@ -1790,12 +1219,7 @@ System.out.println(muhammad); System.out.println(pascal); ``` - @@ -1805,58 +1229,42 @@ Blaise Pascal, born on 19.6.1623 - + Now a person object has object variables `name` and `birthday`. The variable `name` is a string, which itself is an object; the variable `birthday` is a SimpleDate object. - + Both variables contain a reference to an object. Therefore a person object contains two references. In the image below, weight and height are not considered at all. - + So the main program is connected to two Person objects by strands. A person has a name and a birthday. Since both variables are objects, these attributes exist at the other ends of the strands. - + Birthday appears to be a good extension to the Person class. Earlier we noted that the object variable `age` can be calculated with birthday, so it was removed. - - + - -In the section above, we use our own class `SimpleDate` to represent date, because it is suitable for illustrating and practising the operation of objects. If you want to handle dates in your own programs, it's worth reading about the premade Java class [LocalDate](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html). It contains a significant amount of functionality that can be used to handle dates. - -For example, the current date can be used with the existing `LocalDate` class in the following manner: +In the section above, we use our own class `SimpleDate` to represent date, because it is suitable for illustrating and practising the operation of objects. If you want to handle dates in your own programs, it's worth reading about the premade Java class [LocalDate](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html). It contains a significant amount of functionality that can be used to handle dates. - ```java import java.time.LocalDate; @@ -1879,23 +1287,18 @@ public class Example { - + - + Two classes, `Person` and `Pet`, are included in the exercise template. Each person has one pet. Modify the `public String toString` method of the `Person` class so that the string it returns tells the pet's name and breed in addition to the person's own name. - ```java Pet lucy = new Pet("Lucy", "golden retriever"); @@ -1904,11 +1307,7 @@ Person leo = new Person("Leo", lucy); System.out.println(leo); ``` - @@ -1919,25 +1318,15 @@ Leo, has a friend called Lucy (golden retriever) - + ## Object of same type as method parameter - -We will continue working with the `Person` class. We recall that persons know their birthdays: - ```java public class Person { @@ -1951,18 +1340,11 @@ public class Person { } ``` - + We would like to compare the ages of two people. The comparison can be done in multiple ways. We could, for instance, implement a method called `public int ageAsYears()` for the Person class; in that case, the comparison would happen in the following manner: - ```java Person muhammad = new Person("Muhammad ibn Musa al-Khwarizmi", 1, 1, 780); @@ -1973,29 +1355,20 @@ if (muhammad.ageAsYears() > pascal.ageAsYears()) { } ``` - + We are now going to learn a more "object-oriented" way to compare the ages of people. - + We are going to create a new method `boolean olderThan(Person compared)` for the Person class. It can be used to compare a certain person object to the person supplied as the parameter based on their ages. - + The method is meant to be used like this: - ```java Person muhammad = new Person("Muhammad ibn Musa al-Khwarizmi", 1, 1, 780); @@ -2008,23 +1381,19 @@ if (muhammad.olderThan(pascal)) { // same as muhammad.olderThan(pascal)==true } ``` - + The program above asks if al-Khwarizmi is older than Pascal. The method `olderThan` returns `true` if the object that is used to call the method (`object.olderThan(objectGivenAsParameter)`) is older than the object given as the parameter, and `false` otherwise. - + In practice, we call the `olderThan` method of the object that matches "Muhammad ibn Musa al-Khwarizmi", which is referred to by the variable `muhammad`. The reference `pascal`, matching the object "Blaise Pascal", is given as the parameter to that method. - -The program prints: - @@ -2032,56 +1401,16 @@ Muhammad ibn Musa al-Khwarizmi is older than Blaise Pascal - - -The method `olderThan` receives a person object as its parameter. More precisely, the variable that is defined as the method parameter receives a copy of the value contained by the given variable. That value is a reference to an object, in this case. - - - -The implementation of the method is illustrated below. Note that the **method may return a value in more than one place** -- here the comparison has been divided into multiple parts based on the years, the months, and the days: - - - ```java public class Person { @@ -2126,60 +1455,15 @@ public class Person { ``` - - -Let's pause for a moment to consider abstraction, one of the principles of object-oriented programming. The idea behind abstraction is to conceptualize the programming code so that each concept has its own clear responsibilities. When viewing the solution above, however, we notice that the comparison functionality would be better placed inside the `SimpleDate` class instead of the `Person` class. - - - -We'll create a method called `public boolean before(SimpleDate compared)` for the class `SimpleDate`. The method returns the value `true` if the date given as the parameter is after (or on the same day as) the date of the object whose method is called. - - ```java public class SimpleDate { @@ -2228,31 +1512,15 @@ public class SimpleDate { } ``` - + Even though the object variables `year`, `month`, and `day` are encapsulated (`private`) object variables, we can read their values by writing `compared.*variableName*`. This is because `private` variable can be accessed from all the methods contained by that class. Notice that the syntax here matches calling some object method. Unlike when calling a method, we refer to a field of an object, so the parentheses that indicate a method call are not written. - -An example of how to use the method: - ```java public static void main(String[] args) { @@ -2272,16 +1540,7 @@ public static void main(String[] args) { } ``` - @@ -2294,26 +1553,11 @@ public static void main(String[] args) { - - -Let's tweak the method olderThan of the Person class so that from here on out, we take use of the comparison functionality that date objects provide. - ```java public class Person { @@ -2332,33 +1576,21 @@ public class Person { } ``` - + Now the concrete comparison of dates is implemented in the class that it logically (based on the class names) belongs to. - + - + In the estate agent's information system, an apartment that is on sale is represented by an object that is instantiated from the following class: - ```java public class Apartment { @@ -2374,32 +1606,25 @@ public class Apartment { } ``` - + Your task is to create a few methods that can be used to compare apartments that are being sold. - +

Comparing sizes

- + Create a method `public boolean largerThan(Apartment compared)` that returns true if the apartment object whose method is called has a larger total area than the apartment object that is being compared. - + An example of how the method should work: - ```java Apartment manhattanStudioApt = new Apartment(1, 16, 5500); @@ -2410,27 +1635,20 @@ System.out.println(manhattanStudioApt.largerThan(atlantaTwoBedroomApt)); / System.out.println(bangorThreeBedroomApt.largerThan(atlantaTwoBedroomApt)); // true ``` - +

Price difference

- + Create a method `public int priceDifference(Apartment compared)` that returns the price difference of the apartment object whose method was called and the apartment object received as the parameter. The price difference is the absolute value of the difference of the prices (price can be calculated by multiplying the price per square by the number of squares). - + An example of how the method should work: - ```java Apartment manhattanStudioApt = new Apartment(1, 16, 5500); @@ -2442,27 +1660,20 @@ System.out.println(bangorThreeBedroomApt.priceDifference(atlantaTwoBedroomApt)); ``` - +

More expensive?

- + Write a method `public boolean moreExpensiveThan(Apartment compared)` that returns true if the apartment object whose method is called is more expensive than the apartment object being compared. - + An example of how the method should work: - ```java Apartment manhattanStudioApt = new Apartment(1, 16, 5500); @@ -2476,27 +1687,15 @@ System.out.println(bangorThreeBedroomApt.moreExpensiveThan(atlantaTwoBedroomApt)
- + ## Comparing the equality of objects (equals) - + While working with strings, we learned that strings must be compared using the `equals` method. This is how it's done. - ```java Scanner scanner = new Scanner(System.in); @@ -2512,44 +1711,15 @@ if (first.equals(second)) { } ``` - - -With primitive variables such as `int`, comparing two variables can be done with two equality signs. This is because the value of a primitive variable is stored directly in the "variable's box". The value of reference variables, in contrast, is an address of the object that is referenced; so the "box" contains a reference to the memory location. Using two equality signs compares the equality of the values stored in the "boxes of the variables" -- with reference variables, such comparisons would examine the equality of the memory references. - -The method `equals` is similar to the method `toString` in the respect that it is available for use even if it has not been defined in the class. The default implementation of this method compares the equality of the references. Let's observe this with the help of the previously written `SimpleDate` class. +With primitive variables such as `int`, comparing two variables can be done with two equality signs. This is because the value of a primitive variable is stored directly in the "variable's box". The value of reference variables, in contrast, is an address of the object that is referenced; so the "box" contains a reference to the memory location. Using two equality signs compares the equality of the values stored in the "boxes of the variables" -- with reference variables, such comparisons would examine the equality of the memory references. - ```java SimpleDate first = new SimpleDate(1, 1, 2000); @@ -2582,14 +1752,7 @@ if (first.equals(fourth)) { } ``` - @@ -2601,77 +1764,22 @@ Variables first and fourth are equal - - -There is a problem with the program above. Even though two dates (first and second) have exactly the same values for object variables, they are different from each other from the point of view of the default `equals` method. - - - - -If we want to be able to compare two objects of our own design with the `equals` method, that method must be defined in the class. The method `equals` is defined as a method that returns a boolean type value -- the return value indicates whether the objects are equal. - - - -The `equals` method is implemented in such a way that it can be used to compare the current object with any other object. The method receives an `Object`-type object as its single parameter -- all objects are `Object`-type, in addition to their own type. The `equals` method first compares if the addresses are equal: if so, the objects are equal. After this, we examine if the types of the objects are the same: if not, the objects are not equal. Next, the `Object`-type object passed as the parameter is converted to the type of the object that is being examined by using a type cast, so that the values of the object variables can be compared. Below the equality comparison has been implemented for the SimpleDate class. +There is a problem with the program above. Even though two dates (first and second) have exactly the same values for object variables, they are different from each other from the point of view of the default `equals` method. - ```java public class SimpleDate { @@ -2730,51 +1838,12 @@ public class SimpleDate { } ``` - - -Building a similar comparison functionality is possible for Person objects too. Below, the comparison has been implemented for Person objects that don't have a separate SimpleDate object. Notice that the names of people are strings (i.e. objects), so we use the `equals` method for comparing them. - - - ```java public class Person { @@ -2818,28 +1887,17 @@ public class Person { ``` - + - + In the exercise base there is a class called `Song` that can be used to create new objects that represent songs. Add to that class the `equals` method so that the similarity of songs can be examined. - ```java Song jackSparrow = new Song("The Lonely Island", "Jack Sparrow", 196); @@ -2854,11 +1912,7 @@ if (jackSparrow.equals("Another object")) { } ``` - @@ -2869,41 +1923,25 @@ Songs are equal - + - -In the exercise base you can find the `Person` class that is linked with an `SimpleDate` object. Add to the class Person the method `public boolean equals (Object compared)`, which can be used to compare the similarity of people. The comparison should take into account the equality of all the variables of a person (birthday included). - +In the exercise base you can find the `Person` class that is linked with an `SimpleDate` object. Add to the class Person the method `public boolean equals (Object compared)`, which can be used to compare the similarity of people. The comparison should take into account the equality of all the variables of a person (birthday included). -**NB!** Recall that you cannot compare two birthday objects with equality signs! - -There are no tests in the exercise template to check the correctess of the solution. Only return your answer after the comparison works as it should. Below is some code to help test the program. +**NB!** Recall that you cannot compare two birthday objects with equality signs! - ```java SimpleDate date = new SimpleDate(24, 3, 2017); @@ -2927,28 +1965,20 @@ if (leo.equals(leoWithDifferentWeight)) { - + - + Every class we create (and every ready-made Java class) inherits the class Object, even though it is not specially visible in the program code. This is why an instance of any class can be passed as a parameter to a method that receives an Object type variable as its parameter. Inheriting the Object can be seen elsewhere, too: for instance, the `toString` method exists even if you have not implemented it yourself, just as the `equals` method does. - + To illustrate, the following source code compiles successfully: `equals` method can be found in the Object class inherited by all classes. - ```java public class Bird { @@ -2961,17 +1991,7 @@ public class Bird { ``` - ```java Bird red = new Bird("Red"); @@ -2987,23 +2007,15 @@ if (red.equals(chuck)) { - + ## Object equality and lists - + Let's examine how the `equals` method is used with lists. Let's assume we have the previously described class `Bird` without any `equals` method. - ```java public class Bird { @@ -3015,37 +2027,11 @@ public class Bird { } ``` - -Let's create a list and add a bird to it. After this we'll check if that bird is contained in it. - - ```java ArrayList birds = new ArrayList<>() @@ -3075,14 +2061,7 @@ if (birds.contains(red)) { } ``` - @@ -3093,58 +2072,20 @@ Red is not on the list. - - -We can notice in the example above that we can search a list for our own objects. First, when the bird had not been added to the list, it is not found -- and after adding it is found. When the program switches the `red` object into a new object, with exactly the same contents as before, it is no longer equal to the object on the list, and therefore cannot be found on the list. - -The `contains` method of a list uses the `equals` method that is defined for the objects in its search for objects. In the example above, the `Bird` class has no definition for that method, so a bird with exactly the same contents -- but a different reference -- cannot be found on the list. - - - -Let's implement the `equals` method for the class `Bird`. The method examines if the names of the objects are equal -- if the names match, the birds are thought to be equal. +We can notice in the example above that we can search a list for our own objects. First, when the bird had not been added to the list, it is not found -- and after adding it is found. When the program switches the `red` object into a new object, with exactly the same contents as before, it is no longer equal to the object on the list, and therefore cannot be found on the list. - ```java public class Bird { @@ -3186,37 +2127,11 @@ public class Bird { } ``` - - -Now the contains list method recognizes birds with identical contents. - - ```java ArrayList birds = new ArrayList<>() @@ -3246,14 +2161,7 @@ if (birds.contains(red)) { } ``` - @@ -3265,43 +2173,24 @@ Red is on the list. - + - + There is a program in the exercise base that asks for books from the user and adds them to a list. - + Modify the program so that books that are already on the list are not added to it again. Two books should be considered the same if they have the same name and publication year. - -Example print - @@ -3327,59 +2216,33 @@ Thank you! Books added: 2 - + - + In this exercise you get to implement a program that can be used to handle an archive. Several items can be added to it. When no more items are added, all the items in the archive are printed. - +

Adding and listing items

- + The program should read items from the user. When all the items from the user have been read, the program prints the information of each item. - + For each item, its identifier and name should be read. If the identifier or name is empty, the program stops asking for input, and prints all the item information. - -Example print: - @@ -3409,53 +2272,29 @@ B07NQFMZYG: He-Man figure - + The printing format of the items should be `identifier: name`. - + NB! Don't print the colon (:) anywhere else in the output of the program. - +

You only print once (per item)

- -Modify the program so that after entering the items, each item is printed at most once. Two items should be considered the same if their identifiers are the same (there can be variation in their names in different countries, for instance). - +Modify the program so that after entering the items, each item is printed at most once. Two items should be considered the same if their identifiers are the same (there can be variation in their names in different countries, for instance). -If the user enters the same item multiple times, the print uses the item that was added first. - @@ -3484,58 +2323,27 @@ B07NQFMZYG: He-Man figure - + Hint! It is probably smart to add each item to the list at most once -- compare the equality of the objects based on their identifiers.
- -## Object as a method's return value - - -We have seen methods return boolean values, numbers, and strings. Easy to guess, a method can return an object of any type. +## Object as a method's return value - -In the next example we present a simple counter that has the method `clone`. The method can be used to create a clone of the counter; i.e. a new counter object that has the same value at the time of its creation as the counter that is being cloned. +We have seen methods return boolean values, numbers, and strings. Easy to guess, a method can return an object of any type. - ```java public Counter { @@ -3570,36 +2378,12 @@ public Counter { } ``` - - -An example of using counters follows: - - - ```java Counter counter = new Counter(); @@ -3627,28 +2411,16 @@ System.out.println(counter); // prints 6 System.out.println(clone); // prints 3 ``` - + Immediately after the cloning operation, the values contained by the clone and the cloned object are the same. However, they are two different objects, so increasing the value of one counter does not affect the value of the other in any way. - + Similarly, a `Factory` object could also be used to create and return new `Car` objects. Below is a sketch of the outline of the factory -- the factory also knows the makes of the cars that are created. - ```java public class Factory { @@ -3665,53 +2437,17 @@ public class Factory { ``` - - - - - -With the exercise base the class `SimpleDate` is supplied. The date is stored with the help of the object variables `year`, `month`, and `day`: + - ```java public class SimpleDate { @@ -3751,51 +2487,43 @@ public class SimpleDate { } ``` - + In this exercise set we will expand this class. - +

Next day

- + Implement the method `public void advance()` that moves the date by one day. In this exercise we assume that each month has 30 day. NB! In *certain* situations you need to change the values of month and year. - +

Advance specific number of days

- + Implement the method `public void advance(int howManyDays)` that moves the date by the number of days that is given. Use the method `advance()` that you implemented in the previous section to help you in this. - +

Passing of time

- + Let's add the possibility to advance time to the `SimpleDate` class. Create the method `public SimpleDate afterNumberOfDays(int days)` for the class. It creates a **new** `SimpleDate` object whose date is the specified number of days greater than the object that the method was called on. You may still assume that each month has 30 days. Notice that the old date object must remain unchanged! - -Since the method must create **a new object**, the structure of the code should be somewhat similar to this: +Since the method must create **a new object**, the structure of the code should be somewhat similar to this: - ```java public SimpleDate afterNumberOfDays(int days) { @@ -3807,29 +2535,11 @@ public SimpleDate afterNumberOfDays(int days) { } ``` - - -Here is an example of how the method works. - - ```java public static void main(String[] args) { @@ -3851,23 +2561,11 @@ public static void main(String[] args) { } ``` - -The program prints: - @@ -3884,19 +2582,12 @@ The date after 790 days from the examined Friday is ... try it out yourself! - + **NB!** Instead of modifying the state of the old object we return a new one. Imagine that the `SimpleDate` class has a method `advance` that works similarly to the method we programmed, but it modifies the state of the old object. In that case the next block of code would cause problems. - ```java SimpleDate now = new SimpleDate(13, 2, 2015); @@ -3907,16 +2598,11 @@ System.out.println("Now: " + now); System.out.println("After one week: " + afterOneWeek); ``` - -The output of the program should be like this: - @@ -3925,52 +2611,24 @@ After one week: 20.2.2015 - + This is because a normal assignment only copies the reference to the object. So the objects `now` and `afterOneWeek` in the program now refer to the **one and same** `SimpleDate` object.
- - - - - -In the Payment card exercise we used a double-type object variable to store the amount of money. In real applications this is not the approach you want to take, since as we have seen, calculating with doubles is not exact. A more reasonable way to handle amounts of money is create an own class for that purpose. Here is a layout for the class: + - ```java public class Money { @@ -4002,36 +2660,29 @@ public class Money { } ``` - + The word `final` used in the definition of object variables catches attention. The result of this word is that the values of these object variables cannot be modified after they have been set in the constructor. The objects of Money class are unchangeable so **immutable** -- if we want to e.g. increase the amount of money, we must create a new object to represent that new amount of money. - + Next we'll create a few operations for processing money. - +

Plus

- + First create the method `public Money plus(Money addition)` that returns a new money object that is worth the total amount of the object whose method was called and the object that is received as the parameter. - + The basis for the method is the following: - ```java public Money plus(Money addition) { @@ -4042,28 +2693,12 @@ public Money plus(Money addition) { } ``` - - -Here are some examples of how the method works. - - ```java Money a = new Money(10,0); @@ -4084,23 +2719,16 @@ System.out.println(c); // 15.00e ``` - +

Less

- + Create the method `public boolean lessThan(Money compared)` that returns true if the money-object on which the method is called on has a lesser value than the money object given as a parameter. - ```java Money a = new Money(10, 0); @@ -4112,36 +2740,20 @@ System.out.println(b.lessThan(c)); // true ``` - +

Minus

- -Write the method `public Money minus(Money decreaser)` that returns a new money object worth the difference of the object whose method was called and the object received as the parameter. If the difference would be negative, the worth of the created money object is set to 0. - - -Here are examples of how the method works. +Write the method `public Money minus(Money decreaser)` that returns a new money object worth the difference of the object whose method was called and the object received as the parameter. If the difference would be negative, the worth of the created money object is set to 0. - ```java Money a = new Money(10, 0); diff --git a/data/part-5/5-conclusion.md b/data/part-5/5-conclusion.md index 579405a4d..989ef83d6 100644 --- a/data/part-5/5-conclusion.md +++ b/data/part-5/5-conclusion.md @@ -4,15 +4,15 @@ title: 'Conclusion' hidden: false --- - - + + In the fifth part we took a deep dive into the world of objects. We examined the differences between primitive and reference variables. We learned to overload methods and constructors, and we practiced using objects as object variables, method parameters, and method return values. We created methods that compare objects with each other, and we saw how objects are handled with objects in them. - - + + Please take a moment to answer the questionnaire below. diff --git a/data/part-5/index.md b/data/part-5/index.md index 221e9b316..9c06222bb 100644 --- a/data/part-5/index.md +++ b/data/part-5/index.md @@ -6,7 +6,7 @@ overview: true hidden: false --- - + The fifth part of the course material continues with object-oriented programming, which was introduced in the fourth part. @@ -14,7 +14,7 @@ The fifth part of the course material continues with object-oriented programming - + The table of contents above lists the topics of the fifth part of the course. The fifth part has been designed to cover the fifth week of the course. You should reserve well above 10 hours for each part of the course, depending on previous experience with computers. If you've tried programming before, you might advance faster in the beginning. diff --git a/data/part-6/1-objects-within-objects.md b/data/part-6/1-objects-within-objects.md index 1be954b30..07822f85b 100644 --- a/data/part-6/1-objects-within-objects.md +++ b/data/part-6/1-objects-within-objects.md @@ -4,52 +4,24 @@ title: 'Objects on a list and a list as part of an object' hidden: false --- - + - + - You review the use of lists. - You know how to use a list as an instance variable. - Next, let's have a look at objects that contain a list. Examples of objects like these include objects that describe sets, for example playlists. In the following example, we have made a class for the concept of a playlist. The playlist contains songs: songs can be added, songs can be removed, and the songs that the playlist contains can be printed. - ```java // imports @@ -77,16 +49,11 @@ public class Playlist { } ``` - + Creating playlists is easy with the help of the class above. - + ```java Playlist list = new Playlist(); @@ -102,31 +69,16 @@ Teuvo, maanteiden kuningas - + - The gourmet restaurant 'Unicafe' on the Kumpula campus of the University of Helsinki needs a new menu. The chef knows about programming and wants a computer system to manage the menu. In this assignment, we'll implement the heart of the system, the Menu class. The exercise template comes with a `Main` class that you can use to test the menu. For the implementation of the menu, you'll have the following boilerplate code: - ```java import java.util.ArrayList; @@ -143,15 +95,7 @@ public class Menu { } ``` - The menu object has an ArrayList as an instance variable to store the names of the dishes on the menu. The menu should provide the following methods: @@ -163,20 +107,7 @@ The menu object has an ArrayList as an instance variable to store the names of t Once the menu is done, you can use it as follows. - ```java Menu menu = new Menu(); @@ -203,13 +134,7 @@ Tomato and mozzarella salad -

Adding a Meal

Implement the `public void addMeal(String meal)` method, which adds a new meal to the `meals` list. If the meal you want to add is already on the list, you shouldn't add it again. The list method `contains` is handy for checking an items existence on it. @@ -218,15 +143,7 @@ Implement the `public void addMeal(String meal)` method, which adds a new meal t Implement the `public void printMeals()` method, which prints the meals. You can test out the program using the following example code. - ```java Menu menu = new Menu(); @@ -240,9 +157,7 @@ menu.printMeals(); - + Tofu ratatouille Chilli Coconut Chicken @@ -250,31 +165,14 @@ Meatballs with mustard sauce -

Clearing the Food List

Implement the `public void clearMenu()` method, which clears the menu. The `ArrayList` class has a method which is useful here. NetBeans can hint at the available methods when you type the object name an a dot. Try to write `meals.` inside the method frame and see what happens. Once the menu is ready, try it with the following example code. - ```java Menu menu = new Menu(); @@ -293,11 +191,7 @@ menu.printMeals(); - Tofu ratatouille Chilli Coconut Chicken @@ -309,22 +203,10 @@ Tomato and mozzarella salad
- - - A stack is a data structure that you can add to and take from. Always to the top of it or from the top. @@ -340,14 +222,7 @@ Create a `Stack` class that has a list of strings as an instance variable. Add t You can test your class with the following code: - + ```java Stack s = new Stack(); @@ -360,10 +235,7 @@ System.out.println(s.values()); - + true [] @@ -372,25 +244,12 @@ false -

Taking from the Stack

Add to the `Stack` class a `public String take()` method, which returns the topmost value (i.e., the last value added to the deque) and removes it from the stack. - + ```java Stack s = new Stack(); @@ -407,13 +266,7 @@ System.out.println(taken); - + true [] @@ -425,18 +278,7 @@ Value - ```java Stack s = new Stack(); @@ -461,51 +303,23 @@ while (!s.isEmpty()) { - + Tip! When a value is added to an ArrayList, it goes to the end of the list. As such, the most recently added value is in the last index of the list - the `length` method provided by the list is useful for finding the last index. You can remove an element from a particular index using the `remove` method provided by the list.
- + ## Objects in an Instance Variable List - A list that is an object's instance variable can contain objects other than strings as long as the type of objects in the list is specified when defining the list. In the previous section, we created a class called `AmusementParkRide`, which was used to check whether or not a person was eligible to get on a particular ride. The `Amusement park` class looks like the following. - ```java public class AmusementParkRide { @@ -535,27 +349,11 @@ public class AmusementParkRide { } ``` - + We'll extend the class so that the amusement park keeps track of the people on the ride. In this version, the ride has, as an instance variable, a list of the people who have been allowed on the ride. The list is created in the constructor. - ```java public class AmusementParkRide { @@ -575,40 +373,11 @@ public class AmusementParkRide { } ``` - - -Let's change the method `isAllowedOn`. The method adds to the list all the persons who meet the height requirements. - ```java public class AmusementParkRide { @@ -641,18 +410,10 @@ public class AmusementParkRide { } ``` - - - - The exercise template comes with a pre-defined `Message` class that can be used to create objects representing messages. Each message has a sender and some content. @@ -666,38 +427,15 @@ Tip! You can find out the length of the string using the `length()` method assoc - + ### Printing an Object from a List - -Let's now modify the `toString` method so that the string returned by the method contains the name of each and every person on the ride. - ```java public class AmusementParkRide { @@ -724,38 +462,11 @@ public class AmusementParkRide { } ``` - - -Let's test out the extended amusement park ride: - - ```java Person matti = new Person("Matti"); @@ -786,22 +497,11 @@ if (hurjakuru.isAllowedOn(juhana)) { System.out.println(hurjakuru); ``` - - -The program's output is: - @@ -816,47 +516,11 @@ Matti - -Even though there is no one on the ride, the string `riding:` is on the print output. Let's modify the `toString` method so that if there is no one on the ride, the string returned by the method informs of it. - - ```java public class AmusementParkRide { @@ -896,38 +560,11 @@ public class AmusementParkRide { } ``` - - -The print output has now been improved. - - ```java Person matti = new Person("Matti"); @@ -958,22 +595,11 @@ if (hurjakuru.isAllowedOn(juhana)) { System.out.println(hurjakuru); ``` - - -The program's output is: - @@ -989,36 +615,16 @@ Matti - + - The exercise template has a predefined `SimpleCollection` class, which is used to represent a group of values. The class is missing the `toString` method used for printing. Implement a `toString` method for the class that will perform as demonstrated in the following examples. - ```java SimpleCollection s = new SimpleCollection("alphabet"); @@ -1042,19 +648,7 @@ System.out.println(s); - The collection alphabet is empty. @@ -1072,25 +666,7 @@ c - ```java SimpleCollection s = new SimpleCollection("characters"); @@ -1114,19 +690,7 @@ System.out.println(s); - The collection characters is empty. @@ -1146,25 +710,15 @@ phoenix - + ### Clearing an Object's List - -We'll next add a `removeEveryoneOnRide` method to the amusement park ride, which removes each and every person currently on the ride.The list method `clear` is very handy here. - ```java public class AmusementParkRIde { @@ -1178,39 +732,7 @@ public class AmusementParkRIde { } ``` - ```java Person matti = new Person("Matti"); @@ -1246,23 +768,13 @@ System.out.println(); System.out.println(hurjakuru); ``` - + The program's output is: - Hurjakuru, minimum height requirement: 140, visitors: 0 no one is on the ride. @@ -1278,43 +790,17 @@ no one is on the ride. - + ### Calculating a Sum from Objects on a List - Let's now create a method for the amusement park ride that calculates the average height of the people currently on it. Average height can obtained by calculating the average from the persons on the ride -- the average is calculated by adding up the individual values and dividing that sum by the number of values. The implementation underneath returns `-1` if not a single person is on the ride. The result of `-1` is impossible in a program that calculates averages. Based on that, we can determine that the average could not have been calculated. - ```java public class AmusementParkRide { @@ -1342,25 +828,7 @@ public class AmusementParkRide { } ``` - ```java Person matti = new Person("Matti"); @@ -1382,17 +850,13 @@ System.out.println(hurjakuru); System.out.println(hurjakuru.averageHeightOfPeopleOnRide()); ``` - + The program's output is: - + Hurjakuru, minimum height requirement: 140, visitors: 2 on the ride: @@ -1402,29 +866,17 @@ Awak - - - - - -We'll practise wrapping gifts in this exercise. Let's create the classes `Gift` and `Package`. The gift has a name and weight, and the package contains gifts. - -

Gift-class

+ - Create a `Gift` class, where the objects instantiated from it represent different kinds of gifts. The information that's recorded is the name and weight of the item (kg). @@ -1440,17 +892,7 @@ Add the following methods to the class: The following is an example of the class in use: - ```java public class Main { @@ -1465,15 +907,13 @@ public class Main { } ``` - + The program's print output should be as follows: - + Gift's name: Harry Potter and the Philosopher's Stone Gift's weight: 2 @@ -1481,18 +921,10 @@ Gift: Harry Potter and the Philosopher's Stone (2 kg) - -

Package-class

- - Create a `Package` class to which gifts can be added, and that keeps track of the total weight of the gifts in the package. The class should contain: @@ -1504,29 +936,17 @@ Create a `Package` class to which gifts can be added, and that keeps track of th It's recommended to store the items in an `ArrayList` object. - + ```java ArrayList gifts = new ArrayList<>(); ``` - + An example use case of the class is as follows: - ```java public class Main { @@ -1540,7 +960,7 @@ public class Main { } ``` - + The program's output should be the following: @@ -1552,47 +972,17 @@ The program's output should be the following:
- + ### Retrieving a Specific Object from a List - We'll now create a method for the amusement park ride that returns the tallest person on the ride. As such, the method should both retrieve the tallest person from the list and return it. Methods that retrieve objects from a list should be implemented in the following way. First off, we'll check whether or not the list is empty - if it is, we return a `null` reference or some other value indicating that the list had no values. After that, we create an object reference variable that describes the object to be returned. We set the first object on the list as its value. We then go through the values on the list by comparing each list object with the object variable representing the object to be returned. If the comparison finds a better matching object, its assigned to the object reference variable to be returned. Finally, we return the object variable describing the object that we want to return. - ```java public Person getTallest() { @@ -1624,34 +1014,11 @@ public Person getTallest() { } ``` - - -Finding the tallest person is now easy. - - ```java @@ -1682,11 +1049,7 @@ System.out.println(tallest.getName()); - + Hurjakuru, minimum height requirement: 140, visitors: 2 on the ride: @@ -1699,23 +1062,14 @@ Awak - + - -The exercise template comes with the class `SimpleCollection` that's familiar from previous exercises. Implement the method `public String longest()` for the class, which returns the longest string of the collection. If the collection is empty, the method should return a `null` reference. - ```java SimpleCollection j = new SimpleCollection("characters"); @@ -1730,8 +1084,7 @@ System.out.println("Longest: " + j.longest()); - + Longest: null Longest: mystique @@ -1740,27 +1093,19 @@ Longest: mystique - + - A `Person` class is included in the exercise template. A person has a name and a height. In this exercise, we'll implement a `Room` class, which can be used to add people and order them according to their height -- taking a person out of the room always returns the shortest person. The class should eventually work in the following way. - -

Room

- - Create `Room` class. The class should contain a list of persons as an instance variable, and it should have a parameterless constructor. In addition, add the following methods to the class: @@ -1770,21 +1115,7 @@ Create `Room` class. The class should contain a list of persons as an instance v - `public ArrayList getPersons()` - returns a list of the persons in the room. - ```java Room room = new Room(); @@ -1802,18 +1133,7 @@ for (Person person : room.getPersons()) { } ``` - @@ -1828,37 +1148,15 @@ Terhi (185 cm) - +

Shortest person

- + Add a `public Person shortest()` method to the `Room` class, which returns the shortest person added to the room. If the room is empty, a null reference is returned. The method should not remove a person from the room. - ```java Room room = new Room(); @@ -1884,27 +1182,7 @@ for (Person person : room.getPersons()) { } ``` - @@ -1928,34 +1206,15 @@ Terhi (185 cm) - +

Taking from a room

- -Add a `public Person take()` method to the `Room` class, which takes the shortest person in the room. When a room is empty, it returns a `null` reference. - ```java Room room = new Room(); @@ -1978,22 +1237,7 @@ for (Person person : room.getPersons()) { } ``` - @@ -2012,22 +1256,11 @@ Terhi (185 cm) - + It's now possible to print the persons in height order. - ```java Room room = new Room(); @@ -2054,29 +1287,17 @@ Auli (186 cm)
- - - - - -In this exercise, we create the classes `Item`, `Suitcase` and `Hold` to practise the use of objects containing other objects. - -

Item-class

+ - Create an `Item` class from which objects can be instantiated to represent different items. The information to store is the name and weight of the item (kg). @@ -2092,20 +1313,7 @@ Add the following methods to the class: The following is an example of the class in use: - ```java public class Main { @@ -2122,18 +1330,11 @@ public class Main { } ``` - -The program's print output should be the following: - @@ -2144,20 +1345,10 @@ Phone: Nokia 3210 (1 kg) - -

Suitcase-class

- - Create a `Suitcase` class. The suitcase has items and a maximum weight that determines the maximum total weight of the items. @@ -2171,43 +1362,19 @@ Add the following methods to the class: It's advisable to store the items in an `ArrayList` object: - + ```java ArrayList items = new ArrayList<>(); ``` - The class `Suitcase` should ensure that the total weight of the items within it does not exceed the maximum weight limit. If that limit would be exceeded as a result of the item to be added, the method `addItem` should not add the new item to the suitcase. The following is an example use case of the class: - ```java public class Main { @@ -2231,18 +1398,11 @@ public class Main { } ``` - -The program's output should be the following: - 0 items (0 kg) @@ -2252,25 +1412,16 @@ The program's output should be the following: - +

Language Formatting

- The statement "1 items" is not exactly proper English -- a better form would be "1 item". The lack of items could also be expressed as "no items". Implement this change to the toString method of the `Suitcase` class. The output of the previous program should now look as follows: - no items (0 kg) @@ -2280,16 +1431,10 @@ no items (0 kg) - -

All items

- Add the following methods to the `Suitcase` class: @@ -2297,28 +1442,11 @@ Add the following methods to the `Suitcase` class: - a `totalWeight` method, which returns the total weight of the items - + The following is an example use case of the class: - + ```java public class Main { @@ -2339,19 +1467,11 @@ public class Main { } ``` - -The program's output should be the following: - The suitcase contains the following items: @@ -2362,39 +1482,21 @@ Total Weight: 7 kg - + Make a further modification to your class so that you only use two instance variables. One holds the maximum weight, the other is the list of items in the suitcase. - +

Heaviest item

- Add to the `Suitcase` class a `heaviestItem` method, which returns the largest item based on weight. If several items share the heaviest weight, the method can return any one of them. The method should return an object reference. If the suitcase is empty, return the value *null*. The following is an example of the class in use: - ```java public class Main { @@ -2414,37 +1516,21 @@ public class Main { } ``` - -The program should print the following: - Heaviest item: Brick (4 kg) - -

Hold-class

- - Make a `Hold` class with the following methods: @@ -2460,28 +1546,7 @@ The class `Hold` has to ensure that the total weight of the suitcases it contain The following is an example of the class in use: - ```java public class Main { @@ -2506,55 +1571,27 @@ public class Main { } ``` - -The program's output should be the following: - 2 suitcases (7 kg) - +

The Hold's Contents

- Add to the `Hold` class the method `public void printItems()` that prints all the items contained in the hold's suitcases. The following is an example of the class in use: - ```java public class Main { @@ -2580,18 +1617,11 @@ public class Main { } ``` - -The program's output should be as follows: - The suitcases in the hold contain the following items: diff --git a/data/part-6/2-separating-user-interface-from-program-logic.md b/data/part-6/2-separating-user-interface-from-program-logic.md index 27af2ad81..1aa134a38 100644 --- a/data/part-6/2-separating-user-interface-from-program-logic.md +++ b/data/part-6/2-separating-user-interface-from-program-logic.md @@ -6,8 +6,8 @@ hidden: false - - + + - Understand creating programs so that the user interface and the application logic are separated @@ -16,7 +16,7 @@ hidden: false - + Let's examine the process of implementing a program and separating different areas of responsibility from each other. The program asks the user to write words until they write the same word twice. @@ -32,28 +32,16 @@ You wrote the same word twice! - + Let's build this program piece by piece. One of the challenges is that it is difficult to decide how to approach the problem, or how to split the problem into smaller subproblems, and from which subproblem to start. There is no one clear answer -- sometimes it is good to start from the problem domain and its concepts and their connections, sometimes it is better to start from the user interface. - -We could start implementing the user interface by creating a class UserInterface. The user interface uses a Scanner object for reading user input. This object is given to the user interface. - ```java public class UserInterface { @@ -69,17 +57,11 @@ public class UserInterface { } ``` - + Creating and starting up a user interface can be done as follows. - + ```java public static void main(String[] args) { Scanner scanner = new Scanner(System.in); @@ -88,39 +70,16 @@ public static void main(String[] args) { } ``` - -## Looping and quitting +## Looping and quitting - - -This program has (at least) two "sub-problems". The first problem is continuously reading words from the user until a certain condition is reached. We can outline this as follows. - - ```java public class UserInterface { @@ -147,40 +106,11 @@ public class UserInterface { } ``` - -The program continues to ask for words until the user enters a word that has already been entered before. Let us modify the program so that it checks whether the word has been entered or not. We don't know how to implement this functionality yet, so let us first build an outline for it. - - ```java public class UserInterface { @@ -213,19 +143,11 @@ public class UserInterface { } ``` - + It's a good idea to test the program continuously, so let's make a test version of the method: - ```java public boolean alreadyEntered(String word) { @@ -237,20 +159,11 @@ public boolean alreadyEntered(String word) { } ``` - -Now the loop continues until the input equals the word "end": - @@ -262,31 +175,19 @@ You gave the same word twice! - + The program doesn't completely work yet, but the first sub-problem - quitting the loop when a certain condition has been reached - has now been implemented. - + ## Storing relevant information - -Another sub-problem is remembering the words that have already been entered. A list is a good structure for this purpose. - ```java public class UserInterface { @@ -302,24 +203,11 @@ public class UserInterface { } ``` - -When a new word is entered, it has to be added to the list of words that have been entered before. This is done by adding a line that updates our list to the while-loop: - ```java while (true) { @@ -335,46 +223,10 @@ while (true) { } ``` - -The whole user interface looks as follows. - - ```java public class UserInterface { @@ -414,16 +266,11 @@ public class UserInterface { } ``` - + Again, it is a good idea to test that the program still works. For example, it might be useful to add a test print to the end of the start-method to make sure that the entered words have really been added to the list. - + ```java // test print to check that everything still works @@ -432,19 +279,15 @@ for (String word: this.words) { } ``` - + ## Combining the solutions to sub-problems - + Let's change the method 'alreadyEntered' so that it checks whether the entered word is contained in our list of words that have been already entered. - + ```java public boolean alreadyEntered(String word) { @@ -452,29 +295,20 @@ public boolean alreadyEntered(String word) { } ``` - + Now the application works as intended. - + ## Objects as a natural part of problem solving - -We just built a solution to a problem where the program reads words from a user until the user enters a word that has already been entered before. Our example input was as follows: +We just built a solution to a problem where the program reads words from a user until the user enters a word that has already been entered before. Our example input was as follows: - @@ -487,43 +321,12 @@ You gave the same word twice! - - -We came up with the following solution: - ```java public class UserInterface { @@ -563,31 +366,19 @@ public class UserInterface { } ``` - + From the point of view of the user interface, the support variable 'words' is just a detail. The main thing is that the user interface remembers the *set of words* that have been entered before. The set is a clear distinct "concept" or an abstraction. Distinct concepts like this are all potential objects: when we notice that we have an abstraction like this in our code, we can think about separating the concept into a class of its own. - -### Word set - +### Word set - Let's make a class called 'WordSet'. After implementing the class, the user interface's start method looks like this: - ```java while (true) { @@ -603,11 +394,7 @@ while (true) { System.out.println("You gave the same word twice!"); ``` - From the point of view of the user interface, the class WordSet should contain the method 'boolean contains(String word)', that checks whether the given word is contained in our set of words, and the method 'void add(String word)', that adds the given word into the set. @@ -615,24 +402,7 @@ We notice that the readability of the user interface is greatly improved when it The outline for the class 'WordSet' looks like this: - ```java public class WordSet { @@ -653,35 +423,17 @@ public class WordSet { } ``` - - -### Earlier solution as part of implementation - +### Earlier solution as part of implementation -We can implement the set of words by making our earlier solution, the list, into an object variable: - ```java import java.util.ArrayList; @@ -703,41 +455,13 @@ public class WordSet { } ``` - Now our solution is quite elegant. We have separated a distinct concept into a class of its own, and our user interface looks clean. All the "dirty details" have been encapsulated neatly inside an object. Let's now edit the user interface so that it uses the class WordSet. The class is given to the user interface as a parameter, just like Scanner. - ```java public class UserInterface { @@ -767,20 +491,12 @@ public class UserInterface { } ``` - + Starting the program is now done as follows: - ```java public static void main(String[] args) { @@ -792,47 +508,30 @@ public static void main(String[] args) { } ``` - + ## Changing the implementation of a class - + We have arrived at a situation where the class 'WordSet' "encapsulates" an ArrayList. Is this reasonable? Perhaps. This is because we can make other changes to the class if we so desire, and before long we might arrive at a situation where the word set has to be, for example, saved into a file. If we make all these changes inside the class WordSet without changing the names of the methods that the user interface uses, we don't have to modify the actual user interface at all. - + The main point here is that changes made inside the class WordSet don't affect the class UserInterface. This is because the user interface uses WordSet through the methods that it provides -- these are called its public interfaces. - -## Implementing new functionality: palindromes +## Implementing new functionality: palindromes - - -In the future, we might want to augment the program so that the class 'WordSet' offers some new functionalities. If, for example, we wanted to know how many of the entered words were palindromes, we could add a method called 'palindromes' into the program. - ```java public void start() { @@ -853,58 +552,11 @@ public void start() { } ``` - - -The user interface remains clean, because counting the palindromes is done inside the 'WordSet' object. The following is an example implementation of the method. - - ```java import java.util.ArrayList; @@ -955,15 +607,11 @@ public class WordSet { } ``` - -The method 'palindromes' uses the helper method 'isPalindrome' to check whether the word that's given to it as a parameter is, in fact, a palindrome. - @@ -971,31 +619,16 @@ When concepts have been separated into different classes in the code, recycling - - -## Programming tips - +## Programming tips -In the larger example above, we were following the advice given here. - - Proceed with small steps - Try to separate the program into several sub-problems and **work on only one sub-problem at a time** @@ -1012,26 +645,18 @@ In the larger example above, we were following the advice given here. - If needed, take a step back and assess the program as a whole. If it doesn't work, it might be a good idea to return into a previous state where the code still worked. As a corollary, we might say that a program that's broken is rarely fixed by adding more code to it. - + Programmers follow these conventions so that programming can be made easier. Following them also makes it easier to read programs, to keep them up, and to edit them in teams. - + The exercise base contains a class `SimpleDictionary` that allows for storing words and their translations. The internal implementation of the class contains some techniques not (yet) covered on the course. Nevertheless, it's fairly simple to use it: - ```java SimpleDictionary book = new SimpleDictionary(); @@ -1052,39 +677,33 @@ null - + In this exercise you will implement a text user interface that takes use of the `SimpleDictionary` class. And maybe pick up a few Finnish words while doing it! - +

Starting and stopping the UI

- + Implement the class `TextUI` that receives as constructor parameters a `Scanner` and `SimpleDictionary` objects. Then give the class a method called `public void start()`. The method should work as follows: - + 1. The method asks the user for a command - + 2. If the command is `end`, the UI prints the string "Bye bye!" and the execution of the `start` method ends. - + 3. Otherwise the text UI prints the message `Unknown command` and asks for a new command, so it loops back to step 1. - ```java Scanner scanner = new Scanner(System.in); @@ -1094,16 +713,7 @@ TextUI ui = new TextUI(scanner, dictionary); ui.start(); ``` - @@ -1117,44 +727,32 @@ Bye bye! - +

Adding a translation

- + Modify the method `public void start()` so that it works in the following way: - + 1. The method asks the user for a command. - + 2. If the command is `end`, the UI prints the string "Bye bye!" and the execution of the `start` method ends. - + 3. If the command is `add`, the text UI asks the user for a word and a translation, each on its own line. After this the words are stored in the dictionary, and the method continues by asking for a new command (loops back to stage 1). - -4. Otherwise the text UI prints the message `Unknown command` and asks for a new command, so it loops back to step 1. - @@ -1170,18 +768,11 @@ Bye bye! - + In the example above, we added the word "pike" and its translation "hauki" to the SimpleDictionary object. After exiting the text user interface the dictionary could be used in the following manner: - ```java Scanner scanner = new Scanner(System.in); @@ -1192,53 +783,35 @@ textUI.start(); System.out.println(dictionary.translate("pike")); // prints the string "hauki" ``` - +

Translating a word

- + Modify the method `public void start()` so that it works in the following: - + 1. The method asks the user for a command. - + 2. If the command is `end`, the UI prints the string "Bye bye!" and the execution of the `start` method ends. - + 3. If the command is `add`, the text UI asks the user for a word and a translation, each on its own line. After this the words are stored in the dictionary, and the method continues by asking for a new command (loops back to stage 1). - + 4. If the command is `search`, the text UI asks the user for the word to be translated. After this it prints the translation of the word, and the method continues by asking for a new command (loops back to stage 1). - + 5. Otherwise the text UI prints the message `Unknown command` and asks for a new command, so it loops back to step 1. - + @@ -1261,33 +834,15 @@ Bye bye! - +

Cleaning up the translation

- + Modify the searching functionality of the UI so that if the word isn't found (i.e. the dictionary returns `null`), the UI prints the message "Word (searched word) was not found". - + @@ -1314,32 +869,11 @@ Bye bye! - + In this exercise we are going to create a program that can be used to create and modify a to-do list. The final product will work in the following manner. - + Command: **add** @@ -1363,19 +897,15 @@ Command: **stop** - + We will build the program in parts. - +

TodoList

- Create a class called `TodoList`. It should have a constructor without parameters and the following methods: @@ -1383,18 +913,7 @@ Create a class called `TodoList`. It should have a constructor without parameter - `public void print()` - prints the exercises. Each task has a number associated with it on the print statement -- use the task's index here (+1). - `public void remove(int number)` - removes the task associated with the given number; the number is the one seen associated with the task in the print. - ```java TodoList list = new TodoList(); @@ -1409,16 +928,7 @@ System.out.println(); list.print(); ``` - 1: read the course material @@ -1430,28 +940,15 @@ list.print(); - + **NB!** You may assume that the `remove` method is given a number that corresponds to a real task. The method only has to correctly work once after each print call. - + Another example: - + ```java TodoList list = new TodoList(); @@ -1468,19 +965,7 @@ list.remove(1); list.print(); ``` - 1: read the course material @@ -1495,18 +980,11 @@ list.print(); - -

User interface

- Next, implement a class called `UserInterface`. It should have a constructor with two parameters. The first parameter is an instance of the class `TodoList`, and the second is an instance of the class `Scanner`. In addition to the constructor, the class should have the method `public void start()` that is used to start the text user interface. The text UI works with an eternal looping statement (`while-true`), and it must offer the following commands to the user: @@ -1520,29 +998,7 @@ Next, implement a class called `UserInterface`. It should have a constructor wit Below is an example of how the program should work. - + @@ -1568,47 +1024,22 @@ Command: **stop** - + NB! The user interface is to use the TodoList and Scanner that are passed as parameters to the constructor.
- + ## From one entity to many parts - -Let's examine a program that asks the user to enter exam points and turns them into grades. Finally, the program prints the distribution of the grades as stars. The program stops reading inputs when the user inputs an empty string. An example program looks as follows: - @@ -1637,75 +1068,11 @@ Points: - - -As almost all programs, this program can be written into main as one entity. Here is one possibility. - - ```java import java.util.ArrayList; @@ -1773,71 +1140,24 @@ public class Program { } ``` - -Let's separate the program into smaller chunks. This can be done by identifying several discrete areas of responsibility within the program. Keeping track of grades, including converting scores into grades, could be done inside a different class. In addition, we could create a new class for the user interface. - - -### Program logic - - - +Let's separate the program into smaller chunks. This can be done by identifying several discrete areas of responsibility within the program. Keeping track of grades, including converting scores into grades, could be done inside a different class. In addition, we could create a new class for the user interface. -Program logic includes parts that are crucial for the execution of the program, like functionalities that store information. From the previous example, we can separate the parts that store grade information. From these we can make a class called 'GradeRegister', which is responsible for keeping track of the numbers of different grades students have received. In the register, we can add grades according to scores. In addition, we can use the register to ask how many people have received a certain grade. - -An example class follows. +### Program logic - ```java import java.util.ArrayList; @@ -1887,53 +1207,11 @@ public class GradeRegister { } ``` - - -When the grade register has been separated into a class, we can remove the functionality associated with it from our main program. The main program now looks like this. - ```java import java.util.Scanner; @@ -1979,19 +1257,11 @@ public class Program { } ``` - + Separating the program logic is a major benefit for the maintenance of the program. Since the program logic -- in this case the GradeRegister -- is its own class, it can also be tested separately from the other parts of the program. If you wanted to, you could copy the class `GradeRegister` and use it in your other programs. Below is an example of simple manual testing -- this experiment only concerns itself with a small part of the register's functionality. - ```java GradeRegister register = new GradeRegister(); @@ -2003,33 +1273,19 @@ System.out.println("Number of students with grade 0 (should be 1): " + register. System.out.println("Number of students with grade 0 (should be 2): " + register.numberOfGrades(2); ``` - + ### User interface - -Typically each program has its own user interface. We will create the class `UserInterface` and separate it from the main program. The user interface receives two parameters in its constructor: a grade register for storing the grades, and a Scanner object used for reading input. - +Typically each program has its own user interface. We will create the class `UserInterface` and separate it from the main program. The user interface receives two parameters in its constructor: a grade register for storing the grades, and a Scanner object used for reading input. -When we now have a separate user interface at our disposal, the main program that initializes the whole program becomes very clear. - ```java import java.util.Scanner; @@ -2047,36 +1303,11 @@ public class Program { } ``` - - -Let's have a look at how the user interface is implemented. There are two essential parts to the UI: reading the points, and printing the grade distribution. - - ```java import java.util.Scanner; @@ -2105,68 +1336,11 @@ public class UserInterface { } ``` - - -We can copy the code for reading exam points and printing grade distribution nearly as is from the previous main program. In the program below, parts of the code have indeed been copied from the earlier main program, and new method for printing stars has also been created -- this clarifies the method that is used for printing the grade distribution. - - ```java import java.util.Scanner; @@ -2230,32 +1404,24 @@ public class UserInterface { - + The exercise base includes the previously constructed program to store grades. In this exercise you will further develop the class `GradeRegister` so that it can calculate the average of grades and exam results. - +

Average grade

- + Create the method `public double averageOfGrades()` for the class `GradeRegister`. It should return the average of the grades. If the register contains no grades, the method should return `-1`. Use the `grades` list to calculate the average. - + Example: - ```java GradeRegister register = new GradeRegister(); @@ -2275,24 +1441,17 @@ System.out.println(register.averageOfGrades()); - +

Average points

- + Give the class `GradeRegister` a new object variable: a list where you will store the exam points every time that the method `addGradeBasedOnPoints` is called. After this addition, create a method `public double averageOfPoints()` that calculates and returns the average of the exam points. If there are no points added to the register, the method should return the number `-1`. Example: - ```java GradeRegister register = new GradeRegister(); @@ -2310,35 +1469,15 @@ System.out.println(register.averageOfPoints());
- +

Prints in the user interface

- + As a final step, add the methods implemented above as parts of the user interface. When the program prints the grade distribution, it should also print the averages of the points and the grades. - @@ -2364,55 +1503,15 @@ The average of grades: 2.4285714285714284
- - - - -The exercise base contains the following program that has been written "in the main". - - - ```java Scanner scanner = new Scanner(System.in); @@ -2456,21 +1555,15 @@ while (true) { } ``` - + The application is in practice a storage for jokes. You can add jokes, get a randomized joke, and the stored jokes can be printed. In this exercise the program is divided into parts in a guided manner. - -

Joke manager

- Create a class called `JokeManager` and move the functionality to manage jokes in it. The class must have a parameter-free constructor, and the following methods: @@ -2480,20 +1573,7 @@ Create a class called `JokeManager` and move the functionality to manage jokes i An example of how to use the class: - ```java JokeManager manager = new JokeManager(); @@ -2510,24 +1590,11 @@ System.out.println("Printing jokes:"); manager.printJokes(); ``` - - -Below is a possible output of the program. Notice that the jokes will probably not be drawn as in this example. - Drawing jokes: @@ -2543,20 +1610,11 @@ What is blue and smells of red paint? - Blue paint. - -

User interface

- - Create a class called `UserInterface` and move the UI functionality of the program there. The class must have a constructor with two parameters. The first parameter is an instance of the JokeManager class, and the second parameter is an instance of the Scanner class. In addition, the class should have the method `public void start()` that can be used to start the user interface. @@ -2569,13 +1627,7 @@ The user interface should provide the user with the following commands: An example of how to use the UI: - ```java JokeManager manager = new JokeManager(); @@ -2585,32 +1637,7 @@ UserInterface interface = new UserInterface(manager, scanner); interface.start(); ``` - diff --git a/data/part-6/3-introduction-to-testing.md b/data/part-6/3-introduction-to-testing.md index 9155cf5b7..48dd6b088 100644 --- a/data/part-6/3-introduction-to-testing.md +++ b/data/part-6/3-introduction-to-testing.md @@ -4,13 +4,10 @@ title: 'Introduction to testing' hidden: false --- - + - + - Can tell about some issues caused by software bugs. - You know what a stack trace is, the steps taken in troubleshooting, and can give textual test inputs to a Scanner. @@ -19,88 +16,73 @@ hidden: false - + Let's take our first steps in the world of program testing. - + ## Error Situations and Step-By-Step Problem Resolving - Errors end up in the programs that we write. Sometimes the errors are not serious and cause headache mostly to users of the program. Occasionally, however, mistakes can lead to very serious consequences. In any case, it's certain that a person learning to program makes many mistakes. You should never be afraid of or avoid making mistakes since that is the best way to learn. For this reason, try to break the program that you're working on from time to time to investigate error messages, and to see if those messages tell you something about the error(s) you've made. - + - + The report in the address http://sunnyday.mit.edu/accidents/MCO_report.pdf describes an incident resulting from a more serious software error and also the error itself.
- + The bug in the software was caused by the fact that the program in question expected the programmer to use the International System of Units (meters, kilograms, ...) in the calculations. However, the programmer had used the American Measurement System for some of the system's calculations, which prevented the satellite navigation auto-correction system from working as inteded.
- + The satellite was destroyed.
- + As programs grow in their complexity, finding errors becomes even more challenging. The debugger integrated into NetBeans can help you find errors. The use of the debugger is introduced with videos embedded in the course material; going over them is always an option. ## Stack Trace - + When an error occurs in a program, the program typically prints something called a stack trace, i.e., the list of method calls that resulted in the error. For example, a stack trace might look like this: - + Exception in thread "main" ... at Program.main(Program.java:15) - + The type of error is stated at the beginning of the list, and the following line tells us where the error occurred. The line "at Program.main(Program.java:15)" says that the error occurred at line number 15 in the Program.java file. - + at Program.main(Program.java:15) - - + + ## Checklist for Troubleshooting - If your code doesn't work and you don't know where the error is, these steps will help you get started. @@ -112,43 +94,17 @@ If your code doesn't work and you don't know where the error is, these steps wil 6. If your program causes an exception, you should definitely pay attention to the stack trace associated with the exception, which is the list of method calls that resulted in the situation that caused the exception. 7. Learn how to use the debugger. The earlier video will get you started. - + ## Passing Test Input to Scanner - Manually testing the program is often laborious. It's possible to automate the passing of input by, for example, passing the string to be read into a Scanner object. You'll find an example below of how to test a program automatically. The program first enters five strings, followed by the previously seen string. After that, we try to enter a new string. The string "six" should not appear in the word set. The test input can be given as a string to the Scanner object in the constructor. Each line break in the test feed is marked on the string with a combination of a backslash and an n character "\n". - ```java String input = "one\n" + "two\n" + @@ -177,21 +133,11 @@ if (read.contains("six")) { } ``` - -The program's output only shows the one provided by the program, and no user commands. - Enter an input: @@ -204,11 +150,7 @@ Thank you! - Passing a string to the constructor of the Scanner class replaces input read from the keyboard. As such, the content of the string variable `input` 'simulates' user input. A line break in the input is marked with `\n`. Therefore, each part ending in an newline character in a given string input corresponds to one input given to the `nextLine()` command. @@ -216,15 +158,11 @@ When testing your program again manually, change the parameter Scanner object co The working of the program should continue to be checked on-screen. The print output can be a little confusing at first, as the automated input is not visible on the screen at all. The ultimate aim is to also automate the checking of the correctness of the output so that the program can be tested and the test result analyzed with the "push of a button". We shall return to this in later sections. - -## Unit Testing - The automated testing method laid out above where the input to a program is modified is quite convenient, but limited nonetheless. Testing larger programs in this way is challenging. One solution to this is unit testing, where small parts of the program are tested in isolation. @@ -234,32 +172,11 @@ Ready-made unit test libraries are commonly used in writing tests, which provide
- - -Let's take a look at writing unit tests with the help of an example. Let's assume that we have the following Calculator class and want to write automated tests for it. - - ```java public class Calculator { @@ -284,11 +201,7 @@ public class Calculator { } ``` - The calculator works by always remembering the result produced by the preceding calculation. All subsequent calculations are always added to the previous result. A minor error resulting from copying and pasting has been left in the calculator above. The method subtract should deduct from the value, but it currently adds to it. @@ -296,11 +209,7 @@ Unit test writing begins by creating a test class, which is created under the Te The test class `CalculatorTest` is initially empty. - ```java public class CalculatorTest { @@ -308,23 +217,11 @@ public class CalculatorTest { } ``` - + Tests are methods of the test class where each test tests an individual unit. Let's begin testing the class -- we start off by creating a test method that confirms that the newly created calculator's value is intially 0. - ```java import static org.junit.Assert.assertEquals; @@ -340,11 +237,7 @@ public class CalculatorTest { } ``` - In the calculatorInitialValueZero method a calculator object is first created. The assertEquals method provided by the JUnit test framework is then used to check the value. The method is imported from the Assert class with the import Static command, and it's given the expected value as a parameter - 0 in this instance - and the value returned by the calculator. If the values of the assertEquals method values ​​differ, the test will not pass. Each test method should have an "annotation" `@ Test`. This tells the JUnit test framework that this is an executable test method. @@ -352,16 +245,7 @@ To run the tests, select the project with the right-mouse button and click Test. Running the tests prints to the output tab (typically at the bottom of NetBeans) that contains some information specific to each test class. In the example below, tests of the CalculatorTest class from the package are executed. The number of tests executed were 1, none of which failed -- failure in this context means that the functionality tested by the test did not work as expected. -> - Testsuite: CalculatorTest @@ -373,38 +257,11 @@ BUILD SUCCESSFUL (total time: 0 seconds) - - -Let's add functionality for adding and subtracting to the test class. - ```java import static org.junit.Assert.assertEquals; @@ -434,26 +291,11 @@ public class CalculatorTest { } ``` - - -Executing the tests produces the following output. - Testsuite: CalculatorTest @@ -471,21 +313,13 @@ BUILD SUCCESSFUL (total time: 0 seconds) - The output tells us that three tests were executed. One of them failed. The test output also informs us of the line in which the error occured (25), and of the expected (-2) and actual (2) values. Whenever the execution of tests ends in an error, NetBeans also displays the error state visually. While the previous tests two passed, one of them resulted in an error. Let's fix the mistake left in the Calculator class. - + ```java // ... @@ -495,20 +329,11 @@ public void subtract(int number) { // ... ``` - -When the test are run again, they pass. - Testsuite: CalculatorTest @@ -520,36 +345,18 @@ BUILD SUCCESSFUL (total time: 0 seconds) - Unit testing tends to be extremely complicated if the whole application has been written in "Main". To make testing easier, the app should be split into small parts, each having a clear responsibility. In the previous section, we practiced this when we seperated the user interface from the application logic. Writing tests for parts of an application, such as the 'JokeManager' class from the previous section is significantly easier than writing them for program contained in "Main" in its entirety. - - -## Test-Driven Development - - Test-driven development is a software development process that's based on constructing a piece of software in small iterations. In test-driven software development, the first thing a programmer always does is write an automatically-executable test, which tests a single piece of the computer program. @@ -575,43 +382,37 @@ Test-driven software development consists of five steps that are repeated until
- + - + The exercise base contains the initial state of the previous example -- it already includes the JUnit unit testing library. Follow the steps of the example, and use the principles of test-driven software development to give the wanted functionality for the exercise management program. - + The exercise is in two parts: - + 1. Follow the steps of the example up until it's time to refactor the program and to create the class 'Exercise'. Create the classes `ExerciseManagementTest` and `ExerciseManagement`, and complete them with what the example instructs. - + 2. Follow the example all the way to the end. In other words, refactor the program as instructed. - + Update the `partsCompleted` class method of the MainProgram to return the highest part that you have completed. You can return the exercise even if you don't complete the second part, in which case you will receive the point for the first one. Returning 2 means you have completed both. - + If you desire to develop the program further (not awarded with points), you can try using test-driven development to first write a test (or a few) for removing exercises, and then implement that feature in your program. This is purely for your own amusement and is not reflected in the points in any manner! - Unit testing is only a part of software testing. On top of unit testing, a developer also performs integration tests that examine the interoperability of components, such as classes, and interface tests that test the application's interface through elements provided by the interface, such as buttons. diff --git a/data/part-6/4-complex-programs.md b/data/part-6/4-complex-programs.md index d632a4675..5480a2556 100644 --- a/data/part-6/4-complex-programs.md +++ b/data/part-6/4-complex-programs.md @@ -5,17 +5,17 @@ hidden: false --- - + When you learn programming, you also develop a better eye for reading code (yours and others). In this part we understood the use of lists and practiced separating the UI from the program logic. - + The following is from [On the role of scientific thought](https://www.cs.utexas.edu/users/EWD/ewd04xx/EWD447.PDF) by [Edsger W. Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra) . _Let me try to explain to you, what to my taste is characteristic for all intelligent thinking. It is, that one is willing to study in depth an aspect of one's subject matter in isolation for the sake of its own consistency, all the time knowing that one is occupying oneself only with one of the aspects. We know that a program must be correct and we can study it from that viewpoint only; we also know that it should be efficient and we can study its efficiency on another day, so to speak. In another mood we may ask ourselves whether, and if so: why, the program is desirable. But nothing is gained - on the contrary! - by tackling these various aspects simultaneously. It is what I sometimes have called "**the separation of concerns**", which, even if not perfectly possible, is yet the only available technique for effective ordering of one's thoughts, that I know of. This is what I mean by "focusing one's attention upon some aspect": it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect's point of view, the other is irrelevant. It is being one- and multiple-track minded simultaneously._ - + The core of Dikstra's message is, that the problem areas of a program must be separated from each other -- this is exactly what we have been doing with object-oriented programming and by separating the UI from the program logic. Each problem area has been separated into its own part. This can also be viewed through the lens of program responsibilities. In [his blog](https://8thlight.com/blog/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html) Robert "Unvle Bob" C. Martin describes the term "**single responsibility principle**": @@ -23,10 +23,10 @@ _When you write a software module, you want to make sure that when changes are r _[..in other words..] Gather together the things that change for the same reasons. Separate those things that change for different reasons._ - + Proper program structure and following good naming principles leads to clean code. When you code a bit more, you'll learn that each program part can be given one clear area of responsibility. - + Finish by answering to the quiz below. diff --git a/data/part-6/index.md b/data/part-6/index.md index c3129c4ab..fa39a7362 100644 --- a/data/part-6/index.md +++ b/data/part-6/index.md @@ -5,7 +5,7 @@ overview: true hidden: false --- - + The sixth part of the course material handles objects consisting of objects, and we'll take a look at separating the text user interface and the program logic. @@ -13,7 +13,7 @@ The sixth part of the course material handles objects consisting of objects, and - + The table of contents above lists the topics of the sixth part of the course. The sixth part has been designed to cover the sixth week of the course. You should reserve well above 10 hours for each part of the course, depending on previous experience with computers. If you've tried programming before, you might advance faster in the beginning. diff --git a/data/part-7/1-programming-paradigms.md b/data/part-7/1-programming-paradigms.md index e486fef1b..636d629ac 100644 --- a/data/part-7/1-programming-paradigms.md +++ b/data/part-7/1-programming-paradigms.md @@ -4,11 +4,10 @@ title: 'Programming paradigms' hidden: false --- - + - + - You know the concept of a programming paradigm. @@ -18,11 +17,7 @@ hidden: false - A programming paradigm is a way of thinking about and structuring a program's functionality. Programming paradigms differ from one another, for example in how the program's execution and control are defined and what components the programs consist of. @@ -32,42 +27,32 @@ The most common programming paradigms today are object-oriented programming, pro - + ## Object-Oriented Programming - + In object-oriented programming, information is represented as classes that describe the concepts of the problem domain and the logic of the application. Classes define the methods that determine how information is handled. During program execution, objects are instantiated from classes that contain runtime information and that also have an effect on program execution: program execution typically proceeds through a series of method calls related to the objects. As mentioned a few weeks ago, "the program is built from small, clear, and cooperative entities." - + The basic ideas of object-oriented programming, i.e., the representation of information and its processing methods with he help of classes and objects, first appeared in [Simula 67](https://en.wikipedia.org/wiki/Simula), which was designed for developing simulations and the [Smalltalk](https://en.wikipedia.org/wiki/Smalltalk) programming language. Its breakthrough came in the 1980s through the [C++](https://en.wikipedia.org/wiki/C%2B%2B) programming language and [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) has made it one of the most widely used programming paradigms in the world. - + One of the major benefits of object-oriented programming is how problem-domain concepts are modeled through classes and objects, which makes programs easier to understand. In addition, structuring the problem domain into classes facilitates the construction and maintenance of programs. However, object-oriented programming is not inherently suited to all problems: for example, scientific computing and statistics applications typically make use of languages, such as [R](https://en.wikipedia.org/wiki/R_(programming_language)) and [Python](https://en.wikipedia.org/wiki/Python_(programming_language)). - + ## Procedural programming - Whereas in object-oriented programming, the structure of a program is formed by the data it processes, in procedural programming, the structure of the program is formed by functionality desired for the program: the program acts as a step-by-step guide for the functionality to be performed. The program is executed one step at a time, and subroutines (methods) are called whenever necessary. In procedural programming, the state of the program is maintained in variables and tables, and any methods handle only the values provided to them as parameters. The program tells the computer what should happen. As an example, the code below demonstrates the swapping of values for two variables a and b - ```java int a = 10; @@ -79,58 +64,13 @@ b = a; a = c; ``` - When comparing object-oriented programming with procedural programming, a few essential differences emerge. In object-oriented programming, the state of an object can, in principle, change with any object method, and that change of state can also affect the working of the methods of other objects. As a consequence, other aspects of a program's execution may also be affected since objects can be used in multiple places within the program. The difference between object-oriented programming and procedural programming are shown concretely in the clock example presented at the beginning of Part Five. The solution below depicts a procedural style where the printing of the time is transferred to a method. - ```java int hours = 0; @@ -177,80 +117,11 @@ public static void print(int value) { } ``` - -The same implemented in an object-oriented way: - - - ```java public class Hand { private int value; @@ -491,30 +362,30 @@ Second: 0/100 - + Let's redo the previous program for handling two liquid containers. This time we'll create a class "Container", which is responsible for managing the contents of a container.

Container

- + Make a class called Container. The class must have a constructor which does not take any parameters, and the following methods: - + - `public int contains()` which returns the amount of liquid in a container as an integer. - + - `public void add(int amount)` which adds the amount of liquid given as a parameter to the container. If the amount is negative, no liquid is added. A container can hold a maximum of 100 units of liquid. - + - `public void remove(int amount)` which removes the amount of liquid given as a parameter from the container. If the amount is negative, no liquid is removed. A container can never hold less than 0 units of liquid. - + - `public String toString()` which returns the container as a string formatted "amount of liquid/100, for example "32/100". - + The class should work as follows: ```java @@ -545,11 +416,11 @@ System.out.println(container);

Functionality

- + Copy the user interface you implemented for the previous example, and modify it to use the new Container class. The main method in the class `LiquidContainers2` must start the program. - + Below is some sample output. The user interface should work as follows: diff --git a/data/part-7/2-algorithms.md b/data/part-7/2-algorithms.md index f58f6caf2..252eeae38 100644 --- a/data/part-7/2-algorithms.md +++ b/data/part-7/2-algorithms.md @@ -4,9 +4,7 @@ title: 'Algorithms' hidden: false --- - + @@ -16,11 +14,7 @@ hidden: false - Algorithms, precise instructions on how to to accomplish a specific task, are at the core of computer science. In the context of programming, algorithms are typically defined using source code. @@ -30,32 +24,28 @@ In a more general sense, retrieving and displaying information quickly is an int ## Sorting information - + If the information (data) giving to a computer, doesn't follow any rules and isn't in order, retrieving that information is taxing for the computer. We need order! ### Selection sort - + Every programmer should be familiar with at least one sorting algorithm (i.e a way to sort an array). Let's familiarize ourselves with one "classic" sorting algorithm, the selection sort. We'll do so with a programing exercise.

Finding the smallest value

- + Create in the class `MainProgram` a class method `smallest` that takes an integer array as a parameter. It should return the smallest value in the array. - + Here is the structure of the method: - + ```java public static int smallest(int[] array){ @@ -63,25 +53,18 @@ public static int smallest(int[] array){ } ``` - + The next example illustrates how the method works: - + ```java int[] numbers = {6, 5, 8, 7, 11}; System.out.println("Smallest: " + MainProgram.smallest(numbers)); ``` - @@ -90,23 +73,19 @@ Smallest: 5 - +

Index of the smallest value

- + Create a method called `indexOfSmallest` in the class MainProgram. It should return the index of the smallest number in the array that it receives as a parameter. - + Here is the structure of the method: - + ```java public static int indexOfSmallest(int[] array){ @@ -114,15 +93,11 @@ public static int indexOfSmallest(int[] array){ } ``` - + The following code illustrates how to use the method: - + ```java // indices: 0 1 2 3 4 @@ -130,11 +105,7 @@ int[] numbers = {6, 5, 8, 7, 11}; System.out.println("Index of the smallest number: " + MainProgram.indexOfSmallest(numbers)); ``` - @@ -142,28 +113,24 @@ Index of the smallest number: 1 - + The smallest number in the array is 5, and its position in the array (i.e. index) is 1. Be sure to remember that indexing an array begins at 0. - +

Index of the smallest value after a certain value

- + Create in the class MainProgram a class method called `indexOfSmallestFrom`. It works similarly to the method in the previous section, but only considers the table values from a certain index forwards. In addition to the table, it receives this start index as a parameter. - + The structure of the method is the following: - + ```java public static int indexOfSmallestFrom(int[] table, int startIndex) { @@ -171,17 +138,11 @@ public static int indexOfSmallestFrom(int[] table, int startIndex) { } ``` - + The following code illustrates how the method words: - + ```java // indices: 0 1 2 3 4 @@ -199,28 +160,24 @@ System.out.println(MainProgram.indexOfSmallestFrom(numbers, 2));
- + In this example the first method call searches for the index of the smallest number, starting from index 0. Starting from index 0, the smallest number is -1 and its index is 0. The second method call searches for the index of the smallest value starting from index 1. In this case the smallest number is 6 and its index is 1. The third calls searches for the index of the smallest value starting at index 2. Then the smallest number is 8 and its index is 3. - +

Swapping numbers

- + Create a class method `swap` in the class MainProgram. It receives as its parameters an array and two indices inside it. The method swaps the numbers in these indices with each other. - + The basic structure of the method is: - + ```java public static void swap(int[] array, int index1, int index2) { @@ -228,22 +185,12 @@ public static void swap(int[] array, int index1, int index2) { } ``` - - -The following illustrates how to use the method. To print an array we take use of the `toString` class method of the class `Arrays`. It formats an array into an easily readable string. - ```java int[] numbers = {3, 2, 5, 4, 8}; @@ -264,45 +211,42 @@ System.out.println(Arrays.toString(numbers));
- +

Sorting

- + We have now assembled a set of useful methods. With their help, we can implement a sorting algorithm known by the name of selection sort. - + The idea of selection sort is: - + - Move the smallest number in the array to index 0. - + - Move the second smallest number to index 1. - + - Move the third smalles number in the array to index 2. - + - Etc. - + In other words: - + - Examine the array starting from index 0. Swap the following two numbers with each other: the number at index 0, and the smallest number in the array starting from index 0. - Examine the array starting from index 1. Swap the following two numbers with each other: the number at index 1, and the smallest number in the array starting from index 1. @@ -310,19 +254,15 @@ In other words: - Etc. - + Implement a class method called `sort` based on the idea above in the class MainProgram. It should include a loop that goes through the indices of the array. Certainly the method `indexOfSmallestFrom` and `swap` will come in handy. Additionally, print the contents of the array before sorting and after every iteration of the loop to ensure that the algorithm works as you expect it to. - + The definition of the method looks like this: - ```java public static void sort(int[] array) { @@ -330,21 +270,18 @@ public static void sort(int[] array) { } ``` - + Use at least the following example to test how the method functions: - + ```java int[] numbers = {8, 3, 7, 9, 1, 2, 4}; MainProgram.sort(numbers); ``` - + The output of the program should look like the print below. Observe that you must print the contents of the array after each swap! @@ -358,7 +295,7 @@ The output of the program should look like the print below. Observe that you mus [1, 2, 3, 4, 7, 8, 9] - + Mark how the array becomes sorted little by little starting from the beginning and advancing towards the end of the array. @@ -366,13 +303,7 @@ Mark how the array becomes sorted little by little starting from the beginning a - At the start of the course, all of our methods included the `static` modifier, but when we started using objects, use of the `static` modifier was banned. Methods in Java can be divided into two groups, based on whether they have the `static` modifier or not. Methods without the `static` modifier are **instance methods**. Methods with the `static` modifier are **class methods** @@ -386,16 +317,11 @@ Instance methods are methods that are associated with an object, can process the ### Build-in sorting algorithms in Java - + Java offers a significant amount of ready to use sorting algorithms. Arrays can be sorted (into their natural order) using the class method `sort` of the `Arrays`-class. Lists can be sorted (into their natural order) using the class method sort of the `Collections` class. - + ```java int[] numbers = {8, 3, 7, 9, 1, 2, 4}; System.out.println(Arrays.toString(numbers)); @@ -409,15 +335,7 @@ System.out.println(Arrays.toString(numbers)); - + ```java ArrayList numbers = new ArrayList<>(); numbers.add(8); @@ -434,23 +352,13 @@ System.out.println(numbers); - + Java's build-in sorting algorithms work with value type variables and some of Java's build-in reference type variables, like String. In order for our own classes to be sorted, we need to provide Java with some tips on how to do that, because the classes themselves don't contain information on how objects created from them should be ordered. We'll get back to ordering objects created from classes we made ourselves in the advanced course in programming. - Add the following methods to the Main class: @@ -469,30 +377,17 @@ Be sure to use the ready-made Java libraries in your implementation. ## Information retrieval - + Next let's take a look at algorithms meant for information retrieval. ### Linear search - + Linear search is a search algorithm that searches for information in an array by going through every value in the array one by one. When the value that was searched for is found, its index is immediately returned. If the requested value cannot be found, linear sort returns the information that the value was not found -- typically this means returning `-1` instead of a valid index. - ```java public class Algorithms { @@ -509,14 +404,13 @@ public class Algorithms { } ``` - + In the worst case scenario, i.e when the value searched for isn't found, the algorithm has to do as many comparisons as there are values in the array. In an array containing, say, 10 million values, this means 10 million comparisons. If we are doing more than one search, it makes sense to try and improve efficiency. ### Binary search (aka half-interval search or logarithmic search ) - + When the data searched is in order, searching can be implemented a lot more efficiently than in linear search. The idea behind Binary Search is to start looking for the searched value in the middle index of the array (or list), compare the value found there to the searched value, and if needed (i.e, when the value isn't found there) eliminate half of the search area. The algorithm is more thoroughly introduced in the following slideshow. @@ -531,18 +425,12 @@ The idea behind Binary Search is to start looking for the searched value in the - In the exercise template you'll find the class `Book`, ready for use. The class describes objects with a numeric id `id` and a name `name`. In this exercise you will implement linear search and binary search algorithms for searching for books by their numeric id. In the exercise template you'll find the names of the methods to be implemented ready for you -- at the moment these method always return -1 -- you'll also find the Main method ready to be used for testing your methods. -

Linear search

@@ -551,23 +439,7 @@ The linear search algorithm works by checking every value in a list or an array In the `Main`-class, implement a method `public static int linearSearch(ArrayList books, int searchedId)`, which searches the list it received as a parameter, for a book with an `id` variable that matches the value of `searchedId` variable it received as a parameter. If that book is found, the method, should return the index it's located at in the list it received as a parameter. If the book isn't found, the method should return the value `-1`. -

Binary search

In the `Main`-class, implement a method `public static int binarySearch(ArrayList books, int searchedId)`, which searches the list it received as a parameter, for a book with an `id` variable that matches the value of `searchedId` variable it received as a parameter. If that book is found the method, should return the index it's located at, in the list it received as a parameter. If the book isn't found, the method should return the value `-1`. @@ -587,26 +459,7 @@ In the slideshow above, the idea of a binary search was described as follows: The pseudocode for binary search looks like this: - ```code // assuming the variable searched exits // assuming the variable list exits @@ -628,7 +481,7 @@ repeat until begin is larger than end: return value -1 ``` - + Note that in the case of books, you are examining the values of the books' `id`-variable. Meaning that in this exercise, instead of examining the value at an index, you should examine the value of the `id`-variable of the value found at the index. diff --git a/data/part-7/3-larger-exercises.md b/data/part-7/3-larger-exercises.md index 41d989866..1755cfc01 100644 --- a/data/part-7/3-larger-exercises.md +++ b/data/part-7/3-larger-exercises.md @@ -5,17 +5,17 @@ hidden: false --- - + To conclude the seventh part, you'll do a few more extensive exercises. There is no predefined structure for these tasks -- think about the classes and objects that will help you complete the task while you're completing it. - + - + In this exercise we create a program for printing statistics for points in course. The program receives points (integers from zero to one hundred) as input, based on which it prints statistics about grades. Reading of input stops when the user enters the number -1. Numbers that are not within the interval [0-100] should not be taken into account when calculating the statistics. - + A string read from the user can be converted to an integer using the `Integer` class' method `valueOf`. It works as follows: @@ -35,27 +35,15 @@ System.out.println(number + 7); - +

Point averages

- -Write a program that reads integers representing course point totals from the user. Numbers between [0-100] are acceptable and the number -1 ends the reading of input. Other numbers are erroneous input, which should be ignored. When the user enters the number -1, the program should print the average of the point totals that were input. - @@ -71,16 +59,7 @@ Point average (all): 54.0 - @@ -94,31 +73,18 @@ Point average (all): 51.0 - +

Point average for points giving a passing grade

- + Extend the program, such that it in addition to giving the point average of all totals also provides the point average for points giving a passing grade. - -A passing grade is achieved by getting a minimum of 50 course points. You may assume that the user always provides at least one integer between [0-100]. If there are no numbers giving a passing grade, the program should print a line "-" where the average would be. - @@ -135,17 +101,7 @@ Point average (passing): 68.0 - @@ -160,25 +116,14 @@ Point average (passing): - - +

Pass percentage

- +

Extend the program from the previous part, such that it also print the pass percentage. The pass percentage is calculated using the formula 100 * passing / participants.

- @@ -193,21 +138,7 @@ Pass percentage: 0.0 - @@ -226,43 +157,14 @@ Pass percentage: 50.0 - +

Grade distribution

- + Extend the program, such that it also prints the grade distribution. The grade distribution is as follows: - + @@ -296,11 +198,11 @@ Extend the program, such that it also prints the grade distribution. The grade d
- + Each point total is converted to a grade based on the above table. If a point total isn't within [0-100], it should be ignored. - +

The grade distribution is printed out as stars. E.g. if there is one point total giving the grade 5, then it should print the row 5: *. If there are no point totals giving a particular grade, then no stars should be printed for it. In the sample below this is true for e.g. the grade 4.

@@ -334,42 +236,15 @@ Grade distribution: - -In this exercise we are going to create a program that allows for searching for recipes based on their name, cooking time, or the name of an ingredient. The program should read the recipes from a file that the user provides. *It might be a good idea to brush up on reading information from files (part 4) before beginning* - +In this exercise we are going to create a program that allows for searching for recipes based on their name, cooking time, or the name of an ingredient. The program should read the recipes from a file that the user provides. *It might be a good idea to brush up on reading information from files (part 4) before beginning* -Each recipe consists of three or more rows in a recipe file. The first row is for the name of the recipe, the second the cooking time (an integer), and the third and possibly following rows list the ingredients used in the recipe. An empty row follows the last ingredient row. There can be many recipes in a single file. Below, an example file containing recipes is described. - @@ -399,45 +274,28 @@ wasabi - + The program will be implemented in parts. First we'll create the possibility to read and list recipes. After that we'll add the functionality to search for recipes based on their name, cooking time, or the name of an ingredient. - + There is a file called `recipes.txt` supplied with the exercise base. You can use it for testing purposes. Notice that the program should not list the ingredients of the recipes, but they will be used in the search functionality. - +
- -

Reading and listing recipes

- - -First create the functionality to read and list recipes. The user interface of the program is described below. You may assume that the user only enters files that exist. Below we assume that the example recipes given earlier in the exercise description are stored in the file `recipes.txt`. - - @@ -459,39 +317,15 @@ Enter command: **stop** - -

Finding recipes by name

- - - -Make it possible to find recipes by their names. Finding by name is done with the command `find name`, after which the user is asked for the name that is used to search. The search should print all the recipes whose names contain the string given by the user. - - @@ -519,45 +353,15 @@ Enter command: **stop** - -

Searching for recipes by cooking time

- - - -Next, implement the possibility to find recipes based on their cooking time. This is done with the command `find cooking time`, after which the user is asked for the longest acceptable cooking time. The program should react by printing all the recipes whose cooking times don't exceed the cooking time given by the user (so equal or less time). - - @@ -592,57 +396,17 @@ Enter command: **stop** - - -

Finding recipes based on their ingredients

- - - - -Finally, add the functionality to search for recipes based on their ingredients. This is done by choosing the command `find ingredient`, after which the user is asked for a string. The program should then print all the recipes that contain the specified string. Notice that with this option the given string must match exactly the ingredient that is searched for (e.g. "ugar" will return different results than "sugar"). - - @@ -691,28 +455,28 @@ Enter command: **stop** **This exercise is worth three one-part exercises** - + In this exercise you will design and implement a database for bird-watchers. The database contains birds, each of which has a name (string) and a name in Latin (string). The database also counts the observations of each bird. - + The program must implement the following commands: - + - `Add` - adds a bird - + - `Observation` - adds an observation - + - `All` - prints all birds - + - `One` - prints one bird - + - `Quit` - ends the program - + Incorrect input must also be handled. The following is an example of the program functionality: @@ -741,7 +505,7 @@ Hawk (Dorkus Dorkus): 2 observations - + **NB** You're free to structure your program the way you want. We only test that the `main` method of the `mainProgram` class works as shown above. You will most likely find it useful to use classes that are descriptive of the problem domain.
diff --git a/data/part-7/4-introduction-to-programming.md b/data/part-7/4-introduction-to-programming.md index 2b1ccf667..06959aa7f 100644 --- a/data/part-7/4-introduction-to-programming.md +++ b/data/part-7/4-introduction-to-programming.md @@ -4,13 +4,7 @@ title: 'Summary and about exam' hidden: false --- - During the first seven parts you've become familiar with the basics of programming and produced many functioning program. You now know how to use variables, conditionals, loops and methods. You know that the naming of variables and methods affects the understandability of your programs. You've also dived deeper into the world of object-oriented programming, and to the wording of your programs through it. In addition, you've become acquainted with one of the most important tools of a professional developer - the integrated development environment (IDE). diff --git a/data/part-7/index.md b/data/part-7/index.md index 8185aa61e..f806c60f6 100644 --- a/data/part-7/index.md +++ b/data/part-7/index.md @@ -5,7 +5,7 @@ overview: true hidden: false --- - + In the seventh part of the course we'll focus on general programming paradigms and algorithms. The course Introduction to programming (TKT-10002) ends after the seventh week, and the Advanced course in programming (TKT-10003) begins with the eight part. @@ -36,7 +36,7 @@ The exam can be found at this page on March 21st 2020 at 08:00: - + The table of contents above lists the topics of the seventh part of the course. The seventh part has been designed to cover the seventh week of the course. You should reserve well above 10 hours for each part of the course, depending on previous experience with computers. If you've tried programming before, you might advance faster in the beginning. diff --git a/data/part-8/1-recap.md b/data/part-8/1-recap.md index 4594842cf..dfdb3effa 100644 --- a/data/part-8/1-recap.md +++ b/data/part-8/1-recap.md @@ -5,11 +5,7 @@ title: 'Short recap' hidden: false --- - @@ -17,27 +13,17 @@ hidden: false - + Below there are a few exercises that go over the material introduced in the parts 1-7. The assignments are identical to some exercises that have appeared earlier in the material. If you have completed some of the exercises before, please solve them again without looking at your earlier solution. - -Write a program that reads strings from the user until the user inputs the string "end". As long as the input is not "end" the program should handle the input as an integer and print the cube of the integer (meaning number * number * number). Below are some sample outputs - @@ -51,11 +37,7 @@ Write a program that reads strings from the user until the user inputs the strin - @@ -68,14 +50,14 @@ Write a program that reads strings from the user until the user inputs the strin - + Write a number that asks user for input until the user inputs 0. After this, the program prints the average of the positive numbers (numbers that are greater than zero). - + If no positive number is inputted, the program prints "Cannot calculate the average" - + Below a few examples of the program's output @@ -287,31 +269,31 @@ Second: 0/100 - + Let's redo the previous program for handling two liquid containers. This time we'll create a class `Container`, which is responsible for managing the contents of a container.

Container

- + Make a class called `Container`. The class must have a constructor which does not take any parameters, and the following methods: - + - `public int contains()` which returns the amount of liquid in a container as an integer. - + - `public void add(int amount)` which adds the amount of liquid given as a parameter to the container. If the amount is negative, no liquid is added. A container can hold maximum of 100 units of liquid. - + - `public void remove(int amount)` which removes the amount of liquid given as a parameter from the container. If the amount is negative, no liquid is removed. A container can never hold less than 0 units of liquid. - + - `public String toString()` which returns the container as a string formatted "amount of liquid/100", for example "32/100". - + The class should work as follows: ```java @@ -342,11 +324,11 @@ System.out.println(container);

Functionality

- + Copy the user interface you implemented for the previous example, and modify it to use the new `Container` class. The main method in the class `LiquidContainers2` must start the program. - + Below is some sample output. The user interface should work as follows: @@ -386,32 +368,11 @@ Second: 0/100 - + In this exercise we are going to create a program that can be used to create and modify a to-do list. The final product will work in the following manner. - + Command: **add** @@ -435,19 +396,15 @@ Command: **stop** - + We will build the program in parts. - +

TodoList

- Create a class called `TodoList`. It should have a constructor without parameters and the following methods: @@ -455,18 +412,7 @@ Create a class called `TodoList`. It should have a constructor without parameter - `public void print()` - prints the exercises. Each task has a number associated with it on the print statement -- use the task's index here (+1). - `public void remove(int number)` - removes the task associated with the given number; the number is the one seen associated with the task in the print. - ```java TodoList list = new TodoList(); @@ -481,16 +427,7 @@ System.out.println(); list.print(); ``` - 1: read the course material @@ -502,28 +439,15 @@ list.print(); - + **NB!** You may assume that the `remove` method is given a number that corresponds to a real task. The method only has to correctly work once after each print call. - + Another example: - + ```java TodoList list = new TodoList(); @@ -540,19 +464,7 @@ list.remove(1); list.print(); ``` - 1: read the course material @@ -567,18 +479,11 @@ list.print(); - -

User interface

- Next, implement a class called `UserInterface`. It should have a constructor with two parameters. The first parameter is an instance of the class `TodoList`, and the second is an instance of the class `Scanner`. In addition to the constructor, the class should have the method `public void start()` that is used to start the text user interface. The text UI works with an eternal looping statement (`while-true`), and it must offer the following commands to the user: @@ -592,29 +497,7 @@ Next, implement a class called `UserInterface`. It should have a constructor wit Below is an example of how the program should work. - + @@ -640,7 +523,7 @@ Command: **stop** - + NB! The user interface is to use the TodoList and Scanner that are passed as parameters to the constructor. diff --git a/data/part-8/2-hash-map.md b/data/part-8/2-hash-map.md index ddb3a55f2..b879bb27e 100644 --- a/data/part-8/2-hash-map.md +++ b/data/part-8/2-hash-map.md @@ -4,14 +4,10 @@ title: 'Hash Map' hidden: false --- - + - + - You're familiar with the concept of a hash map and know how one works. - You know how to use Java's hash map: you know how to create one, add information to it and retrieve information from it. @@ -21,9 +17,7 @@ hidden: false - A [HashMap](http://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html) is, in addition to ArrayList, one of the most widely used of Java's pre-built data structures. The hash map is used whenever data is stored as key-value pairs, where values can be added, retrieved, and deleted using keys. @@ -31,15 +25,7 @@ In the example below, a HashMap object has been created to search for cities by - ```java HashMap postalCodes = new HashMap<>(); postalCodes.put("00710", "Helsinki"); @@ -57,27 +43,16 @@ Helsinki
- + The internal state of the hash map created above looks like this. Each key refers to some value. - + A value in a hashmap is looked up based on a key. - -If the hash map does not contained the key used for the search, its `get` method returns a `null` reference. - ```java HashMap numbers = new HashMap<>(); numbers.put("One", "Uno"); @@ -103,11 +78,7 @@ null - Using a hash map requires the `import java.util.HashMap;` statement at the beginning of the class. Two type parameters are required when creating a hash map - the type of the key and the type of the value added. If the keys of the hash map are of type string, and the values of type integer, the hash map is created with the following statement `HashMap hashmap = new HashMap<>();` @@ -116,45 +87,32 @@ Adding to the hash map is done through the `put(*key*, *value*)` method that has - + In the `main`-method create a new `HashMap` object. Store the names and nicknames of the following people in this hashmap so, that the name is the key and the nickname is the value. Use only lower case letters. - - - + + + - matthew's nickname is matt - michael's nickname is mix - arthur's nickname is artie - + Then get Matthew's nickname from the hashmap, and print it. - + There is no automated tests for this exercise. Just submit the exercise when you think it works as it should. - -## Hash Map Keys Correspond to a Single Value at Most - -The hash map has a maximum of one value per key. If a new key-value pair is added to the hash map, but the key has already been associated with some other value stored in the hash map, the old value will vanish from the hash map. +## Hash Map Keys Correspond to a Single Value at Most - ```java HashMap numbers = new HashMap<>(); @@ -180,55 +138,14 @@ Ein
- -## A Reference Type Variable as a Hash Map Value - - -Let's take a look at how a spreadsheet works using a library example. You can search for books by book title. If a book is found with the given search term, the library returns a reference to the book. Let's begin by creating an example class `Book` that has its name, content and the year of publication as instance variables. - - ```java public class Book { private String name; @@ -272,27 +189,18 @@ public class Book { } ``` - + Let's create a hash map that uses the book's name as a key, i.e., a String-type object, and the book we've just created as the value. - + ```java HashMap directory = new HashMap<>(); ``` - + The hash map above uses a`String` object as a key. Let's expand the example so that two books are added to the directory, `"Sense and Sensibility"` and `"Pride and Prejudice"`. - ```java Book senseAndSensibility = new Book("Sense and Sensibility", 1811, "..."); Book prideAndPrejudice = new Book("Pride and Prejudice", 1813, "...."); @@ -302,17 +210,11 @@ directory.put(senseAndSensibility.getName(), senseAndSensibility); directory.put(prideAndPrejudice.getName(), prideAndPrejudice); ``` - + Books can be retrieved from the directory by book name. A search for `"Persuasion"` will not produce any results, in which case the hash map returns a `null`-reference. The book "Pride and Prejudice" is found, however. - + ```java Book book = directory.get("Persuasion"); System.out.println(book); @@ -321,14 +223,7 @@ book = directory.get("Pride and Prejudice"); System.out.println(book); ``` - null @@ -338,21 +233,16 @@ Content: ... - - + - -## When Should Hash Maps Be Used? - The hash map is implemented internally in such a way that searching by a key is very fast. The hash map generates a "hash value" from the key, i.e. a piece of code, which is used to store the value of a specific location. When a key is used to retrieve information from a hash map, this particular code identifies the location where the value associated with the key is. In practice, it's not necessary to go through all the key-value pairs in the hash map when searching for a key; the set that's checked is significantly smaller. We'll be taking a deeper look into the implementation of a hash map in the Advanced Programming and Data Structures and Algorithms courses. @@ -362,36 +252,7 @@ Consider the library example that was introduced above. The whole program could In the example below, the books have been stored in a list and searching for them is done by going through the list. - ```java ArrayList books = new ArrayList<>(); Book senseAndSensibility = new Book("Sense and Sensibility", 1811, "..."); @@ -423,14 +284,7 @@ for (Book book: books) { System.out.println(match); ``` - Name: Sense and Sensibility (1811) @@ -440,22 +294,11 @@ null - -For the program above, you could create a separate class method `get` that is provided a list and the name of the book to be fetched as parameters. The method returns a book found by the given name if one exists. Otherwise, the method returns a `null` reference. - ```java public static Book get(ArrayList books, String name) { @@ -469,22 +312,10 @@ public static Book get(ArrayList books, String name) { } ``` - -Now the program is a bit more clear. - - ```java ArrayList books = new ArrayList<>(); Book senseAndSensibility = new Book("Sense and Sensibility", 1811, "..."); @@ -499,14 +330,7 @@ System.out.println(); System.out.println(get(books, "Persuasion")); ``` - Name: Sense and Sensibility (1811) @@ -516,29 +340,12 @@ null - The program would now work in the same way as the program implemented with the hash map, right? Functionally, yes. Let's, however, consider the performance of the program. Java's `System.nanoTime()` method returns the time of the computer in nanoseconds. We'll add functionality to the program considered above to calculate how long it took to retrieve the books. - ```java ArrayList books = new ArrayList<>(); @@ -556,15 +363,7 @@ double durationInMilliseconds = 1.0 * (end - start) / 1000000; System.out.println("The book search took " + durationInMilliseconds + " milliseconds."); ``` - Name: Sense and Sensibility (1811) @@ -575,30 +374,13 @@ The book search took 881.3447 milliseconds. - With ten million books, it takes almost a second to find two books. Of course, the way in which the list is ordered has an effect. If the book being searched was first on the list, the program would be faster. On the other hand, if the book were not on the list, the program would have to go through all of the books in the list before determining that such book does not exist. Let's consider the same program using a hash map. - ```java HashMap directory = new HashMap<>(); @@ -616,15 +398,7 @@ double durationInMilliseconds = 1.0 * (end - start) / 1000000; System.out.println("The book search took " + durationInMilliseconds + " milliseconds."); ``` - Name: Sense and Sensibility (1811) @@ -645,33 +419,23 @@ The hash maps also have no internal order, and it is not possible to search the Typically, hash maps and lists are used together. The hash map provides quick access to a specific key or keys, while the list is used, for instance, to maintain order. - + ## Hash Map as an Instance Variable - The example considered above on storing books is problematic in that the book's spelling format must be remembered accurately. Someone may search for a book with a lowercase letter, while another may, for example, enter a space to begin typing a name. Let's take a look at a slightly more forgiving search by book title. We make use of the tools provided by the String-class to handle strings. The `toLowerCase()` method creates a new string with all letters converted to lowercase. The `trim()` method, on the other hand, creates a new string where empty characters such as spaces at the beginning and end have been removed. - + ```java String text = "Pride and Prejudice "; text = text.toLowerCase(); // text currently "pride and prejudice " text = text.trim(); // text now "pride and prejudice" ``` - The conversion of the string described above will result in the book being found, even if the user happens to type the title of the book with lower-case letters. @@ -679,31 +443,7 @@ Let's create a `Library` class that encapsulates a hash map containing books, an Let's first outline the method for adding. The book is added to the hash map with the book name as the key and the book itself as the value. Since we want to allow for minor misspellings, such as capitalized or lower-cased strings, or ones with spaces at the beginning and/or end, the key - the title of the book - is converted to lowercase, and spaces at the beginning and end are removed. - ```java public class Library { private HashMap directory; @@ -730,23 +470,12 @@ public class Library { } ``` - The `containsKey` method of the hash map is being used above to check for the existence of a key. The method returns `true` if any value has been added to the hash map with the given key. Otherwise, the method returns `false`. We can already see that code dealing with string sanitizion is needed in every method that handles a book, which makes it a good candiate for a separate helper method. The method is implemented as a class method since it doesn't handle object variables. - ```java public static String sanitizedString(String string) { if (string == null) { @@ -758,52 +487,10 @@ public static String sanitizedString(String string) { } ``` - -The implementation is much neater when the helper method is used. - - ```java public class Library { private HashMap directory; @@ -848,25 +535,10 @@ public class Library { } ``` - -Let's take a look at the class in use. - - ```java Book senseAndSensibility = new Book("Sense and Sensibility", 1811, "..."); Book prideAndPrejudice = new Book("Pride and Prejudice", 1813, "...."); @@ -884,17 +556,7 @@ System.out.println(); System.out.println(library.getBook("SENSE")); ``` - Name: Pride and Prejudice (1813) @@ -907,13 +569,13 @@ null - + In the above example, we adhered to the DRY (Don't Repeat Yourself) principle according to which code duplication should be avoided. Sanitizing a string, i.e., changing it to lowercase, and *trimming*, i.e., removing empty characters from the beginning and end, would have been repeated many times in our library class without the `sanitizedString` method. Repetitive code is often not noticed until it has already been written, which means that it almost always makes its way into the code. There's nothing wrong with that - the important thing is that the code is cleaned up so that places that require tidying up are noticed. - + Create a class `Abbreviations` for managing common abbreviations. The class must have a constructor, which does not take any parameters. The class must also provide the following methods: - `public void addAbbreviation(String abbreviation, String explanation)` adds a new abbreviation and its explanation. @@ -944,7 +606,7 @@ System.out.println(); - + for example more precisely and so on lol @@ -952,14 +614,10 @@ for example more precisely and so on lol - -## Going Through A Hash Map's Keys - We may sometimes want to search for a book by a part of its title. The `get` method in the hash map is not applicable in this case as it's used to search by a specific key. Searching by a part of a book title is not possible with it. We can go through the values ​​of a hash map by using a for-each loop on the set returned by the `keySet()` method of the hash map. @@ -967,25 +625,7 @@ We can go through the values ​​of a hash map by using a for-each loop on the Below, a search is performed for all the books whose names contain the given string. - ```java public ArrayList getBookByPart(String titlePart) { titlePart = sanitizedString(titlePart); @@ -1008,26 +648,26 @@ public ArrayList getBookByPart(String titlePart) { } ``` - + This way, however, we lose the speed advantage that comes with the hash map. The hash map is implemented in such a way that searching by a single key is extremely fast. The example above goes through all the book titles when looking for the existence of a single book using a particular key. - + Exercise template contains a class `Program`. Implement the following class methods in the class: - - - + + + - `public static void printKeys(HashMap hashmap)`, prints all the keys in the hashmap given as a parameter. - `public static void printKeysWhere(HashMap hashmap, String text)` prints the keys in the hashmap given as a parameter, which contain the string given as a parameter. - `public static void printValuesOfKeysWhere(HashMap hashmap, String text)`, prints the values in the given hashmap whichs keys contain the given string. - + Example of using the class methods: ```java @@ -1054,36 +694,20 @@ for example more precisely - + NB! The order of the output can vary, because the implementation of hashmaps does not guarantee the order of the objects in it.
- -## Going Through A Hash map's Values - - -The preceding functionality could also be implemented by going through the hash map's values. The set of values can be retrieved with the hash map's `values​​()` method. This set of values can also be iterated over ​​with a for-each loop. +## Going Through A Hash map's Values - ```java public ArrayList getBookByPart(String titlePart) { titlePart = sanitizedString(titlePart); @@ -1102,24 +726,24 @@ public ArrayList getBookByPart(String titlePart) { } ``` - + As with the previous example, the speed advantage that comes with the hash map is lost. - + The exercise template contains the already familiar classes `Book` and `Program`. In the class `Program` implement the following class methods: - + - `public static void printValues(HashMap hashmap)`, which prints all the values in the hashmap given as a parameter using the toString method of the Book objects. - + - `public static void printValueIfNameContains(HashMap hashmap, String text)`, which prints only the Books in the given hashmap which name contains the given string. You can find out the name of a Book with the method `getName`. - + An example of using the class methods: ```java @@ -1132,15 +756,15 @@ System.out.println("---"); printValueIfNameContains(hashmap, "prejud"); ``` - - - - - - - - - + + + + + + + + + Name: Pride and prejudice (1813) Contents: ... @@ -1151,57 +775,31 @@ Name: Pride and prejudice (1813) Contents: ... - + NB! The order of the output may vary. The implementation of a hashmap does not guarantee the order of the objects in it. - + ## Primitive Variables In Hash Maps - + A hash map expects that only reference-variables are added to it (in the same way that `ArrayList` does). Java converts primitive variables to their corresponding reference-types when using any Java's built in data structures (such as ArrayList and HashMap). Although the value `1` can be represented as a value of the primitive `int` variable, its type should be defined as `Integer` when using ArrayLists and HashMaps. - + ```java HashMap hashmap = new HashMap<>(); // works hashmap.put(1, "Ole!"); HashMap map2 = new HashMap<>(); // doesn't work ``` - -A hash map's key and the object to be stored are always reference-type variables. If you want to use a primitive variable as a key or value, there exists a reference-type version for each one. A few have been introduced below. - @@ -1226,17 +824,11 @@ A hash map's key and the object to be stored are always reference-type variables
- + Java converts primitive variables to reference-types automatically as they are added to either a HashMap or an ArrayList. This automatic conversion to a reference-type variable is termed *auto-boxing* in Java, i.e. putting something in a box automatically. The automatic conversion is also possible in the other direction. - + ```java int key = 2; HashMap hashmap = new HashMap<>(); @@ -1248,35 +840,12 @@ System.out.println(value); 10 - -The following examples describes a class used for counting the number of vehicle number-plate sightings. Automatic type conversion takes place in the `addSighting` and `timesSighted` methods. +The following examples describes a class used for counting the number of vehicle number-plate sightings. Automatic type conversion takes place in the `addSighting` and `timesSighted` methods. - ```java public class registerSightingCounter { private HashMap allSightings; @@ -1301,39 +870,25 @@ public class registerSightingCounter { } ``` - There is, however, some risk in type conversions. If we attempt to convert a `null` reference - a sighting not in HashMap, for instance - to an integer, we witness a *java.lang.reflect.InvocationTargetException* error. Such an error may occur in the `timesSighted` method in the example above - if the `allSightings` hash map does not contain the value being searched, it returns a `null` reference and the conversion to an integer fails. When performing automatic conversion, we should ensure that the value to be converted is not null. For example, the `timesSighted` method in the program program should be fixed in the following way. -> - + ```java public int timesSighted(String sighted) { return this.allSightings.getOrDefault(sighted, 0); } ``` - + The `getOrDefault` method of the HashMap searches for the key passed to it as a parameter from the HashMap. If the key is not found, it returns the value of the second parameter passed to it. The one-liner shown above is equivalent in its function to the following. - ```java public int timesSighted(String sighted) { if (this.allSightings.containsKey(sighted)) { @@ -1344,30 +899,12 @@ public int timesSighted(String sighted) { } ``` - -Let's make the `addSighting` method a little bit neater. In the original version, 0 is set as the value of the sighting count in the hash map if the given key is not found. We then get retrieve the count of the sightings, increment it by one, and the previous value of the sightings is replaced with the new one by adding the incremented count back into the hash map. A part of this can also be replaced with the `getOrDefault` method. +Let's make the `addSighting` method a little bit neater. In the original version, 0 is set as the value of the sighting count in the hash map if the given key is not found. We then get retrieve the count of the sightings, increment it by one, and the previous value of the sightings is replaced with the new one by adding the incremented count back into the hash map. A part of this can also be replaced with the `getOrDefault` method. - ```java public class registerSightingCounter { private HashMap allSightings; @@ -1391,22 +928,22 @@ public class registerSightingCounter { - + Create a class called `IOU` which has the following methods: - + - constructor `public IOU()` creates a new IOU - + - `public void setSum(String toWhom, double amount)` saves the amount owed and the person owed to to the IOU. - + - `public double howMuchDoIOweTo(String toWhom)` returns the amount owed to the person whose name is given as a parameter. If the person cannot be found, it returns 0. - + The class can be used like this: ```java @@ -1418,7 +955,7 @@ System.out.println(mattsIOU.howMuchDoIOweTo("Arthur")); System.out.println(mattsIOU.howMuchDoIOweTo("Michael")); ``` - + The code above prints: @@ -1428,10 +965,10 @@ The code above prints: - + Be careful in situations, when a person does not owe anything to anyone. - + NB! The IOU does not care about old debt. When you set a new sum owed to a person when there is some money already owed to the same person, the old debt is forgotten. ```java diff --git a/data/part-8/3-similarity-of-objects.md b/data/part-8/3-similarity-of-objects.md index cbed3a7b3..1ada13bbf 100644 --- a/data/part-8/3-similarity-of-objects.md +++ b/data/part-8/3-similarity-of-objects.md @@ -4,14 +4,7 @@ title: "Similarity of objects" hidden: false --- - - You'll revise object equivalence comparison using the equals method. @@ -21,41 +14,21 @@ hidden: false - + Let's revise the `equals` method used to compare objects, and become familiar with the `hashCode` method used in making approximate comparisons. - + ## Method to Test For Equality - "equals" - The equals method checks by default whether the object given as a parameter has the same reference as the object it is being compared to. In other words, the default behaviour checks whether the two objects are the same. If the reference is the same, the method returns `true`, and `false` otherwise. This can be illustrated with the following example. The `Book` class does not have its own implementation of the `equals` method, so it falls back on the default implementation provided by Java. - ```java Book bookObject = new Book("Book object", 2000, "..."); @@ -77,12 +50,7 @@ if (bookObject.equals(anotherBookObject)) { } ``` - The books are the same @@ -90,11 +58,7 @@ The books aren't the same - The internal structure of the book objects (i.e., the values of their instance variables ) in the previous example is the same, but only the first comparison prints "`The books are the same`". This is because the references are the same in the first case, i.e., the object is compared to itself. The second comparison is about two different entities, even though the variables have the same values. @@ -102,32 +66,7 @@ For strings, `equals` works as expected in that it declares two strings _identic If we want to compare our own classes using the `equals` method, then it must be defined inside the class. The method created accepts an `Object`-type reference as a parameter, which can be any object. The comparison first looks at the references. This is followed by checking the parameter object's type with the `instanceof` operation - if the object type does not match the type of our class, the object cannot be the same. We then create a version of the object that is of the same type as our class, after which the object variables are compared against each other. - ```java public boolean equals(Object comparedObject) { @@ -156,78 +95,11 @@ public boolean equals(Object comparedObject) { } ``` - - -The `Book` class in its entirety. - - ```java public class Book { @@ -298,20 +170,11 @@ public class Book { } ``` - + Now the book comparison returns `true` if the instance variables of the books are the same. - ```java Book bookObject = new Book("Book Object", 2000, "..."); @@ -324,11 +187,7 @@ if (bookObject.equals(anotherBookObject)) { } ``` - The books are the same @@ -337,25 +196,11 @@ The books are the same - -The ArrayList also uses the `equals` method in its internal implementation. If we don't define the `equals` method in our objects, the `contains` method of the ArrayList does not work properly. If you try out the code below with two Book classes, one with the `equals` method defined and another without it, you'll see the difference. - - ```java ArrayList books = new ArrayList<>(); @@ -373,21 +218,17 @@ if (!books.contains(bookObject)) { } ``` - + This reliance on default methods such as `equals` is actually the reason why Java demands that variables added to ArrayList and HashMap are of reference type. Each reference type variable comes with default methods, such as equals, which means that you don't need to change the internal implementation of the ArrayList class when adding variables of different types. Primitive variables do not have such default methods. - -## Approximate Comparison With HashMap - In addition to `equals`, the `hashCode` method can also be used for **approximate comparison of objects**. The method creates from the object a "hash code", i.e, a number, that tells a bit about the object's content. If two objects have the same hash value, they may be equal. On the other hand, if two objects have different hash values, they are certainly unequal. @@ -395,17 +236,7 @@ Hash codes are used in HashMaps, for instance. HashMap's internal behavior is ba So far, we've only used String and Integer-type objects as HashMap keys, which have conveniently had ready-made `hashCode` methods implemented. Let's create an example where this is not the case: we'll continue with the books and keep track of the books that are on loan. We'll implement the book keeping with a HashMap. The key is the book and the value attached to the book is a string that tells the borrower's name: - ```java HashMap borrowers = new HashMap<>(); @@ -427,11 +258,7 @@ null - We find the borrower when searching for the same object that was given as a key to the hash map's `put` method. However, when searching by the exact same book but with a different object, a borrower isn't found, and we get the _null_ reference instead. The reason lies in the default implementation of the `hashCode` method in the `Object` class. The default implementation creates a `hashCode` value based on the object's reference, which means that books having the same content that are nonetheless different objects get different results from the hashCode method. As such, the object is not being searched for in the right place. @@ -439,11 +266,7 @@ For the HashMap to work in the way we want it to, that is, to return the borrowe We've previously used `String` objects as HashMap keys, so we can deduce that the `String` class has a well-functioning `hashCode` implementation of its own. We'll _delegate_, i.e., transfer the computational responsibility to the `String` object. - + ```java public int hashCode() { @@ -451,19 +274,11 @@ public int hashCode() { } ``` - + The above solution is quite good. However, if `name` is _null_, we see a `NullPointerException` error. Let's fix this by defining a condition: if the value of the `name` variable is _null_, we'll return the year of publication as the hash value. - ```java public int hashCode() { @@ -477,15 +292,7 @@ public int hashCode() { Now, all of the books that share a name are bundled into one group. Let's improve it further so that the year of publication is also taken into account in the hash value calculation that's based on the book title. - ```java public int hashCode() { @@ -497,21 +304,11 @@ public int hashCode() { } ``` - -It's now possible to use the book as the hash map's key. This way the problem we faced earlier gets solved and the book borrowers are found: - ```java HashMap borrowers = new HashMap<>(); @@ -525,7 +322,7 @@ System.out.println(borrowers.get(new Book("Book Object", 2000, "..."))); System.out.println(borrowers.get(new Book("Test Driven Development", 1999))); ``` - + Output: @@ -536,30 +333,15 @@ Arto - **Let's review the ideas once more:** for a class to be used as a HashMap's key, we need to define for it: - the `equals` method, so that all equal or approximately equal objects cause the comparison to return true and all false for all the rest - the `hashCode` method, so that as few objects as possible end up with the same hash value - - NetBeans provides support for the creation of both `equals` and `hashCode`. You can select Source -> Insert Code from the menu and then select *equals() and hashCode()* from the drop-down list. NetBeans then asks for the instance variables used in the methods. The methods developed by NetBeans are typically sufficient for our needs. @@ -568,27 +350,22 @@ Use NetBeans's support in creating the equals and hashCode methods until you kno - + - + The exercise template contains a class `SimpleDate`, which defines a date object based on a given day, month, and year. In this exercise you will expand the SimpleDate class with an equals method, which can tell if the dates are exactly the same. - + Create a method `public boolean equals(Object object)` for the `SimpleDate` class, which returns true if the date of the object passed to the method as a parameter is the same as the date of the object used to call the method. - + The method should work as follows: - + ```java SimpleDate d = new SimpleDate(1, 2, 2000); @@ -607,14 +384,14 @@ true - + - + Let's expand the `SimpleDate` class from the previous exercise to also have its own `hashCode` method. - + Create a method `public int hashCode()` for the `SimpleDate` class, which calculates a hash for the the SimpleDate object. Implement the calculation of the hash in way that there are as few similar hashes as possible between the years 1900 and 2100. @@ -622,9 +399,7 @@ Create a method `public int hashCode()` for the `SimpleDate` class, which calcul -

Equals and hashCode for the LicensePlate class

@@ -649,11 +424,11 @@ public class LicensePlate { } ``` - + We want to be able to save the license plates in ArrayLists and to use them as keys in a HashMap. This, as explained above, means that the `equals` and `hashcode` methods need to be overwritten, or they won't work as intended. Implement the methods `equals` and `hashCode` for the LicensePlate class. - + Example program: @@ -687,18 +462,11 @@ public static void main(String[] args) { } ``` - + Implement the methods `equals` and `hashCode`. When they are implemented correctly the example program above will print: - @@ -709,18 +477,7 @@ Jürgen -

Pairing plates with owners

@@ -732,15 +489,7 @@ Implement the class `VehicleRegistry`, which has the following methods: - `public boolean remove(LicensePlate licensePlate)` removes the license plate and attached data from the registry. The method returns true if removed successfully and false if the license plate wasn't in the registry. -

Expanded vehicle registry

diff --git a/data/part-8/4-grouping-data-using-hash-maps.md b/data/part-8/4-grouping-data-using-hash-maps.md index 092aed69b..4cbb540a9 100644 --- a/data/part-8/4-grouping-data-using-hash-maps.md +++ b/data/part-8/4-grouping-data-using-hash-maps.md @@ -4,12 +4,7 @@ title: 'Grouping data using hash maps' hidden: false --- - - You know how to use a list as a hash map's value @@ -17,20 +12,11 @@ hidden: false - -A hash map has at most one value per each key. In the following example, we store the phone numbers of people into the hash map. - - ```java HashMap phoneNumbers = new HashMap<>(); phoneNumbers.put("Pekka", "040-12348765"); @@ -41,13 +27,7 @@ phoneNumbers.put("Pekka", "09-111333"); System.out.println("Pekka's Number " + phoneNumbers.get("Pekka")); ``` - @@ -56,36 +36,20 @@ Pekka's number: 09-111333 - What if we wanted to assign multiple values ​​to a single key, such as multiple phone numbers for a given person? Since keys and values ​​in a hash map can be any variable, it is also possible to use lists as values in a hash map. You can add more values ​​to a single key by attaching a list to the key. Let's change the way the numbers are stored in the following way: - + ```java HashMap> phoneNumbers = new HashMap<>(); ``` - -Each key of the hash map now has a list attached to it. Although the new command creates a hash map, the hash map initially does not contain a single list. They need to be created separately as needed. - - ```java HashMap> phoneNumbers = new HashMap<>(); @@ -100,26 +64,17 @@ phoneNumbers.get("Pekka").add("09-111333"); System.out.println("Pekka's numbers: " + phoneNumbers.get("Pekka")); ``` - Pekka's number: [040-12348765, 09-111333] - + We define the type of the phone number as `HashMap>`. This refers to a hash map that uses a string as a key and a list containing strings as its value. As such, the values added to the hash map are concrete lists. - ```java // let's first add an empty ArrayList as the value of Pekka phoneNumbers.put("Pekka", new ArrayList<>()); @@ -127,37 +82,10 @@ phoneNumbers.put("Pekka", new ArrayList<>()); // ... ``` - -We can implement, for instance, an exercise point tracking program in a similar way. The example below outlines the `TaskTracker` class, which involves user-specific tracking of points from tasks. The user is represented as a string and the points as integers. - - ```java public class TaskTracker { private HashMap> completedExercises; @@ -185,22 +113,7 @@ public class TaskTracker { } } ``` - ```java TaskTracker tracker = new TaskTracker(); @@ -228,42 +141,31 @@ Ada: [3, 4, 3, 3] - + Your assignment is to create the class `DictionaryOfManyTranslations`. In it can be stored one or more translations for each word. The class is to implement the following methods: - + - `public void add(String word, String translation)` adds the translation for the word and preserves the old translations. - + - `public ArrayList translate(String word)` returns a list of the translations added for the word. If the word has no translations, the method should return an empty list. - + - `public void remove(String word)` removes the word and all its translations from the dictionary. - + It's probably best to add the translations to an object variable that is of the type `HashMap>` - -An example: - ```java DictionaryOfManyTranslations dictionary = new DictionaryOfManyTranslations(); @@ -278,12 +180,7 @@ dictionary.remove("bow"); System.out.println(dictionary.translate("bow")); ``` - @@ -298,41 +195,27 @@ System.out.println(dictionary.translate("bow")); - +

Adding items and examining contents

- + Your task is creating a class called `StorageFacility` that can be used to keep track of storage units and their contents. The class is to implement the following methods: - + - `public void add(String unit, String item)` adds the parameter item to the storage unit that is also given as a parameter. - -- `public ArrayList contents(String storageUnit)` returns a list that contains all the items in the storage unit indicated by the parameter. If there is no such storage unit or it contains no items, the method should return an empty list. - +- `public ArrayList contents(String storageUnit)` returns a list that contains all the items in the storage unit indicated by the parameter. If there is no such storage unit or it contains no items, the method should return an empty list. -Here's an example: - ```java StorageFacility facility = new StorageFacility(); @@ -350,12 +233,7 @@ System.out.println(facility.contents("a14")); System.out.println(facility.contents("f156")); ``` - @@ -365,46 +243,27 @@ System.out.println(facility.contents("f156")); - -

Listing the units and removing from unit

- +

Listing the units and removing from unit

-- Now the class `StorageFacility` contains the functionality to add an item to a storage unit and to list the contents of a unit. Next add the possibilities to remove an item from a storage unit and to list all the units. - -- `public void remove(String storageUnit, String item)` removes the given item from the given storage unit. NB! Only removes one item -- if there are several items with the same name, the rest still remain. If the storage unit would be empty after the removal, the method also removes the unit. +- Now the class `StorageFacility` contains the functionality to add an item to a storage unit and to list the contents of a unit. Next add the possibilities to remove an item from a storage unit and to list all the units. - -- `public ArrayList storageUnits()` returns the names of the storage units as a list. NB! Only the units that contain items are listed. - +- `public void remove(String storageUnit, String item)` removes the given item from the given storage unit. NB! Only removes one item -- if there are several items with the same name, the rest still remain. If the storage unit would be empty after the removal, the method also removes the unit. -An example: - ```java StorageFacility facility = new StorageFacility(); @@ -427,12 +286,7 @@ facility.remove("f156", "rollerblades"); System.out.println(facility.storageUnits()); ``` - @@ -441,7 +295,7 @@ System.out.println(facility.storageUnits()); - + The order of the storage units in the output may be different from this example. diff --git a/data/part-8/5-fast-data-fetching-and-grouping-information.md b/data/part-8/5-fast-data-fetching-and-grouping-information.md index bf85fe87f..5c2279a1a 100644 --- a/data/part-8/5-fast-data-fetching-and-grouping-information.md +++ b/data/part-8/5-fast-data-fetching-and-grouping-information.md @@ -4,8 +4,7 @@ title: 'Fast data fetching and grouping information' hidden: false --- - + In the eighth part we recapped the content from parts 1-7 and learned how to use hash maps. HashMap and ArrayList are some of the most used data structures in programming. The benefit of HashMaps is that looking up information by key is really fast -- this efficiency is really important for good user experience. @@ -15,10 +14,9 @@ What is more, we also learned that HashMap enables us to group data -- for examp - - + + The eighth part also started the second part of this course. If you just jumped in, welcome aboard! Finally, please take a moment to answer a self-reflective survey on the learning goals of the eighth part. diff --git a/data/part-9/1-inheritance.md b/data/part-9/1-inheritance.md index 2fc58a4bc..a43facf26 100644 --- a/data/part-9/1-inheritance.md +++ b/data/part-9/1-inheritance.md @@ -5,15 +5,7 @@ hidden: false --- - @@ -27,17 +19,17 @@ hidden: false - + Classes are used to clarify the concepts of the problem domain in object-oriented programming. Every class we create adds functionality to the programming language. This functionality is needed to solve the problems that we encounter. An essential idea behind object-oriented programming is that **solutions rise from the interactions between objects which are created from classes**. An object in object-oriented programming is an independent unit that has a state, which can be modified by using the methods that the object provides. Objects are used in cooperation; each has its own area of responsibility. For instance, our user interface classes have so far made use of `Scanner` objects. - + Every Java class extends the class Object, which means that every class we create has at its disposal all the methods defined in the Object class. If we want to change how these methods are defined in Object function, they must be overriden by defining a new implementation for them in the newly created class. The objects we create receive the methods `equals` and `hashCode`, among others, from the Object class. - + Every class derives from `Object`, but it's also possible to derive from other classes. When we examine the API (Application Programming Interface) of Java's ArrayList, we notice that `ArrayList` has the superclass `AbstractList`. `AbstractList`, in turn, has the class `Object` as its superclass. @@ -51,46 +43,21 @@ Every class derives from `Object`, but it's also possible to derive from other c - -Each class can directly extend only one class. However, a class indirectly inherits all the properties of the classes it extends. So the `ArrayList` class derives from the class `AbstractList`, and indirectly derives from the classes `AbstractCollection` and `Object`. So `ArrayList` has at its disposal all the variables and methods of the classes `AbstractList`, `AbstractCollection`, and `Object`. +Each class can directly extend only one class. However, a class indirectly inherits all the properties of the classes it extends. So the `ArrayList` class derives from the class `AbstractList`, and indirectly derives from the classes `AbstractCollection` and `Object`. So `ArrayList` has at its disposal all the variables and methods of the classes `AbstractList`, `AbstractCollection`, and `Object`. - -You use the keyword `extends` to inherit the properties of a class. The class that receives the properties is called the subclass, and the class whose properties are inherited is called the superclass. - +You use the keyword `extends` to inherit the properties of a class. The class that receives the properties is called the subclass, and the class whose properties are inherited is called the superclass. -Let's take a look at a car manufacturing system that manages car parts. A basic component of part management is the class `Part`, which defines the identifier, the manufacturer, and the description. - ```java public class Part { @@ -119,47 +86,16 @@ public class Part { } ``` - - -One part of the car is the engine. As is the case with all parts, the engine, too, has a manufacturer, an identifier, and a description. In addition, each engine has a type: for instance, an internal combustion engine, an electric motor, or a hybrid engine. - - -The traditional way to implement the class `Engine`, without using inheritance, would be this. +One part of the car is the engine. As is the case with all parts, the engine, too, has a manufacturer, an identifier, and a description. In addition, each engine has a type: for instance, an internal combustion engine, an electric motor, or a hybrid engine. - ```java public class Engine { @@ -195,30 +131,16 @@ public class Engine { ``` - -We notice a significant amount of overlap between the contents of `Engine` and `Part`. It can confidently be said the `Engine` is a special case of `Part`. **The Engine is a Part**, but it also has properties that a Part does not have, which in this case means the engine type. - +We notice a significant amount of overlap between the contents of `Engine` and `Part`. It can confidently be said the `Engine` is a special case of `Part`. **The Engine is a Part**, but it also has properties that a Part does not have, which in this case means the engine type. -Let's recreate the class `Engine` and, this time, use inheritance in our implementation. We'll create the class `Engine` which inherits the class `Part`: an engine is a special case of a part. - ```java @@ -237,30 +159,26 @@ public class Engine extends Part { } ``` - + The class definition `public class Engine extends Part` indicates that the class `Engine` inherits the functionality of the class `Part`. We also define an object variable `engineType` in the class `Engine`. - + The constructor of the Engine class is worth some consideration. On its first line we use the keyword `super` to call the constructor of the superclass. The call `super(identifier, manufacturer, description)` calls the constructor `public Part(String identifier, String manufacturer, String description)` which is defined in the class Part. Through this process the object variables defined in the superclass are initiated with their initial values. After calling the superclass constructor, we also set the proper value for the object variable `engineType`. - + *The `super` call bears some resemblance to the `this` call in a constructor; `this` is used to call a constructor of this class, while `super` is used to call a constructor of the superclass. If a constructor uses the constructor of the superclass by calling `super` in it, the `super` call must be on the first line of the constructor. This is similar to the case with calling `this` (must also be the first line of the constructor).* - + Since the class `Engine` extends the class `Part`, it has at its disposal all the methods that the class `Part` offers. You can create instances of the class `Engine` the same way you can of any other class. - + ```java Engine engine = new Engine("combustion", "hz", "volkswagen", "VW GOLF 1L 86-91"); @@ -269,12 +187,7 @@ System.out.println(engine.getManufacturer()); ``` - @@ -283,25 +196,19 @@ volkswagen - + As you can see, the class `Engine` has all the methods that are defined in the class `Part`. - + Let's practice creating and inheriting classes. - -

Creating classes

- Create the following three classes: @@ -330,10 +237,10 @@ C - +

Class inheritance

- + Modify the classes so that class B inherits class A, and class C inherits class B. In other words, class A will be a superclass for class B, and class B will be a superclass for class C. @@ -357,54 +264,37 @@ C
- + ## Access modifiers private, protected, and public - + If a method or variable has the access modifier `private`, it is visible only to the internal methods of that class. Subclasses will not see it, and a subclass has no direct means to access it. So, from the Engine class there is no way to directly access the variables identifier, manufacturer, and description, which are defined in the superclass Part. The programmer cannot access the variables of the superclass that have been defined with the access modifier private. - + A subclass sees everything that is defined with the `public` modifier in the superclass. If we want to define some variables or methods that are visible to the subclasses but invisible to everything else, we can use the access modifier `protected` to achieve this. - + ## Calling the constructor of the superclass - + You use the keyword `super` to call the constructor of the superclass. The call receives as parameters the types of values that the superclass constructor requires. If there are multiple constructors in the superclass, the parameters of the super call dictate which of them is used. - + When the constructor (of the subclass) is called, the variables defined in the superclass are initialized. The events that occur during the constructor call are practically identical to what happens with a normal constructor call. If the superclass doesn't provide a non-parameterized constructor, there must always be an explicit call to the constructor of the superclass in the constructors of the subclass. - -We demonstrate in the example below how to call `this` and `super`. The class `Superclass` includes an object variable and two constructors. One of them calls the other constructor with the `this` keyword. The class `Subclass` includes a parameterized constructor, but it has no object variables. The constructor of `Subclass` calls the parameterized constructor of the `Superclass`. +We demonstrate in the example below how to call `this` and `super`. The class `Superclass` includes an object variable and two constructors. One of them calls the other constructor with the `this` keyword. The class `Subclass` includes a parameterized constructor, but it has no object variables. The constructor of `Subclass` calls the parameterized constructor of the `Superclass`. - ```java public class Superclass { @@ -435,13 +325,7 @@ public class Subclass extends Superclass { ``` - ```java Superclass sup = new Superclass(); @@ -451,12 +335,7 @@ System.out.println(sup); System.out.println(sub); ``` - @@ -465,20 +344,15 @@ Subclass - + ## Calling a superclass method - + You can call the methods defined in the superclass by prefixing the call with `super`, just as you can call the methods defined in this class by prefixing the call with `this`. For example, when overriding the `toString` method, you can call the superclass's definition of that method in the following manner: - + ```java @Override @@ -490,20 +364,13 @@ public String toString() { - +

Person

- + Create a class `Person`. The class must work as follows: - + ```java Person ada = new Person("Ada Lovelace", "24 Maddox St. London W1S 2QN"); @@ -512,14 +379,7 @@ System.out.println(ada); System.out.println(esko); ``` - + Ada Lovelace @@ -528,29 +388,16 @@ Esko Ukkonen Mannerheimintie 15 00100 Helsinki - -

Student

- Create a class `Student`, which inherits the class `Person`. At creation, a student has 0 study credits. Every time a student studies, the amount of study credits goes up. The class must act as follows: - + ```java Student ollie = new Student("Ollie", "6381 Hollywood Blvd. Los Angeles 90028"); @@ -560,14 +407,7 @@ ollie.study(); System.out.println("Study credits "+ ollie.credits()); ``` - + Ollie @@ -577,20 +417,13 @@ Study credits 1 - +

Student's toString

- + In the previous task, `Student`inherits the toString method from the class `Person`. However, you can also overwrite an inherited method, replacing it with your own version. Write a version of toString method specifically for the `Student` class. The method must act as follows: - + ```java Student ollie = new Student("Ollie", "6381 Hollywood Blvd. Los Angeles 90028"); @@ -599,16 +432,7 @@ ollie.study(); System.out.println(ollie); ``` - + Ollie @@ -620,35 +444,16 @@ Ollie - -

Teacher

- Create a class `Teacher`, which inherits the class `Person`. The class must act as follows: - ```java Teacher ada = new Teacher("Ada Lovelace", "24 Maddox St. London W1S 2QN", 1200); @@ -666,19 +471,7 @@ while (i < 25) { System.out.println(ollie); ``` - + Ada Lovelace @@ -692,24 +485,14 @@ Ollie Study credits 25 - +

List all Persons

- + Write a method `public static void printPersons(ArrayList persons)` in the Main class. The method prints all the persons on the list given as the parameter. Method must act as follows when invoked from the `main` method: - ```java public static void main(String[] args) { @@ -721,16 +504,7 @@ public static void main(String[] args) { } ``` - + Ada Lovelace @@ -746,21 +520,16 @@ Ollie - + ## The actual type of an object dictates which method is executed - + An object's type decides what the methods provided by the object are. For instance, we implemented the class `Student` earlier. If a reference to a `Student` type object is stored in a `Person` type variable, only the methods defined in the `Person` class (and its superclass and interfaces) are available: - + ```java Person ollie = new Student("Ollie", "6381 Hollywood Blvd. Los Angeles 90028"); @@ -769,30 +538,20 @@ ollie.study(); // DOESN'T WORK! System.out.println(ollie); // ollie.toString() WORKS ``` - + So an object has at its disposal the methods that relate to its type, and also to its superclasses and interfaces. The Student object above offers the methods defined in the the classes Person and Object. - + In the last exercise we wrote a new `toString` implementation for Student to override the method that it inherits from Person. The class Person had already overriden the toString method it inherited from the class Object. If we handle an object by some other type than its actual type, which version of the object's method is called? - + In the following example, we'll have two students that we refer to by variables of different types. Which version of the toString method will be executed: the one defined in Objecct, Person, or Student? - ```java Student ollie = new Student("Ollie", "6381 Hollywood Blvd. Los Angeles 90028"); @@ -806,20 +565,7 @@ Object alice = new Student("Alice", "177 Stewart Ave. Farmington, ME 04938"); System.out.println(alice); ``` - + Ollie @@ -836,59 +582,31 @@ Alice credits 0 - -The method to be executed is chosen based on the actual type of the object, which means the class whose constructor is called when the object is created. If the method has no definition in that class, the version of the method is chosen from the class that is closest to the actual type in the inheritance hierarchy. +The method to be executed is chosen based on the actual type of the object, which means the class whose constructor is called when the object is created. If the method has no definition in that class, the version of the method is chosen from the class that is closest to the actual type in the inheritance hierarchy. - - + Regardless of the type of the variable, the method that is executed is always chosen based on the actual type of the object. Objects are polymorphic, which means that they can be used via many different variable types. The executed method always relates to the actual type of the object. This phenomenon is called polymorphism. - -Let's examine polymorphism with another example. - +Let's examine polymorphism with another example. -You could represent a point in two-dimensional coordinate system with the following class: - ```java public class Point { @@ -917,32 +635,17 @@ public class Point { ``` - + The `location` method is not meant for external use, which is why it is defined as protected. Subclasses will still be able to access the method. Manhattan distance means the distance between two points if you can only travel in the direction of the coordinate axes. It is used in many navigation algorithms, for example. - + A colored point is otherwise identical to a point, but it contains also a color that is expressed as a string. Due to the similarity, we can create a new class by extending the class Point. - ```java public class ColorPoint extends Point { @@ -961,29 +664,15 @@ public class ColorPoint extends Point { } ``` - + The class defines an object variable in which we store the color. The coordinates are already defined in the superclass. We want the string representation to be the same as the Point class, but to also include information about the color. The overriden `toString` method calls the `toString` method of the superclass and adds to it the color of the point. - + Next, we'll add a few points to a list. Some of them are "normal" while others are color points. At the end of the example, we'll print the points on the list. For each point, the toString to be executed is determined by the actual type of the point, even though the list knows all the points by the `Point` type. - ```java public class Main { @@ -1001,12 +690,7 @@ public class Main { } ``` - + (4, 8) distance 12 @@ -1015,38 +699,11 @@ public class Main { (0, 0) distance 0 - - -We also want to include a three-dimensional point in our program. Since it has no color information, let's derive it from the class `Point`. - ```java public class Point3D extends Point { @@ -1077,29 +734,12 @@ public class Point3D extends Point { } ``` - - -So a three-dimensional point defines an object variable that represents the third dimension, and overrides the methods `location`, `manhattanDistanceFromOrigin`, and `toString` so that they also account for the third dimension. Let's now expand the previous example and add also three-dimensional points to the list. - ```java public class Main { @@ -1120,15 +760,7 @@ public class Main { } ``` - @@ -1140,32 +772,12 @@ public class Main { - - -We notice that the `toString` method in Point3D is exactly the same as the toString of Point. Could we save some effort and not override toString? The answer happens to be yes! The Point3D class is refined into this: - - ```java public class Point3D extends Point { @@ -1189,20 +801,13 @@ public class Point3D extends Point { } ``` - + What happens in detail when we call the toString method of a three-dimensional point? The execution advances in the following manner. - + 1. Look for a definition of toString in the class Point3D. It does not exist, so the superclass is next to be examined. @@ -1216,7 +821,7 @@ What happens in detail when we call the toString method of a three-dimensional p * Again, the method calls the similarly named method of the superclass during its execution - + As we can see, the sequence of events caused by the method call has multiple steps. The principle, however, is clear: The definition for the method is first searched for in the class definition of the actual type of the object. If it is not found, we next examine the superclass. If the definition cannot be found there, either, we move on to the superclass of this superclass, etc... @@ -1227,64 +832,41 @@ As we can see, the sequence of events caused by the method call has multiple ste - + ## When is inheritance worth using? - + Inheritance is a tool for building and specializing hierarchies of concepts; a subclass is always a special case of the superclass. If the class to be created is a special case of an existing class, this new class could be created by extending the existing class. For example, in the previously discussed car part scenario an engine **is** a part, but an engine has extra functionality that not all parts have. - + When inheriting, the subclass receives the functionality of the superclass. If the subclass doesn't need or use some of the inherited functionality, inheritance is not justifiable. Classes that inherit will inherit all the methods and interfaces from the superclass, so the subclass can be used in place of the superclass wherever the superclass is used. It's a good idea to keep the inheritance hierarchy shallow, since maintaining and further developing the hierarchy becomes more difficult as it grows larger. Generally speaking, if your inheritance hierarchy is more than 2 or 3 levels deep, the structure of the program could probably be improved. - + Inheritance is not useful in every scenario. For instance, extending the class `Car` with the class `Part` (or `Engine`) would be incorrect. A car **includes** an engine and parts, but an engine or a part is not a car. More generally, **if an object owns or is composed of other objects, inheritance should not be used**. - + When using inheritance, you should take care to ensure that the Single Responsibility Principle holds true. There should only be one reason for each class to change. If you notice that inheriting adds more responsibilities to a class, you should form multiple classes of the class.
- -### Example of misusing inheritance - - - -Let's consider a postal service and some related classes. `Customer` includes the information related to a customer, and the class `Order` that inherits from the `Customer` class and includes the information about the ordered item. The class `Order` also has a method called `postalAddress` which represents the postal address that the order is shipped to. +### Example of misusing inheritance - ```java public class Customer { @@ -1311,31 +893,7 @@ public class Customer { } ``` - ```java public class Order extends Customer { @@ -1364,51 +922,26 @@ public class Order extends Customer { ``` - -Above inheritance is not used correctly. When inheriting, the subclass must be a special case of the superclass; an order is definitely not a special case of a customer. The misuse shows itself in how the code breaks the single responsibility principle: the `Order` class is responsible both for maintaining the customer information and the order information. +Above inheritance is not used correctly. When inheriting, the subclass must be a special case of the superclass; an order is definitely not a special case of a customer. The misuse shows itself in how the code breaks the single responsibility principle: the `Order` class is responsible both for maintaining the customer information and the order information. - -The problem becomes very clear when we think of what a change in a customer's address would cause. - +The problem becomes very clear when we think of what a change in a customer's address would cause. -In the case that an address changes, we would have to change *every* order object that relates to that customer. This is hardly ideal. A better solution would be to encapsulate the customer as an object variable of the `Order` class. Thinking more closely on the semantics of an order, this seems intuitive. *An order has a customer*. - -Let's modify the `Order` class so that it includes a reference to a `Customer` object. +In the case that an address changes, we would have to change *every* order object that relates to that customer. This is hardly ideal. A better solution would be to encapsulate the customer as an object variable of the `Order` class. Thinking more closely on the semantics of an order, this seems intuitive. *An order has a customer*. - ```java public class Order { @@ -1437,76 +970,70 @@ public class Order { } ``` - + This version of the `Order` class is better. The method `postalAddress` uses the *customer* reference to obtain the postal address instead of inheriting the class `Customer`. This helps both the maintenance of the program and its concrete functionality. - + Now, when a customer changes, all you need to do is change the customer information; there is no need to change the orders. - + The exercise template contains a class `Warehouse`, which has the following constructors and methods: - + - **public Warehouse(double capacity)** - Creates an empty warehouse, which has the capacity provided as a parameter; an invalid capacity (<=0) creates a useless warehouse, with the the capacity 0. - + - **public double getBalance()** - Returns the balance of the warehouse, i.e. the capacity which is taken up by the items in the warehouse. - + - **public double getCapacity()** - Returns the total capacity of the warehouse (i.e. the one that was provided in the constructor). - + - **public double howMuchSpaceLeft()** - Returns a value telling how much space is left in the warehouse. - + - **public void addToWarehouse(double amount)** - Adds the desired amount to the warehouse; if the amount is negative, nothing changes, and if everything doesn't fit, then the warehouse is filled up and the rest is "thrown away" / "overflows". - + - **public double takeFromWarehouse(double amount)** - Take the desired amount from the warehouse. The method returns much we actually **get**. If the desired amount is negative, nothing changes and we return 0. If the desired amount is greater than the amount the warehouse contains, we get all there is to take and the warehouse is emptied. - + - **public String toString()** - Returns the state of the object represented as a string like this `balance = 64.5, space left 123.5` - + In this exercise we build variations of a warehouse based on the `Warehouse` class. - +

Product warehouse, step 1

- + The class `Warehouse` handles the functions related to the amount of a product. Now we want a product name for the product and a way to handle the name. **Let's write ProductWarehouse as a subclass of Warehouse!** First, we'll just create a private object variable for the product name, a constructor, and a getter for the name field: - + - **public ProductWarehouse(String productName, double capacity)** - Creates an empty product warehouse. The name of the product and the capacity of the warehouse are provided as parameters. - + - **public String getName()** - Returns the name of the product. - + *Remind yourself of how a constructor can run the constructor of the superclass as its first action!* - + Example usage: - + ```java ProductWarehouse juice = new ProductWarehouse("Juice", 1000.0); @@ -1516,10 +1043,7 @@ System.out.println(juice.getName()); // Juice System.out.println(juice); // balance = 988.7, space left 11.3 ``` - + @@ -1530,42 +1054,35 @@ balance = 988.7, space left 11.3 - +

Product warehouse, step 2

- + As we can see from the previous example, the `toString()` inherited by the ProductWarehouse object doesn't (obviously!) know anything about the product name. *Something must be done!* Let's also add a setter for the product name while we're at it: - + - **public void setName(String newName)** - sets a new name for the product. - + - **public String toString()** - Returns the state of the object represented as a string like this `Juice: balance = 64.5, space left 123.5` - + The new `toString()` method could be written using the getters inherited from the superclass, which would give access to values of inherited, but still hidden fields. However, the superclass already has the desired functionality to provide a string representation of the warehouse state, so why bother recreating that functionality? Just take advantage of the inherited `toString()`. - + *Remind yourself of how to call an overridden method in a subclass!* - + Usage example: - + ```java ProductWarehouse juice = new ProductWarehouse("Juice", 1000.0); @@ -1576,12 +1093,7 @@ juice.addToWarehouse(1.0); System.out.println(juice); // Juice: balance = 989.7, space left 10.299999999999955 ``` - @@ -1592,102 +1104,89 @@ Juice: balance = 989.7, space left 10.299999999999955 - +

Change History, step 1

- + Sometimes it might be useful to know how the inventory of a product changes over time: Is the inventory often low? Are we usually at the limit? Are the changes in inventory big or small? Etc. Thus we should give the `ProductWarehouse` class the ability to remember the changes in the amount of a product. - + Let's begin by creating a tool that aids in the desired functionality. - + The storing of the change history could of course have been done using an `ArrayList` object in the class *ProductWarehouse*, however, we want our own *specialized tool* for this purpose. The tool should be implemented by encapsulating the `ArrayList` object. - + Public constructors and methods of the `ChangeHistory` class: - + - **public ChangeHistory()** creates an empty `ChangeHistory` object. - + - **public void add(double status)** adds provided status as the latest amount to remember in the change history. - + - **public void clear()** empties the history. - + - **public String toString()** returns the string representation of the change history. *The string representation provided by the ArrayList class is sufficient.* - +

Change History, step 2

- + Build on the `ChangeHistory` class by adding analysis methods: - + - **public double maxValue()** returns the largest value in the change history. If the history is empty, the method should return zero. - + - **public double minValue()** returns the smallest value in the change history. If the history is empty, the method should return zero. - + - **public double average()** returns the average of the values in the change history. If the history is empty, the method should return zero. - + The methods should not modify the order of the encapsulated list. - +

Product warehouse with history, step 1

- + Implement `ProductWarehouseWithHistory` as a subclass of `ProductWarehouse`. In addition to all the previous features this new warehouse also provides services related to the change history of the warehouse inventory. The history is managed using the `ChangeHistory` object. - + Public constructors and methods: - - + + - **public ProductWarehouseWithHistory(String productName, double capacity, double initialBalance)** creates a product warehouse. The product name, capacity, and initial balance are provided as parameters. Set the initial balance as the initial balance of the warehouse, as well as the first value of the change history. - + - **public String history()** returns the product history like this `[0.0, 119.2, 21.2]`. Use the string representation of the ChangeHistory object as is. - + **NB** in this initial version the history is not yet working properly; currently it only remembers the initial balance. - -Usage example: +Usage example: - ```java // the usual: @@ -1704,11 +1203,7 @@ System.out.println(juice.history()); // [1000.0] // so we only get the initial state of the history set by the constructor... ``` - + @@ -1718,38 +1213,26 @@ Juice: balance = 989.7, space left 10.299999999999955 - +

Product warehouse with history, step 2

- + *It's time to make history!* The first version didn't know anything but the initial state of the history. Expand the class with the following methods - + - **public void addToWarehouse(double amount)** works just like the method in the `Warehouse` class, but we also record the changed state to the history. **NB:** the value recorded in the history should be the warehouse's balance after adding, not the amount added! - + - **public double takeFromWarehouse(double amount)** works just like the method in the `Warehouse` class, but we also record the changed state to the history. **NB:** the value recorded in the history should be the warehouse's balance after removing, not the amount removed! - -Usage example: +Usage example: - ```java // the usual: @@ -1765,11 +1248,7 @@ System.out.println(juice); // Juice: balance = 989.7, space left 10.3 System.out.println(juice.history()); // [1000.0, 988.7, 989.7] ``` - + @@ -1779,35 +1258,28 @@ Juice: balance = 989.7, space left 10.299999999999955 - + *Remember how an overriding method can take advantage of the overridden method!* - +

Product warehouse with history, step 3

- + Expand the class with the method - + - **public void printAnalysis()**, which prints history related information for the product in the way presented in the example. - + Usage example: - ```java ProductWarehouseWithHistory juice = new ProductWarehouseWithHistory("Juice", 1000.0, 1000.0); @@ -1818,15 +1290,7 @@ juice.addToWarehouse(1.0); juice.printAnalysis(); ``` - @@ -1843,40 +1307,25 @@ Average: 992.8
- + ## Abstract classes - + Sometimes, when planning a hierarchy of inheritance, there are cases when there exists a clear concept, but that concept is not a good candidate for an object in itself. The concept would be beneficial from the point of view of inheritance, since it includes variables and functionality that are shared by all the classes that would inherit it. On the other hand, you should not be able to create instances of the concept itself. - -An abstract class combines interfaces and inheritance. You cannot create instances of them -- you can only create instances of subclasses of an abstract class. They can include normal methods which have a method body, but it's also possible to define abstract methods that only contain the method definition. Implementing the abstract methods is the responsibility of subclasses. Generally, abstract classes are used in situations where the concept that the class represents is not a clear independent concept. In such a case you shouldn't be able to create instances of it. - +An abstract class combines interfaces and inheritance. You cannot create instances of them -- you can only create instances of subclasses of an abstract class. They can include normal methods which have a method body, but it's also possible to define abstract methods that only contain the method definition. Implementing the abstract methods is the responsibility of subclasses. Generally, abstract classes are used in situations where the concept that the class represents is not a clear independent concept. In such a case you shouldn't be able to create instances of it. -To define an abstract class or an abstract method the keyword `abstract` is used. An abstract class is defined with the phrase `public abstract class *NameOfClass*`; an abstract method is defined by `public abstract returnType nameOfMethod`. Let's take a look at the following abstract class called `Operation`, which offers a structure for operations and executing them. - ```java public abstract class Operation { @@ -1895,29 +1344,12 @@ public abstract class Operation { } ``` - + The abstract class `Operation` works as a basis for implementing different actions. For instance, you can implement the plus operation by extending the `Operation` class in the following manner. - ```java public class PlusOperation extends Operation { @@ -1938,7 +1370,7 @@ public class PlusOperation extends Operation { } ``` - + Since all the classes that inherit from `Operation` have also the type `Operation`, we can create a user interface by using `Operation` type variables. Next we'll show the class `UserInterface` that contains a list of operations and a scanner. It's possible to add operations to the UI dynamically. @@ -1993,17 +1425,12 @@ public class UserInterface { ``` - + The user interface works like this: - ```java UserInterface userInterface = new UserInterface(new Scanner(System.in)); @@ -2012,22 +1439,7 @@ userInterface.addOperation(new PlusOperation()); userInterface.start(); ``` - @@ -2047,32 +1459,17 @@ Choice: **0** - + The greatest difference between interfaces and abstract classes is that abstract classes can contain object variables and constructors in addition to methods. Since you can also define functionality in abstract classes, you can use them to define e.g. default behavior. In the user interface above storing the name of the operation used the functionality defined in the abstract `Operation` class. - -In the exercise template you'll find the classes `Item` and `Box`. `Box` is an abstract class, where adding multiple items is implemented by repeatedly calling the `add`-method. The `add`-method, meant for adding a single item, is abstract, so every class that inherits it, must implement it. Your assignment is to edit the `Box`-class and to implement different kinds of boxes based on the `Box` class. - - - ```java import java.util.ArrayList; @@ -2091,17 +1488,8 @@ public abstract class Box { ``` - -

Editing the Item class

Implement the `equals` and `hashCode` methods for the `Item`-class. They are needed, so that you can use the `contains`-methods of different lists and collections. Implement the methods in such a way that value of the `weight` instance variable of the `Item`-class isn't considered. *It's probably a good idea to make use of Netbeans's functionality to implement the `equals` and `hashCode` methods* @@ -2110,16 +1498,7 @@ Implement the `equals` and `hashCode` methods for the `Item`-class. They are nee Implement the class `BoxWithMaxWeight`, that inherits the `Box` class. BoxWithMaxWeight has a constructor `public BoxWithMaxWeight(int capacity)`, that defines the max weight allowed for that box. You can add an item to a BoxWithMaxWeight when and only when, adding the item won't cause the boxes maximum weight capacity to be exceeded. - ```java BoxWithMaxWeight coffeeBox = new BoxWithMaxWeight(10); coffeeBox.add(new Item("Saludo", 5)); @@ -2141,25 +1520,15 @@ false
- -

One item box and the misplacing box

Next, implement the class `OneItemBox`, that inherits the `Box` class. `OneItemBox` has the constructor `public OneItemBox()`, and it has the capacity of exactly one item. If there is already an item in the box, it must not be switched. The weight of the item added to the box is irrelevant. - ```java OneItemBox box = new OneItemBox(); box.add(new Item("Saludo", 5)); @@ -2176,18 +1545,11 @@ false
- + Next implement the class `MisplacingBox`, that inherits the `Box`-class. MisplacingBox has a constructor `public MisplacingBox()`. You can add any items to a misplacing box, but items can never be found when looked for. In other words adding to the box must always succeed, but calling the method `isInBox` must always return false. - ```java MisplacingBox box = new MisplacingBox(); box.add(new Item("Saludo", 5)); diff --git a/data/part-9/2-interfaces.md b/data/part-9/2-interfaces.md index fe184b532..5fc1001e3 100644 --- a/data/part-9/2-interfaces.md +++ b/data/part-9/2-interfaces.md @@ -7,10 +7,7 @@ hidden: false - + - You're familiar with the concept of an interface, can define your own interfaces, and implement an interface in a class. - You know how to use interfaces as variable types, method parameters and method return values. - You're aware of some of the interfaces that come with Java. @@ -18,53 +15,27 @@ hidden: false - + We can use interfaces to define behavior that's required from a class, i.e., its methods. They're defined the same way that regular Java classes are, but "`public interface ...`" is used instead of "`public class ... `" at the beginning of the class. Interfaces define behavior through method names and their return values. However, they don't always include the actual implementations of the methods. A visibility attribute on interfaces is not marked explicitly as they're always `public`. Let's examine a *Readable* interface that describes readability. - + ```java public interface Readable { String read(); } ``` - - The `Readable` interface declares a `read()` method, which returns a String-type object. Readable defines certain behavior: for example, a text message or an email may be readable. The classes that implement the interface decide *how* the methods defined in the interface are implemented. A class implements the interface by adding the keyword *implements* after the class name followed by the name of the interface being implemented. Let's create a class called `TextMessage` that implements the `Readable` interface. - ```java public class TextMessage implements Readable { private String sender; @@ -86,22 +57,14 @@ public class TextMessage implements Readable { ``` - - -Since the `TextMessage` class implements the `Readable` interface (`public class TextMessage implements Readable`), the `TextMessage` class *must* contain an implementation of the `public String read()` method. Implementations of methods defined in the interface must always have public as their visibility attribute. - - When a class implements an interface, it signs an agreement. The agreement dictates that the class will implement the methods defined by the interface. If those methods are not implemented in the class, the program will not function. @@ -110,45 +73,12 @@ The interface defines only the names, parameters, and return values ​​of the - - -In addition to the `TextMessage` class, let's add another class that implements the `Readable` interface. The `Ebook` class is an electronic implementation of a book that containing the title and pages of a book. The ebook is read page by page, and calling the `public String read()` method always returns the next page as a string. - - - ```java public class Ebook implements Readable { private String name; @@ -184,17 +114,11 @@ public class Ebook implements Readable { } ``` - + Objects can be instantiated from interface-implementing classes just like with normal classes. They're also used in the same way, for instance, as an ArrayList's type. - ```java TextMessage message = new TextMessage("ope", "It's going great!"); System.out.println(message.read()); @@ -203,32 +127,14 @@ ArrayList textMessage = new ArrayList<>(); textMessage.add(new TextMessage("private number", "I hid the body."); ``` - It's going great! - ```java ArrayList pages = new ArrayList<>(); pages.add("Split your method into short, readable entities."); @@ -245,14 +151,7 @@ while (page < book.pages()) { } ``` - Split your method into short, readable entities. @@ -265,11 +164,7 @@ Practice makes the master. Try different out things for yourself and work on you - In the exercise template you'll find Interface `TacoBox` ready for your use. It has the following methods: @@ -278,12 +173,7 @@ In the exercise template you'll find Interface `TacoBox` ready for your use. It - the method `void eat()` reduces the number of tacos remaining by one. The number of tacos remaining can't become negative. - + ```java public interface TacoBox { int tacosRemaining(); @@ -292,16 +182,7 @@ public interface TacoBox { ``` -

Triple taco box

@@ -317,48 +198,31 @@ Implement the class `CustomTacoBox`, that implements the `TacoBox` interface. `C - + ## Interface as Variable Type - + The type of a variable is always stated as its introduced. There are two kinds of type, the primitive-type variables (int, double, ...) and reference-type variables (all objects). We've so far used an object's class as the type of a reference-type variable. - + ```java String string = "string-object"; TextMessage message = new TextMessage("ope", "many types for the same object"); ``` - + An object's type can be other than its class. For example, the type of the `Ebook` class that implements the `Readable` interface is both `Ebook` and `Readable`. Similarly, the text message also has multiple types. Because the `TextMessage` class implements the `Readable` interface, it has a `Readable` type in addition to the `TextMessage` type. - + ```java TextMessage message = new TextMessage("ope", "Something cool's about to happen); Readable readable = new TextMessage("ope", "The text message is Readable!"); ``` - ```java ArrayList pages = new ArrayList<>(); pages.add("A method can call itself."); @@ -372,28 +236,10 @@ while (page < book.pages()) { } ``` - -Because an interface can be used as a type, it's possible to create a list that contains objects of the interface's type. - - ```java ArrayList readingList = new ArrayList<>(); @@ -415,16 +261,10 @@ for (Readable readable: readingList) { ``` - + Note that although the `Ebook` class that inherits the `Readable` interface class is always of the interface's type, not all classes that implement the `Readable` interface are of type `Ebook`. You can assign an object created from the `Ebook` class to a `Readable`-type variable, but it does not work the other way without a separate type conversion. - ```java Readable readable = new TextMessage("ope", "TextMessage is Readable!"); // works TextMessage message = readable; // doesn't work @@ -432,23 +272,17 @@ TextMessage message = readable; // doesn't work TextMessage castMessage = (TextMessage) readable; // works if, and only if, readable is of text message type ``` - + Type conversion succeeds if, and only if, the variable is of the type that it's being converted to. Type conversion is not considered good practice, and one of the few situation where it's use is appropriate is in the implementation of the `equals` method. - + ## Interfaces as Method Parameters - + The true benefits of interfaces are reaped when they are used as the type of parameter provided to a method. Since an interface can be used as a variable's type, it can also be used as a parameter type in method calls. For example, the `print` method in the `Printer` class of the class below gets a variable of type `read`. - + ```java public class Printer { public void print(Readable readable) { @@ -458,21 +292,11 @@ public class Printer { ``` - -The value of the `print` method of the `printer` class lies in the fact that it can be given *any* class that implements the `Readable` interface as a parameter. Were we to call the method with any object instantiated from a class that inherits the Readable class, the method would function as desired. +The value of the `print` method of the `printer` class lies in the fact that it can be given *any* class that implements the `Readable` interface as a parameter. Were we to call the method with any object instantiated from a class that inherits the Readable class, the method would function as desired. - ```java TextMessage message = new TextMessage("ope", "Oh wow, this printer knows how to print these as well!"); @@ -485,12 +309,7 @@ printer.print(message); printer.print(book); ``` - Oh wow, this printer knows how to print these as well! @@ -498,27 +317,11 @@ Values common to both {1, 3, 5} and {2, 3, 4, 5} are {3, 5}. - -Let's make another class called `ReadingList` to which we can add interesting things to read. The class has an `ArrayList` instance as an instance variable, where the things to be read are added. Adding to the reading list is done using the `add` method, which receives a `Readable`-type object as its parameter. - - ```java public class ReadingList { private ArrayList readables; @@ -538,38 +341,10 @@ public class ReadingList { ``` - -Reading lists are usually readable, so let's have the `ReadingList` class implement the `Readable` interface. The `read` method of the reading list reads all the objects in the `readables` list, and adds them to the string returned by the `read()` method one-by-one. - - ```java public class ReadingList implements Readable { private ArrayList readables; @@ -601,13 +376,7 @@ public class ReadingList implements Readable { ``` - ```java ReadingList jonisList = new ReadingList(); jonisList.add(new TextMessage("arto", "have you written the tests yet?")); @@ -616,41 +385,19 @@ jonisList.add(new TextMessage("arto", "have you checked the submissions yet?")); System.out.println("Joni's to-read: " + jonisList.toRead()); ``` - Joni's to-read: 2 - - -Because the `ReadingList` is of type `Readable`, we're able to add `ReadingList` objects to the reading list. In the example below, Joni has a lot to read. Fortunately for him, Verna comes to the rescue and reads the messages on Joni's behalf. - ```java ReadingList jonisList = new ReadingList(); int i = 0; @@ -680,11 +427,8 @@ Joni's to-read:0
- - The `read` method called on Verna's list goes through all the `Readable` objects and calls the `read` method on them. When the `read` method is called on Verna's list it also goes through Joni's reading list that's included in Verna's reading list. Joni's reading list is run through by calling its `read` method. At the end of each `read` method call, the read list is cleared. In this way, Joni's reading list empties when Verna reads it. @@ -696,7 +440,7 @@ As you notice, the program already contains a lot of references. It's a good ide

Packables

- + Moving houses requires packing all your belongings into boxes. Let's imitate that with a program. The program will have boxes, and items to pack into those boxes. All items must implement the following Interface: @@ -707,14 +451,14 @@ public interface Packable { ``` - + Add the Interface to your program. Adding a new Interface is quite similar to adding a new class. Instead of selecting new Java class just select new Java interface. - + Create classes `Book` and `CD`, which implement the Interface. Book has a constructor which is given the author (String), name of the book (String), and the weight of the book (double) as parameters. CD has a constructor which is given the artist (String), name of the CD (String), and the publication year (int). The weight of all CDs is 0.1 kg. - + Remember to implement the Interface `Packable` in both of the classes. The classes must work as follows: @@ -738,7 +482,7 @@ public static void main(String[] args) { ``` - + Prints: @@ -754,17 +498,17 @@ Rendezvous Park: Closer to Being Here (2012)
- + NB: The weight is not printed

Box

- + Make a class called `Box`. Items implementing the `Packable` interface can be packed into a box. The `Box` constructor takes the maximum capacity of the box in kilograms as a parameter. The combined weight of all items in a box cannot be more than the maximum capacity of the box. - + Below is an example of using a box: @@ -785,24 +529,24 @@ public static void main(String[] args) { ``` - + Prints - + Box: 6 items, total weight 4.0 kg - + NB: As the weights are saved as a double, the calculations might have some small rounding errors. You don't need to worry about them.

Box weight

- + If you made an class variable `double weight` in the Box class, replace it with a method which calculates the weight of the box: ```java @@ -818,24 +562,24 @@ public class Box { ``` - + When you need the weight of the box, for example when adding a new item to the box, you can just call the weight method. - + The method could also return the value of an object variable. However here we are practicing a situation, where we do not have to maintain an object variable explicitly, but can calculate its value as needed. After the next exercise storing the weight as an object variable would not necessary work anyway. After completing the exercise have a moment to think why that is.

A Box is packable too!

- + Implementing the `Packable` Interface requires a class to have the method `double weight()`. We just added this method to the Box class. This means we can make the Box packable as well! - + Boxes are objects, which can contain objects implementing the `packable` Interface. Boxes implement this Interface as well. So **a box can contain other boxes!** - + Try this out. Make some boxes containing some items, and add some smaller boxes to a bigger box. Try what happens, when you put a box in itself. Why does this happen? @@ -844,46 +588,17 @@ Try this out. Make some boxes containing some items, and add some smaller boxes - -## Interface as a return type of a method +## Interface as a return type of a method - -Interfaces can be used as return types in methods -- just like regular variable types. In the next example is a class `Factory` that can be asked to construct differerent objects that implement the `Packable` interface. - ```java import java.util.Random; @@ -944,20 +659,12 @@ public class Packer { } ``` - + Because the packer does not know the classes that implement the interface `Packable`, one can add new classes that implement the interface without changing the packer. The next example creates a new class that implements the Packable interface `ChocolateBar`. The factory has been changed so that it creates chocolate bars in addition to books and CDs. The class `Packer` works without changes with the updated version of the factory. - ```java public class ChocolateBar implements Packable { @@ -970,31 +677,7 @@ public class ChocolateBar implements Packable { } ``` - ```java import java.util.Random; @@ -1026,13 +709,7 @@ public class Factory { - @@ -1044,58 +721,52 @@ Using interfaces in programming enables reducing dependencies between classes. I ## Built-in Interfaces - +

Java offers a considerable amount of built-in interfaces. Here we'll get familiar with four commonly used interfaces: List, Map, Set, and Collection.


- + ### The List Interface - +

The List interface defines the basic functionality related to lists. Because the ArrayList class implements the `List` interface, one can also use it through the `List` interface.


- + ```java List strings = new ArrayList<>(); strings.add("string objects inside an arraylist object!"); ``` - +

As we can see fom the Java API of List, there are many classes that implement the `List` interface. One list that is familiar to computer scientists is a linked list. A linked list can be used through the List interface exactly the same way as an object created from ArrayList.


- + ```java List strings = new LinkedList<>(); strings.add("string objects inside a linkedlist object!"); ``` - + From the perspective of the user, both implementations of the `List` interface work the same way. The interface *abstracts* their inner functionality. The internal structures of `ArrayList` and `LinkedList` differ quite a bit. ArrayList saves objects to an array where fetching an object with a specific index is very fast. On the other hand LinkedList constructs a list where each element contains a reference to the next element in the list. When one searches for an object by index in a linked list, one has to go though the list from the beginning until the index. - + One can see noticeable performcance differences between list implementations if the lists are big enough. The strength of a linked list is that adding to it is always fast. ArrayList, on the other hand, is backed by an array, which needs to be resized each time it gets full. Resizing the array requires creating a new array and copying the values from the old array to the new one. On the other hand, searching objects by index is much faster in an array list compared to a linked list. - + For the problems that you encounter during this course you should almost always choose ArrayList. However, "interface programming" is beneficial: implement your programs so that you'll use the data structures through the interfaces. @@ -1103,11 +774,11 @@ For the problems that you encounter during this course you should almost always - + In the mainProgram class, implement a class method `returnSize`, which is given a List-object as a parameter, and returns the size of the list as an integer. - + The method should work as follows: @@ -1130,20 +801,16 @@ System.out.println(returnSize(names)); - + ### The Map Interface - + The Map interface defines the basic behavior associated with hash tables. Because the HashMap class implements the `Map` interface, it can also be accessed through the `Map` interface.
- + ```java Map maps = new HashMap<>(); @@ -1151,18 +818,10 @@ maps.put("ganbatte", "good luck"); maps.put("hai", "yes"); ``` - + The keys to the hash table are obtained using the `keySet` method. - ```java Map maps = new HashMap<>(); @@ -1174,12 +833,7 @@ for (String key : maps.keySet()) { } ``` - ganbatte: good luck @@ -1188,17 +842,17 @@ hai: yes - + The `keySet` method returns a set of elements that implement the `Set` interface. You can use a for-each statement to go through a set that implements the `Set` interface. The hash values can be obtained from the hash table using the `values` method. The `values` method returns a set of elements that implement the `Collection` interface. Let's take a quick look at the `Set` and `Collection` interfaces. - + In the class MainProgram implement a class method `returnSize` which gets a Map-object as a parameter, and returns its size as an integer. - + The method should work as follows: ```java @@ -1218,26 +872,17 @@ System.out.println(returnSize(names)); - + ### The Set Interface - + The Set interface describes functionality related to sets. In Java, sets always contain either 0 or 1 amounts of any given object. As an example, the set interface is implemented by HashSet. Here's how to go through the elements of a set.
- ```java Set set = new HashSet<>(); set.add("one"); @@ -1249,12 +894,7 @@ for (String element: set) { } ``` - one @@ -1263,29 +903,18 @@ two - + Note that HashSet in no way assumes the order of a set of elements. If objects created from custom classes are added to the HashSet object, they must have both the `equals` and `hashCode` methods defined. - In the Main-class, implement the static method `returnSize`, which receives a Set object as a parameter and returns its size. The method should work e.g. like this: - ```java Set names = new HashSet<>(); name.add("first"); @@ -1298,7 +927,7 @@ System.out.println(returnSize(names)); ``` - + Prints: @@ -1311,43 +940,23 @@ Prints: - + ### The Collection Interface - + The Collection interface describes functionality related to collections. Among other things, lists and sets are categorized as collections in Java -- both the List and Set interfaces implement the Collection interface. The Collection interface provides, for instance, methods for checking the existence of an item (the method `contains`) and determining the size of a collection (the method `size`).
- -The Collection interface also determines how the collection is iterated over. Any class that implements the Collection interface, either directly or indirectly, inherits the functionality required for a `for-each` loop. - - -Let's create a hash table and iterate over its keys and values. +The Collection interface also determines how the collection is iterated over. Any class that implements the Collection interface, either directly or indirectly, inherits the functionality required for a `for-each` loop. - ```java Map translations = new HashMap<>(); translations.put("ganbatte", "good luck"); @@ -1370,17 +979,7 @@ for (String value: values) { } ``` - Keys: @@ -1394,28 +993,14 @@ good luck - + In the next exercise, we build functionality realted to e-commerce and practice using classes through the their interfaces. - In this exercise we'll create program components, that can used to run an online store. @@ -1429,16 +1014,7 @@ Create the class `Warehouse` with the following methods: The products in the warehouse (and in the next part their stock) must be stored in a variable of the type `Map`! The object created can be a HashMap, but its type must be the Map-interface, rather than any implementation of that interface. - ```java Warehouse warehouse = new Warehouse(); warehouse.addProduct("milk", 3, 10); @@ -1450,16 +1026,9 @@ System.out.println("coffee: " + warehouse.price("coffee")); System.out.println("sugar: " + warehouse.price("sugar")); ``` - -Prints: - @@ -1471,17 +1040,7 @@ sugar: -99 -

Products stock balance

Save the stock balance of products in a variable with the `Map` type, in the same way the prices were stored. Supplement the warehouse with the following methods: @@ -1490,22 +1049,7 @@ Save the stock balance of products in a variable with the `Map` - `public boolean take(String product)` reduces the stock remaining for the product it received as a parameter by one, and returns true if there was stock remaining. If the product was not available in the warehouse the method returns false. A products stock can't go below zero. An example of the warehouse in use: - + ```java Warehouse warehouse = new Warehouse(); warehouse.addProduct("coffee", 5, 1); @@ -1523,21 +1067,9 @@ System.out.println("coffee: " + warehouse.stock("coffee")); System.out.println("sugar: " + warehouse.stock("sugar")); ``` - -Prints: - @@ -1554,19 +1086,7 @@ sugar: 0 -

Listing the products

Let's add one more method to the warehouse: @@ -1576,19 +1096,7 @@ Let's add one more method to the warehouse: This method is easy to implement with HashMap. You can get the products in the warehouse from either the Map storing the prices or the one storing current stock, by using the method `keySet()` An example use case: - ```java Warehouse warehouse = new Warehouse(); warehouse.addProduct("milk", 3, 10); @@ -1603,15 +1111,7 @@ for (String product: warehouse.products()) { } ``` - @@ -1624,22 +1124,7 @@ milk -

Item

*Items* can be added to the shopping cart (which we'll add soon). An item is a product with a quantity. You for example add an item representing one bread to the cart, or add an item representing 24 coffees. @@ -1652,13 +1137,7 @@ Create the class `Item` with the following methods: - `public String toString()` returns the string representation of the item. which must match the format shown in the example below. An example of the Item class being used: - + ```java Item item = new Item("milk", 4, 2); @@ -1668,13 +1147,7 @@ item.increaseQuantity(); System.out.println(item); ``` - @@ -1685,30 +1158,11 @@ milk: 5 - -NB: The *toString* is formatted like this: *product: qty* -- price is not included in the string representation. - - -

Shopping cart

@@ -1723,15 +1177,7 @@ First let's give `ShoppingCart` a constructor with no parameters and these metho - `public void add(String product, int price)` adds an item to the cart that matches the product given as a parameter, with the price given as a parameter. - `public int price()` returns the total price of the shopping cart. - + ```java ShoppingCart cart = new ShoppingCart(); cart.add("milk", 3); @@ -1742,12 +1188,7 @@ cart.add("computer", 899); System.out.println("cart price: " + cart.price()); ``` - @@ -1757,24 +1198,13 @@ cart price: 909 -

Printing the cart

Implement the method `public void print()` for the shopping cart. The method prints the *Item-objects* in the cart. The order they are printed in is irrelevant. E.g the print of the cart in the previous example would be: - buttermilk: 1 @@ -1785,40 +1215,17 @@ milk: 1 - -NB: the number printed is the quantity in the cart, not the price! - - -

One item per product

Let's change our cart so that if a product is being added thats already in the cart, we don't add a new item, but instead update item already in the cart by calling its *increaseQuantity()* method. E.g: - + ```java ShoppingCart cart = new ShoppingCart(); cart.add("milk", 3); @@ -1838,24 +1245,7 @@ cart.print(); System.out.println("cart price: " + cart.price() + "\n"); ``` - milk: 1 @@ -1876,16 +1266,11 @@ cart price: 11 - -So in the example above, we first added milk and buttermilk and they get their own Item-objects. When more milk is added to to cart, instead of adding new items we increase the quantity in the item representing milk. - -

Store

@@ -1893,48 +1278,7 @@ We now have all the parts we need for our "online store", except the store itsel Below you'll find a template for a text-based user interface for our store. Create a `Store` class for your project and copy-paste the code below there. - ```java import java.util.Scanner; @@ -1978,20 +1322,11 @@ public class Store { } ``` - + The following is a main method that stocks the stores warehouse and sends John to shop in the store. - ```java Warehouse warehouse = new Warehouse(); warehouse.addProduct("coffee", 5, 10); @@ -2005,10 +1340,7 @@ Warehouse warehouse = new Warehouse(); store.shop("John"); ``` - The store is almost done. The method `public void shop(String customer)` has a part you need to complete, marked with comments. In the marked part, add code that checks if the product requested by the customer is available and has stock in the warehouse. If so, reduce the products stock in the warehouse and add the product to the shopping cart. diff --git a/data/part-9/3-object-polymorphism.md b/data/part-9/3-object-polymorphism.md index 0bde4bb5c..f7738055c 100644 --- a/data/part-9/3-object-polymorphism.md +++ b/data/part-9/3-object-polymorphism.md @@ -5,31 +5,21 @@ hidden: false --- - + - + - You are familiar with the concept of inheritance hierarchy. - You understand that an object can be represented through all of its actual types. - + We've encountered situations where reference-type variables have other types besides their own one. For example, *all* objects are of type `Object`, i.e., any given object can be represented as a `Object`-type variable in addition to its own type. - ```java String text = "text"; Object textString = "another string"; @@ -40,34 +30,27 @@ String text = "text"; Object textString = text; ``` - + In the examples above, a string variable is represented as both a String type and an Object type. Also, a String-type variable is assigned to an Object-type variable. However, assignment in the other direction, i.e., setting an Object-type variable to a String type, will not work. This is because `Object`-type variables are not of type `String` - + ```java Object textString = "another string"; String text = textString; // WON'T WORK! ``` - What is this all about? In addition to each variable's original type, each variable can also be represented by the types of interfaces it implements and classes that it inherits. The String class inherits the Object class and, as such, String objects are always of type Object. The Object class does not inherit a String class, so Object-type variables are not automatically of type String. Take a closer look at the String API documentation, in particular at the top of the HTML page. - + A screenshot of the String Class API documentation. The screenshot shows that the String class inherits the class Object. - + The API documentation for the String class begins with a generic header followed by the class' package (`java.lang`). After the package details, the name of the class (`Class String`) is followed by the *inheritance hierarchy* of the class.
@@ -76,13 +59,7 @@ The API documentation for the String class begins with a generic header followed
 
- The inheritance hierarchy lists all the classes that the given class has inherited. Inherited classes are listed in the order of inheritance, with class being inspected always at the bottom. In the inheritance hierarchy of the String class, we see that the `String` class inherits the `Object` class. *In Java, each class can inherit one class at most*. On the other hand, the inherited class may have inherited another class. As such, a class may indirectly inherit more than a single class. @@ -91,20 +68,7 @@ The inheritance hierarchy can also be thought of as a list of the different type Knowledge of the fact that objects can be of many different types -- of type Object, for instance -- makes programming simpler. If we only need methods defined in the Object class, such as `toString`, `equals` and `hashCode` in a method, we can simply use `Object` as the type of the method parameter. In that case, you can pass the method for *any* object as a parameter. Let's take a look at this with the `printManyTimes` method. The method gets an `Object`-type variable and the number of print operations as its parameters. - ```java public class Printer { @@ -120,23 +84,11 @@ public class Printer { } ``` - -The method can be given any type of object as a parameter. Within the `printManyTimes` method, the object only has access to the methods defined in the `Object` class because the object is *known* in the method to be of type `Object`. The object may, in fact, be of another type. +The method can be given any type of object as a parameter. Within the `printManyTimes` method, the object only has access to the methods defined in the `Object` class because the object is *known* in the method to be of type `Object`. The object may, in fact, be of another type. - ```java Printer printer = new Printer(); @@ -151,15 +103,7 @@ printer.printManyTimes(string, 2); printer.printManyTimes(words, 3); ``` - o @@ -171,7 +115,7 @@ o - + Let's continue to look at the API description of the `String` class. The inheritance hierarchy in the description is followed by a list of interfaces implemented by the class. @@ -181,47 +125,24 @@ Let's continue to look at the API description of the `String` class. The inherit - + The `String` class implements the `Serializable`, `CharSequence`, and `Comparable ` interfaces. An interface is also a type. According to the class' API description, the following interfaces can be set as the type of a String object. - + ```java Serializable serializableString = "string"; CharSequence charSequenceString = "string"; Comparable comparableString = "string"; ``` - + Since we're able to define the type of a method's parameter, we can declare methods that receive an object that *implements a specific interface*. When a method's parameter is an interface, any object that implements that interface can be passed to it as an argument. - -We'll extend the `Printer` class so that it has a method for printing the characters of objects that implement the `CharSequence` interface. The `CharSequence` interface provides, among other things, methods `int length()` for getting a string's length and `char charAt(int index)`, which retrieves a character from a given index. - ```java public class Printer { @@ -243,16 +164,10 @@ public class Printer { } ``` - -The `printCharacters` method can be passed any object that implements the `CharSequence` interface. These include `String` as well as `StringBuilder`, which is often more functional for building strings than `String`. The `printCharacters` method prints each character of a given object on its own line. - ```java Printer printer = new Printer(); @@ -261,16 +176,7 @@ String string = "works"; printer.printCharacters(string); ``` - w @@ -283,54 +189,47 @@ s - + In this exercise we are going to create organisms and herds of organisms that can move around. To represent the locations of the organisms we'll use a **two-dimensional coordinate system**. Each position involves two numbers: `x` and `y` coordinates. The `x` coordinate indicates how far from the origin (i.e. point zero, where x = 0, y = 0) that position is horizontally. The `y` coordinate indicates the distance from the origin vertically. If you are not familiar with using a coordinate system, you can study the basics from [Wikipedia](https://en.wikipedia.org/wiki/Cartesian_coordinate_system).
- + The exercise base includes the interface `Movable`, which represents something that can be moved from one position to another. The interface includes the method `void move(int dx, int dy)`. The parameter `dx` tells how much the object moves on the x axis, and dy tells the distance on the y axis. - + This exercise involves implementing the classes `Organism` and `Herd`, both of which are movable. - +

Implementing the Organism Class

- + Create a class called `Organism` that implements the interface `Movable`. An organism should know its own location (as x, y coordinates). The API for the class `Organism` is to be as follows: - + - **public Organism(int x, int y)**
The class constructor that receives the x and y coordinates of the initial position as its parameters. - + - **public String toString()**
Creates and returns a string representation of the organism. That representation should remind the following: `"x: 3; y: 6"`. Notice that a semicolon is used to separate the coordinates. - + - **public void move(int dx, int dy)**
Moves the object by the values it receives as parameters. The `dx` variable contains the change to coordinate `x`, and the `dy` variable ontains the change to the coordinate `y`. For example, if the value of `dx` is 5, the value of the object variable `x` should be incremented by five. - + Use the following code snippet to test the `Organism` class. - + ```java Organism organism = new Organism(20, 30); @@ -350,42 +249,35 @@ x: 60; y: 55
- +

Implementing the Herd

- + Create a class called `Herd` that implements the interface `Movable`. A herd consists of multiple objects that implement the Movable interface. They must be stored in e.g. a list data structure. - + The `Herd` class must have the following API. - + - **public String toString()**
Returns a string representation of the positions of the members of the herd, each on its own line. - + - **public void addToHerd(Movable movable)**
Adds an object that implements the `Movable` interface to the herd. - + - **public void move(int dx, int dy)**
Moves the herd with by the amount specified by the parameters. Notice that here you have to move each member of the herd. - + Test out your program with the sample code below: - + ```java Herd herd = new Herd(); @@ -411,44 +303,37 @@ x: 19; y: 107 - + In this exercise you'll demonstrate how to use inheritance and interfaces. - +

Animal

- + First implement an abstract class called `Animal`. The class should have a constructor that takes the animal's name as a parameter. The Animal class also has non-parameterized methods eat and sleep that return nothing (void), and a non-parameterized method getName that returns the name of the animal. - + The sleep method should print "(name) sleeps", and the eat method should print "(name) eats". Here (name) is the name of the animal in question. - +

Dog

- + Implement a class called `Dog` that inherits from Animal. Dog should have a parameterized constructor that can be used to name it. The class should also have a non-parameterized constructor, which gives the dog the name "Dog". Another method that Dog must have is the non-parameterized bark, and it should not return any value (void). Like all animals, Dog needs to have the methods eat and sleep. - + Below is an example of how the class Dog is expected to work. - ```java Dog dog = new Dog(); @@ -459,13 +344,7 @@ Dog fido = new Dog("Fido"); fido.bark(); ``` - @@ -476,28 +355,21 @@ Fido barks - +

Cat

- + Next to implement is the class `Cat`, that also inherits from the Animal class. Cat should have two constructors: one with a parameter, used to name the cat according to the parameter, and one without parameters, in which case the name is simply "Cat". Another method for Cat is a non-parameterized method called purr that returns no value (void). Cats should be able to eat and sleep like in the first part. - + Here's an example of how the class Cat is expected to function: - ```java Cat cat = new Cat(); @@ -508,13 +380,7 @@ Cat garfield = new Cat("Garfield"); garfield.purr(); ``` - @@ -525,27 +391,19 @@ Garfield purrs - +

NoiseCapable

- + Finally, create an interface called `NoiseCapable`. It should define a non-parameterized method makeNoise that returns no value (void). Implement the interface in the classes Dog and Cat. The interface should take use of the bark and purr methods you've defined earlier. - + Below is an example of the expected functionality. - ```java NoiseCapable dog = new Dog(); @@ -557,13 +415,7 @@ Cat c = (Cat) cat; c.purr(); ``` - diff --git a/data/part-9/4-conclusion.md b/data/part-9/4-conclusion.md index dcae22e55..2533818b8 100644 --- a/data/part-9/4-conclusion.md +++ b/data/part-9/4-conclusion.md @@ -3,11 +3,11 @@ path: '/part-9/4-summary' title: 'Summary' hidden: false --- - + In the ninth part of the course you learned some of the properties of object-oriented programming. Programmers can expect all objects to have the methods `toString`, `hashCode` and `equals` because each object is of type `Object` in addition to their own type. Inheritance and interfaces allow use to implement methods and constructors that handle many kinds of objects. This enables us to easily extend programs and it helps with solving problems with classes and objects. - + Finally, please take a moment to answer a self-reflective survey on the learning goals of the ninth part. diff --git a/data/part-9/index.md b/data/part-9/index.md index b3d4671fa..fb874cff8 100644 --- a/data/part-9/index.md +++ b/data/part-9/index.md @@ -5,7 +5,7 @@ overview: true hidden: false --- - + The ninth part of the course material focuses on two essential concepts of object oriented programming, namely inheritance and interfaces. You will learn to create classes that inherit another classes, and also classes that implement one or more interfaces. You are also going to notice that an object can be represented by any of its actual types. @@ -13,7 +13,7 @@ The ninth part of the course material focuses on two essential concepts of objec - + The table of contents above lists the topics of the ninth part of the course. The ninth part has been designed to cover the ninth week of the course. You should reserve well above 10 hours for each part of the course, depending on previous experience with computers. If you've tried programming before, you might advance faster in the beginning.