Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

All Exercises in This Part

Exercise 6.1: Calculator 1 p.

Create a program that asks the user for two decimal numbers and an arithmetic operation, and then prints the result as follows:

Number 1 > 12.0
Number 2 > 3.0
Operation (+, -, *, /) > +
12.0 + 3.0 = 15.0

At this stage you do not need to handle invalid input. You may assume that the numbers are always entered as numeric values. The supported operations are addition (+), subtraction (-), multiplication (*) and division (/). You may assume that only these operations are used as input.

Do not use loops or conditional statement. Instead, implement the arithmetic operations as lambda expressions and store them in a lookup structure using the operation symbol as the key.

The program should terminate after displaying the result.

Hint 1

You may use BiFunction<Double, Double, Double> (See JavaDoc) or DoubleBinaryOperator (JavaDoc) as the type for the lambda expressions.

Hint 2

You may use Map<String, BiFunction<Double, Double, Double>> or Map<String, DoubleBinaryOperator> as the type of the lookup structure.

You may either choose a specific implementation for the lookup structure or initialize an immutable lookup structure using the Map.of method:

Map<String, BiFunction<Double, Double, Double>> operations = Map.of(
    "+", ...,
    "-", ...,
    "*", ...,
    "/", ...
);

For each ..., simply provide an appropriate lambda expression.

Complete this exercise in TIM
Exercise 6.2: Comparison Rarity 1 p.

Extend the CollectibleCard class by adding an attribute String rarity. The rarity of a collectible card can be one of the following values (from least rare to most rare): C, U, R, RR, RRR, SR, AR, SAR, UR.

Write a comparator that sorts the cards in a list according to their rarity. You can use the following card collection to test your code:

Example list of collectible cards
List<CollectibleCard> cards = new ArrayList<>(List.of(
    new CollectibleCard("Lost Semicolon", "Code Jungle", 101, "C"),
    new CollectibleCard("Infinite Loop", "Code Jungle", 102, "U"),
    new CollectibleCard("Bug Hunter", "Code Jungle", 103, "R"),
    new CollectibleCard("Spaghetti Code Monster", "Code Jungle", 104, "RR"),
    new CollectibleCard("Overclocked Processor", "Code Jungle", 105, "SR"),
    new CollectibleCard("Holy Stack Overflow", "Code Jungle", 106, "RRR"),
    new CollectibleCard("Null Pointer Ninja", "Code Jungle", 107, "U"),
    new CollectibleCard("Blue Screen of Death", "Code Jungle", 108, "AR"),

    new CollectibleCard("Student Card", "Campus Saga", 201, "C"),
    new CollectibleCard("Sleepy Lecturer", "Campus Saga", 202, "C"),
    new CollectibleCard("Overall Party", "Campus Saga", 203, "U"),
    new CollectibleCard("Overachiever", "Campus Saga", 204, "R"),
    new CollectibleCard("Free Bucket", "Campus Saga", 205, "SAR"),
    new CollectibleCard("Late Submission", "Campus Saga", 206, "RR"),
    new CollectibleCard("Academic Quarter", "Campus Saga", 207, "SR"),
    new CollectibleCard("Thesis Anxiety", "Campus Saga", 208, "AR"),
    new CollectibleCard("Semma Pancake", "Campus Saga", 209, "UR"),

    new CollectibleCard("Angry Moose", "Finnish Myths", 301, "C"),
    new CollectibleCard("Eternal November", "Finnish Myths", 302, "RR"),
    new CollectibleCard("Sauna Gollum", "Finnish Myths", 303, "SR"),
    new CollectibleCard("Salmiakki Rain", "Finnish Myths", 304, "U"),
    new CollectibleCard("Väinämöinen's Kantele", "Finnish Myths", 305, "SAR"),
    new CollectibleCard("Sisu", "Finnish Myths", 306, "RRR"),
    new CollectibleCard("Laser Sauna Ladle", "Finnish Myths", 307, "UR"),
    new CollectibleCard("Market Square Police Officer", "Finnish Myths", 308, "R")
));

Write a main() program that sorts and prints the collectible cards by rarity (most common cards first, rarest cards last). Cards whose rarity is null or some value other than those listed above must be placed at the beginning of the list.

Complete this exercise in TIM
Exercise 6.3: Music Playlist 1 p.

Assume there is a class Song that represents a single musical track. A song has a name, a genre, and a duration in seconds:

class Song {
    String name;
    String genre;
    int durationInSeconds;
}

Add the necessary visibility modifiers, a constructor, the required getter methods, and an appropriate implementation of the toString() method.

Create a function createPlaylist(songs, genre, numberOfSongs) that returns at most the number of songs specified by the numberOfSongs parameter, where the song genre matches the given genre parameter. The songs must be sorted by duration from shortest to longest.

You can use the following sample list to test your code:

Example list of songs
List<Song> songList = List.of(
    new Song("Bohemian Rhapsody", "Rock", 354),
    new Song("Levitating", "Pop", 203),
    new Song("Sandstorm", "Electronic", 225),
    new Song("Paranoid", "Metal", 168),
    new Song("Toxic", "Pop", 198),
    new Song("Master of Puppets", "Metal", 515),
    new Song("Cha Cha Cha", "Pop", 175),
    new Song("Hotel California", "Rock", 390),
    new Song("Stay", "Pop", 141),
    new Song("Enter Sandman", "Metal", 331),
    new Song("Bad Romance", "Pop", 295),
    new Song("Midnight City", "Electronic", 243),
    new Song("Billie Jean", "Pop", 294),
    new Song("Hard Rock Hallelujah", "Metal", 247),
    new Song("Thriller", "Pop", 357),
    new Song("As It Was", "Pop", 167),
    new Song("Paint It, Black", "Rock", 202),
    new Song("Hollywood Hills", "Rock", 210),
    new Song("Get Lucky", "Electronic", 369),
    new Song("Shake It Off", "Pop", 219),
    new Song("Ace of Spades", "Metal", 169),
    new Song("Rolling in the Deep", "Pop", 228),
    new Song("Sweet Child O' Mine", "Rock", 356),
    new Song("Borderline", "Pop", 210),
    new Song("Back in Black", "Rock", 255),
    new Song("Shape of You", "Pop", 233),
    new Song("Fear of the Dark", "Metal", 438),
    new Song("Blinding Lights", "Pop", 200),
    new Song("Stairway to Heaven", "Rock", 482),
    new Song("Uptown Funk", "Pop", 269),
    new Song("Smells Like Teen Spirit", "Rock", 301),
    new Song("Short Pop Song", "Pop", 120)
);

Do not use loops. Implement createPlaylist using streams.

Hint

You may need at least the following Stream methods:

  • filter(): filters elements
  • sorted(): sorts elements
  • limit(): limits the number of elements
  • toList(): collects the elements into a list
Complete this exercise in TIM
Exercise 6.4: Average with threshold values 1 p.

Create a function double average(int[] numbers, int minimum, int maximum). The function calculates the average of the numbers given in the array according to the following rules:

  • If an element is less than or equal to minimum, the element is discarded and is not included in the average.
  • If an element is greater than or equal to maximum, that element and all elements after it are discarded.

Example:

IO.println(average(new int[] { -5, 1, -4, 0, 98 }, -7, 99));
IO.println(average(new int[] { 11, 4, 2, 6, 99, 12, 0, -3 }, 3, 99));
IO.println(average(new int[] { 99, 1, 2, 3 }, 0, 99));
18.0
7.0
0.0

The first call returns 18.0 because the entire dataset falls between the minimum and maximum bounds. The second call returns 7.0 because only the values 11, 4, and 6 are included in the average: the value 2 is smaller than the minimum, and all values starting from 99 are discarded.

If the average cannot be calculated, the function returns the value of the minimum parameter.

Do not use loops. Implement the function using streams.

Hint

Study the IntStream type (JavaDoc) and its methods. You may find at least the following useful:

  • filter(): removes elements from the stream
  • takeWhile(): takes elements from the stream as long as the condition is true; as soon as the condition becomes false, stream processing stops there (like a "tap" being turned off)
  • average(): calculates the average

Note that average() returns an OptionalDouble object (JavaDoc). The object contains an orElse() method that allows you to return either the calculated value or an alternative default value.

Complete this exercise in TIM
Exercise 6.5: Exceptions, Part 1 1 p.

Complete the multiple-choice question in TIM.

Complete this exercise in TIM
Exercise 6.6: Exceptions, Part 2 1 p.

Create a main method that repeatedly reads integers from the user in a loop for as long as the user enters a non-empty input. If the user enters something other than an integer, print an error message and continue reading input.

Store the numbers in an array. Finally, print all numbers stored in the array.

Complete this exercise in TIM
Exercise 6.7: Exceptions, Part 3 1 p.

Create a program that checks whether the age entered by the user is sufficient for a certain activity, such as obtaining a driver's license.

Create a method isOldEnough that takes an age (int) as a parameter and returns true if the age is sufficient. If the age is below 18, throw an AgeException, which is your own checked exception class. Provide an appropriate exception message, for example "Age is not sufficient." As a hint, the method declaration can be:

static boolean isOldEnough(int age) throws AgeException

If the age is negative, throw an AgeException with the message: "Age cannot be negative."

Remove the if statement and modify the main method so that it compiles and prints the correct output.

Complete this exercise in TIM
Exercise 6.8: Dependencies 1 p.

Create a new Maven project. Set the package name to fi.jyu.username (replace username with your JYU username or another username of your choice). Name the main class Dependencies. Add the following code to it:

void main() {
    JSONObject json = new JSONObject();
    json.put("name", "Maija");
    json.put("age", 25);
    IO.println(json.getString("name"));
    IO.println(json.getInt("age"));
}

Now add a dependency to the json artifact in the pom.xml file. Find this library on Maven Central and copy the XML dependency definition into your pom.xml file. Also add the required import statement at the beginning of the class.

Compile and run the program, and make sure that it prints the expected data.

Complete this exercise in TIM
Exercise 6.9: Words 1 p.

Download the dataset: words.txt

Save the file in your project's working directory as words.txt.

The file contains one word per line. It intentionally contains empty lines, leading/trailing whitespace, duplicate words, and different letter cases (e.g. Java, java, JAVA).

Example from the beginning of the dataset:

  Java
python

JAVA
CSharp
  java

Create a program that:

  • Reads all lines.
  • Removes extra whitespace from the words and converts them to lowercase. Hint: String.trim() and String.toLowerCase().
  • Removes empty lines.
  • Removes duplicates. (Hint: the distinct() method in the Stream API, or a Set collection.)
  • Sorts the words alphabetically. (Hint: the sorted() method in the Stream API, or the Collections.sort() method on a List.)
  • Writes a new file output/words-clean.txt containing the cleaned word list (one word per line).
  • Also writes a file output/report.txt containing:
    • the number of original lines
    • the number of unique words after removing empty lines and cleaning the words
    • the longest word (if there are several, any one of them is acceptable)

Hint: If you solve the task using the Stream API, you can use the Stream.max(Comparator) method to find the longest word.

Hint: First create List<String> cleaned = ..., and then use Files.write(...) to write the results to the two output files.

report.txt should look like this:

Original lines: 1074
Cleaned words: 59
Longest word: binarytree
Complete this exercise in TIM
Exercise 6.10: Load people from a JSON file 1 p.
  • Create a new Maven project that uses the Jackson library for processing JSON files.
  • Add the required dependency to your pom.xml file.
  • Download people.json and save it in the same folder as your code.
  • Create a Person class or an equivalent record with the fields String name, int age, and String city.
  • Read the file people.json and convert it into a list of Person objects.
  • Filter the list so that only people aged 18 or older are included.
  • Print their name, age, and city.

Remember to save people.json in the same folder as your code. Then check your run configuration and make sure that the working directory is the same as the folder containing your code so that the file can be found.

You can access the contents of people.json here if necessary:

people.json
[
  { "name": "Maija Laine", "age": 25, "city": "Jyväskylä" },
  { "name": "Matti Virtanen", "age": 30, "city": "Tampere" },
  { "name": "Liisa Niemi", "age": 17, "city": "Helsinki" },
  { "name": "Pekka Korhonen", "age": 41, "city": "Oulu" },
  { "name": "Aino Salmi", "age": 22, "city": "Turku" },
  { "name": "Jari Heikkinen", "age": 19, "city": "Kuopio" },
  { "name": "Sari Lehto", "age": 16, "city": "Lahti" },
  { "name": "Oskari Mäkinen", "age": 28, "city": "Espoo" },
  { "name": "Emilia Ranta", "age": 33, "city": "Vantaa" },
  { "name": "Teemu Koski", "age": 45, "city": "Pori" },
  { "name": "Noora Aalto", "age": 18, "city": "Joensuu" },
  { "name": "Kalle Hämäläinen", "age": 52, "city": "Rovaniemi" }
]
Complete this exercise in TIM
Exercise 6.11: CSV->JSON 1 p.

Create a program that reads the file people.csv (format: name,age,city) and writes a similar JSON file people.json as the one provided in the previous exercise. If a row is invalid (for example, the age is not a number), skip the row and continue processing.

The output file should look like this. It does not matter if the indentation or line breaks are not exactly the same.

[
  {
    "name": "Maija Laine",
    "age": 25,
    "city": "Jyväskylä"
  },
  {
    "name": "Matti Virtanen",
    "age": 30,
    "city": "Tampere"
  },
  ...
]
Complete this exercise in TIM
Exercise 6.12: Better Calculator 1 p.

Create a simple calculator program that repeatedly asks the user for two numbers and an arithmetic operation, and then prints the result.

The program should work approximately as follows:

Enter an expression in the format <number> <operator> <number>.
Type "exit" to close the program.

> 1 + 1
2.0
> 10 - 1
9.0
> 0.5 * 100
50.0
> 10 / 2
5.0
> 10
Enter an expression in the format <number> <operator> <number>.
> cat
Enter an expression in the format <number> <operator> <number>.
> exit
Program closing.

The program must handle invalid user input so that it does not crash due to incorrect input.

Implement the basic arithmetic operations: addition (+), subtraction (-), multiplication (*), and division (/). In addition, invent and implement at least two additional operations of your own choice.

Do not use conditional statements to select the arithmetic operation itself. However, you may use conditional statements and try/catch blocks to validate user input.

Hint 1

You may implement the operations as lambda expressions. Use either BiFunction<Double, Double, Double> (JavaDoc) or DoubleBinaryOperator (JavaDoc) as the type for the lambda expressions.

Hint 2

You may use the Scanner class to read the user's input:

Scanner reader = new Scanner(userInput);
double number1 = reader.nextDouble();
String operation = reader.next();
double number2 = reader.nextDouble();

You may need to add the necessary exception handling.

Complete this exercise in TIM