Full Download Java Programming Exercises Volume Two Java Standard Library 1st Edition Christian Ullenboom PDF DOCX
Full Download Java Programming Exercises Volume Two Java Standard Library 1st Edition Christian Ullenboom PDF DOCX
com
https://ebookfinal.com/download/java-programming-exercises-
volume-two-java-standard-library-1st-edition-christian-
ullenboom/
OR CLICK BUTTON
DOWNLOAD EBOOK
https://ebookfinal.com/download/simply-java-an-introduction-to-java-
programming-programming-series-1st-edition-james-levenick/
ebookfinal.com
https://ebookfinal.com/download/learn-java-fundamentals-a-primer-for-
java-development-and-programming-1st-edition-jeff-friesen/
ebookfinal.com
https://ebookfinal.com/download/java-servlet-programming-second-
edition-jason-hunter/
ebookfinal.com
https://ebookfinal.com/download/wireless-java-programming-
with-j2me-1st-edition-yu-feng/
ebookfinal.com
Java Programming 24 Hour Trainer 1st Edition Yakov Fain
https://ebookfinal.com/download/java-programming-24-hour-trainer-1st-
edition-yakov-fain/
ebookfinal.com
https://ebookfinal.com/download/object-oriented-programming-using-
java-1st-edition-edition-kendal-s/
ebookfinal.com
https://ebookfinal.com/download/object-oriented-programming-and-java-
second-edition-danny-poo/
ebookfinal.com
https://ebookfinal.com/download/introduction-to-java-programming-
comprehensive-version-6th-edition-liang/
ebookfinal.com
https://ebookfinal.com/download/elements-of-programming-interviews-in-
java-2nd-edition-adnan-aziz/
ebookfinal.com
Java Programming Exercises
Take the next step in raising your coding skills and dive into the intricacies of Java Standard Libraries.
You will continue to raise your coding skills, and test your Java knowledge on tricky programming tasks,
with the help of the pirate Captain CiaoCiao. This is the second of two volumes which provide you with
everything you need to excel in your Java journey, including tricks that you should know in detail as a
professional, as well as intensive training for clean code and thoughtful design that carries even complex
software.
Features:
With numerous best practices and extensively commented solutions to the tasks, these books provide the
perfect workout for professional software development with Java.
Java Programming Exercises
Volume Two: Java Standard Library
Christian Ullenboom
Designed cover image: Mai Loan Nguyen Duy, Rheinwerk Verlag GmbH
©2023 Christian Ullenboom. First published in the German language under the title “Captain CiaoCiao erobert Java”
(ISBN 978‑3‑8362‑8427‑1) by Rheinwerk Verlag GmbH, Bonn, Germany.
Reasonable efforts have been made to publish reliable data and information, but the author and publisher cannot
assume responsibility for the validity of all materials or the consequences of their use. The authors and publishers
have attempted to trace the copyright holders of all material reproduced in this publication and apologize to
copyright holders if permission to publish in this form has not been obtained. If any copyright material has not been
acknowledged please write and let us know so we may rectify in any future reprint.
Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced, transmitted, or
utilized in any form by any electronic, mechanical, or other means, now known or hereafter invented, including
photocopying, microfilming, and recording, or in any information storage or retrieval system, without written
permission from the publishers.
For permission to photocopy or use material electronically from this work, access www.copyright.com or contact the
Copyright Clearance Center, Inc. (CCC), 222 Rosewood Drive, Danvers, MA 01923, 978‑750‑8400. For works that are
not available on CCC please contact mpkbookspermissions@tandf.co.uk
Trademark notice: Product or corporate names may be trademarks or registered trademarks and are used only for
identification and explanation without intent to infringe.
DOI: 10.1201/9781003495550
Typeset in Times
by codeMantra
Introduction 1
Previous Knowledge and Target Audience 1
Working with the Book 2
The Suggested Solutions 2
Use of the Book 3
Required Software 3
Used Java Version in the Book 4
JVM 4
Development Environment 4
Conventions 4
Helping Captain CiaoCiao and Bonny Brain 5
v
vi Contents
2 Mathematics 30
The Class Math 30
Quiz: Rule of Thumb ⭑ 30
Check If Tin Tin Cheated on Rounding ⭑ 31
Huge and Very Precise Numbers 32
Calculate Arithmetic Mean of a Large Integer ⭑ 32
Number by Number over the Phone ⭑ 33
Develop Class for Fractions and Truncate Fractions ⭑⭑ 34
Suggested Solutions 35
Quiz: Rule of Thumb 35
Check If Tin Tin Cheated on Rounding 36
Calculate Arithmetic Mean of a Large Integer 37
Number by Number over the Phone 38
Develop Class for Fractions and Truncate Fractions 38
Epilogue 307
Code Golf Stack Exchange 307
Project Euler 307
Daily Programmer 307
Rosetta Code 308
About the Author
Christian Ullenboom s tarted his programming journey at the tender age of ten, typing his first lines of
code into a C64. After mastering assembler programming and early BASIC extensions, he found his call‑
ing on the island of Java, following his studies in computer science and psychology. Despite indulging in
Python, JavaScript, TypeScript, and Kotlin vacations, he remains a savant of all things Java.
For over 20 years, Ullenboom has been a passionate software architect, Java trainer (check out http://
www.tutego.com), and IT specialist instructor. His expertise has resulted in a number of online video
courses and reference books:
Christian Ullenboom has been spreading Java love through his books for years, earning him the coveted
title of Java Champion from Sun (now Oracle) way back in 2005. Only a select few—about 300 world‑
wide—have achieved this status, making him a true Java superstar.
As an instructor, Ullenboom understands that learning by doing is the most effective way to master a
skill. So, he has compiled a comprehensive catalog of exercises that accompany his training courses. This
book features a selection of those exercises, complete with documented solutions.
His roots are in Sonsbeck, a small town in the Lower Rhine region of Germany.
xiii
Introduction
Many beginners in programming often ask themselves, “How can I strengthen my skills as a developer?
How can I become a better programmer?” The answer is simple: study, attend webinars, learn, repeat,
practice, and discuss your work with others. Many aspects of programming are similar to learning new
skills. Just as a book can’t teach you how to play a musical instrument, watching the Fast and the Furious
movie series won’t teach you how to drive. The brain develops patterns and structures through repeated
practice. Learning a programming language and a natural language have many similarities. Consistent
use of the language, and the desire and need to express and communicate in it (just as you need to do so
to order a burger or a beer), leads to gradual improvement in skills.
Books and webinars on learning a programming language are available, but reading, learning, prac‑
ticing, and repeating are just one aspect of becoming a successful software developer. To create effective
software solutions, you need to creatively combine your knowledge, just as a musician regularly practices
finger exercises and maintains their repertoire. The more effective your exercises are, the faster you will
become a master. This book aims to help you progress and gain more hands‑on experience.
Java 21 declares more than 2300 classes, about 1400 interfaces, around 140 enumerations, approxi‑
mately 500 exceptions, and a few annotation types and records are added to this. However, in practical
terms, only a small subset of these types proves to be relevant. This book selects the most important types
and methods for tasks, making them motivating, and following Java conventions. Alternative solutions
and approaches are also presented repeatedly. The goal is to make non‑functional requirements clear
because the quality of programs is not just about “doing what it should.” Issues such as correct indentation,
following naming conventions, proper use of modifiers, best practices, and design patterns are essential.
The proposed solutions aim to demonstrate these principles, with the keyword being Clean Code.
The book is centered around tasks and fully documented solutions, with detailed explanations of Java
peculiarities, good object‑oriented programming practices, best practices, and design patterns. The exer‑
cises are best solved with a textbook, as this exercise book is not a traditional textbook. A useful approach
is to work through a topic with a preferred textbook before attempting the exercises that correspond to it.
DOI: 10.1201/9781003495550-1 1
2 Java Programming Exercises
The first set of tasks are designed for programming beginners who are new to Java. As you gain more
experience with Java, the tasks become more challenging. Therefore, there are tasks for both beginners
and advanced developers.
The Java Standard Edition is augmented by numerous frameworks and libraries. However, this
exercise book does not cover specific libraries or Java Enterprise frameworks like Jakarta EE or Spring
(Boot). There are separate exercise books available for these environments. Additionally, the book does
not require the use of tools like profiling tools, as these are beyond the scope of the book.
1 star ★: Simple exercises, suitable for beginners. They should be easy to solve without much
effort. Often only transfer of knowledge is required, for example, by writing down things that
are in a textbook differently.
2 stars ★★: The effort is higher here. Different techniques have to be combined. Greater creativity
is required.
3 stars ★★★: Assignments with three stars are more complex, require recourse to more prior
knowledge, and sometimes require research. Frequently, the tasks can no longer be solved with
a single method, but require multiple classes that must work together.
REQUIRED SOFTWARE
While solving a task with just a pen and paper is possible in theory, modern software development
requires the proper use of tools. Knowing programming language syntax, object‑oriented modeling,
and libraries is just the tip of the iceberg. Understanding the JVM, using tools like Maven and Git for
version management, and becoming proficient in an IDE are all crucial aspects of professional software
development. Some developers can even perform magic in their IDE, generating code and fixing bugs
automatically.
4 Java Programming Exercises
JVM
If we want to run Java programs, we need a JVM. In the early days, this was easy. The runtime environ‑
ment first came from Sun Microsystems, later from Oracle, which took over Sun. Today, it is much more
confusing. Although a runtime environment can still be obtained from Oracle, the licensing terms have
changed, at least for Java 8 up to Java 16. Testing and development are possible with the Oracle JDK,
but not in production. In this case, Oracle charges license fees. As a consequence, various institutions
compile their own runtime environments from the OpenJDK, the original sources. The best known are
Eclipse Adoptium (https://adoptium.net/), Amazon Corretto (https://aws.amazon.com/de/corretto), Red
Hat OpenJDK (https://developers.redhat.com/products/openjdk/overview) and others such as those from
Azul Systems or Bellsoft. There is no specific distribution that readers are required to follow.
Development Environment
Java source code is just plain text, so technically a simple text editor is all you need. However, relying
solely on Notepad or vi for productivity is like trying to win a race on a tricycle. Modern integrated
development environments support us with many tasks: color highlighting of keywords, automatic code
completion, intelligent error correction, insertion of code blocks, visualization of states in the debug‑
ger, and much more. It is therefore advisable to use a full development environment. Four popular IDEs
are: IntelliJ, Eclipse, Visual Studio Code, and (Apache) NetBeans. Just like with Java runtime environ‑
ments, the choice of IDE is left to the reader. Eclipse, NetBeans, and Visual Studio Code are all free
and open‑source, while IntelliJ Community Edition is also free, but the more advanced IntelliJ Ultimate
Edition will cost you some cash.
Halfway through the book, we delve into implementing project dependencies using Maven in a few
places.
CONVENTIONS
Code is written in fix width font, filenames are italicized. To distinguish methods from attributes,
methods always have a pair of parentheses, such as in “the variable max contains the maximum” or “it
returns max() the maximum”. Since methods can be overloaded, either the parameter list is named, as in
equals(Object), or an ellipsis abbreviates it, such as in “various println(…) methods”. If a group
of identifiers is addressed, * is written, like print*(...) prints something on the screen.
In the suggested solutions, there are usually only the relevant code snippets, so as not to blow up the
book volume. The name of the file is mentioned in the listing caption, like this:
VanillaJava.java
class VanillaJava { }
• Introduction 5
Sometimes, we need to flex our terminal muscles and execute programs from the command line (also
known as console or shell). Since each command‑line program has its own prompt sequence, it is symbol‑
ized here in the book with a $. The user’s input is set in bold. Example:
$ java ‑version
java version "17.0.5" 2022‑10‑18 LTS
Java(TM) SE Runtime Environment (build 17.0.5+9‑LTS‑191)
Java HotSpot(TM) 64‑Bit Server VM (build 17.0.5+9‑LTS‑191, mixed mode,
sharing)
If the Windows command line is explicitly meant, the prompt character > is set:
> netstat ‑e
Interface Statistics
Received Sent
• java.util.Formatter
• java.lang.String
• java.util.regex.Pattern
• java.util.regex.Matcher
• java.util.Scanner
FORMAT STRINGS
There are different ways in Java to format strings, numbers, and temporal data as a string. In the package
java.text, you can find the classes MessageFormat, DateFormat, and DecimalFormat as well
as the class Formatter and in String the method String.format(…). The next tasks can be solved
using the formatting strings from Formatter in a rather easy way.
$ ascii
Usage: ascii [‑adxohv] [‑t] [char‑alias...]
‑t = one‑line output ‑a = vertical format
‑d = Decimal table ‑o = octal table ‑x = hex table ‑b binary table
‑h = This help screen ‑v = version information
Prints all aliases of an ASCII character. Args may be chars, C \‑escapes,
English names, ^‑escapes, ASCII mnemonics, or numerics in decimal/octal/hex.
6 DOI: 10.1201/9781003495550-2
1 • Advanced String Processing 7
Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex
0 00 NUL 16 10 DLE 32 20 48 30 0 64 40 @ 80 50 P 96 60 ' 112 70 p
1 01 SOH 17 11 DC1 33 21 ! 49 31 1 65 41 A 81 51 Q 97 61 a 113 71 q
2 02 STX 18 12 DC2 34 22 " 50 32 2 66 42 B 82 52 R 98 62 b 114 72 r
3 03 ETX 19 13 DC3 35 23 # 51 33 3 67 43 C 83 53 S 99 63 c 115 73 s
4 04 EOT 20 14 DC4 36 24 $ 52 34 4 68 44 D 84 54 T 100 64 d 116 74 t
5 05 ENQ 21 15 NAK 37 25 % 53 35 5 69 45 E 85 55 U 101 65 e 117 75 u
6 06 ACK 22 16 SYN 38 26 & 54 36 6 70 46 F 86 56 V 102 66 f 118 76 v
7 07 BEL 23 17 ETB 39 27 ' 55 37 7 71 47 G 87 57 W 103 67 g 119 77 w
8 08 BS 24 18 CAN 40 28 ( 56 38 8 72 48 H 88 58 X 104 68 h 120 78 x
9 09 HT 25 19 EM 41 29 ) 57 39 9 73 49 I 89 59 Y 105 69 i 121 79 y
10 0A LF 26 1A SUB 42 2A * 58 3A : 74 4A J 90 5A Z 106 6A j 122 7A z
11 0B VT 27 1B ESC 43 2B + 59 3B ; 75 4B K 91 5B [ 107 6B k 123 7B {
12 0C FF 28 1C FS 44 2C , 60 3C < 76 4C L 92 5C \ 108 6C l 124 7C |
13 0D CR 29 1D GS 45 2D ‑ 61 3D = 77 4D M 93 5D ] 109 6D m 125 7D }
14 0E SO 30 1E RS 46 2E . 62 3E > 78 4E N 94 5E ^ 110 6E n 126 7E ~
15 0F SI 31 1F US 47 2F / 63 3F ? 79 4F O 95 5F _ 111 6F o 127 7F DEL
However, their Aye Phone doesn’t have such a widescreen, and the first two blocks are not visible char‑
acters anyway.
Task:
• Write a program that prints all ASCII characters from position 32 to 127 in the same formatting
as the Unix program ascii does.
• At position 127, write DEL.
8 Java Programming Exercises
Aligned Outputs ⭑
Captain CiaoCiao needs a table of the following type for a listing:
Task:
Later, we will also use regular expressions to specify separators and decompose strings.
Task:
Example:
Task:
• Given is a line from the scan with numbers from the format shown. Convert the numbers to an
integer.
• There could be missing spaces after the last digit, and there could be several spaces between
the large characters.
Example:
If you want to play around with the strings, you can find a way at https://patorjk.com/software/taag/#p=
display&f=Alphabet&t=0123456789.
Task:
Example:
We raid the harbor at 11:00 PM and meet on the amusement mile at 1:30 AM.
Bonny Brain doesn’t like that; she wants only the 24‑hour count of Military Time.
Task:
• Write a converter that converts strings with AM/PM (case‑insensitive, even with periods) to
Military Time. As a reminder, 12:00 AM is 00:00, and 12:00 PM is 12:00.
Examples:
The lines are separated with a line break. There are four valid separator symbols or sequences:
LF is the abbreviation for “line feed” and CR for “carriage return”; in old teleprinters, CR moved the
carriage to the first column, and LF pushed the paper up.
Traditionally, DOS and Microsoft Windows use the combination \r\n, while Unix systems use \n.
Task:
• Break a newline‑separated string into four lines, and assign the lines to the variables name,
street, city, and country.
• If a fourth line with the country name is not given, let country be "Drusselstein".
• Reassemble the line as a CSV line separated by semicolons.
Examples:
erehW did eht etarip esahcrup sih kooh? tA eht dnah‑dnoces pohs!
Task:
1. Break the string into words. Separators of words are spaces and punctuation marks.
2. Turn over all the words one by one.
3. Output the words one after the other, separated by a space. The punctuation marks and other
separators are not critical.
Example:
• "erehW did eht etarip esahcrup sih kooh? tA eht dnah‑dnoces pohs!"
→ "Where did the pirate purchase his hook At the hand second shop"
Goldy Goldfish has the task of checking the relation signs <, > and =.
Task:
• Write a program that gets a string like the one in the example and returns true if all relation
signs are correct, and false otherwise.
Examples:
The lines are still described with numbers. Thus, A2 stands for cell 1–2.
14 Java Programming Exercises
Since Captain CiaoCiao has its difficulties with A1 notation, the specification is to be converted back
to numeric columns and rows.
Task:
Examples:
• parseA1Notation("A1") → [1, 1]
• parseA1Notation("Z2") → [26, 2]
• parseA1Notation("AA34") → [27, 34]
• parseA1Notation("BZ") → [0, 0]
• parseA1Notation("34") → [0, 0]
• parseA1Notation(" ") → [0, 0]
• parseA1Notation("") → [0, 0]
20.091612,‑155.676695
23.087301,‑73.643472
21.305452,‑71.690421
Task:
• Create a CSV file manually. It should contain several lines with coordinates; a comma sepa‑
rates the coordinates.
• A Java program should read the CSV file and output an HTML file with SVG for the polygon
course on the screen.
• Use the class Scanner to parse the file. Make sure to initialize the Scanner with
useLocale(Locale.ENGLISH) if your locale is not English by default.
A simple lossless compression is run‑length encoding. The idea is to combine a sequence of identical
symbols so that only the number and the symbol are written. The graphic format GIF, for example, uses
this form of compression. Therefore, images with many monochrome lines are also smaller than, for
example, images in which each pixel has a different color.
The next task is about run‑length encoding. Suppose a string consists of a sequence of . (dot) and ‑
(minus sign), such as:
‑‑....‑‑‑‑‑‑‑‑..‑
To shorten the length of strings, we can first write the symbol followed by the number of symbols. The
string with 17 characters could be shortened to the following string with 9 characters:
‑2.4‑8.2‑
Task:
Extensions:
SUGGESTED SOLUTIONS
First, the program writes the table header, in which the string “Dec Hex” for the six columns is set six
times in a row with spacing.
The generated table has 16 rows, which generates a loop. In principle, we could also dynamically
calculate the number of rows from the start and end values and the number of columns (six in our case).
However, we know that if we start at position 32, and end at 127, with 6 columns we need 16 rows.
The inner loop writes all columns for a given row. At the top left is the first element, the space char‑
acter. To the right, the character increases not by one, but by 16, which is, therefore, the loop counter.
In the next line, we don’t start at 32 but at 33, the pattern here is the following: the start value of the
inner loop is 32 + row, so 32 plus the row number. Altogether, the loop ends when the ASCII code has
reached 127.
Within the inner loop’s body, the character is required to be displayed as a string. Essentially, each
character is outputted as a string. The conditional operator verifies whether the character at positions 127
is the DEL character; all other characters are converted to a string of length 1 through the Character
method. The format string consists of three components: the first two parts access the first format argu‑
ment and begin by displaying the character’s position as a decimal number, followed by its number in
hexadecimal format. The integer is left‑padded with white space, while the hexadecimal number doesn’t
1 • Advanced String Processing 17
require any width information, as it always contains two digits when starting with 32. The third block
contains the character as a string and the second format argument. Finally, a line feed is added at the end
of the line.
Output of PrintAsciiTable
Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex
32 20 48 30 0 64 40 @ 80 50 P 96 60 ' 112 70 p
33 21 ! 49 31 1 65 41 A 81 51 Q 97 61 a 113 71 q
34 22 " 50 32 2 66 42 B 82 52 R 98 62 b 114 72 r
35 23 # 51 33 3 67 43 C 83 53 S 99 63 c 115 73 s
36 24 $ 52 34 4 68 44 D 84 54 T 100 64 d 116 74 t
37 25 % 53 35 5 69 45 E 85 55 U 101 65 e 117 75 u
38 26 & 54 36 6 70 46 F 86 56 V 102 66 f 118 76 v
39 27 ' 55 37 7 71 47 G 87 57 W 103 67 g 119 77 w
40 28 ( 56 38 8 72 48 H 88 58 X 104 68 h 120 78 x
41 29 ) 57 39 9 73 49 I 89 59 Y 105 69 i 121 79 y
42 2A * 58 3A : 74 4A J 90 5A Z 106 6A j 122 7A z
43 2B + 59 3B ; 75 4B K 91 5B [ 107 6B k 123 7B {
44 2C , 60 3C < 76 4C L 92 5C \ 108 6C l 124 7C |
45 2D ‑ 61 3D = 77 4D M 93 5D ] 109 6D m 125 7D }
46 2E . 62 3E > 78 4E N 94 5E ^ 110 6E n 126 7E ~
47 2F / 63 3F ? 79 4F O 95 5F _ 111 6F o 127 7F DEL
Aligned Outputs
com/tutego/exercise/string/PaidOrNotPaid.java
if ( names.length != paid.length )
throw new IllegalArgumentException(
"Number of names and paid entries are not the same, but "
+ names.length + " and " + paid.length );
int maxColumnLength = 0;
for ( String name : names )
maxColumnLength = Math.max( maxColumnLength, name.length() );
First, the method checks if the two arrays have an equal number of elements, and if not, an
IllegalArgumentException is thrown. Accessing length generates the desired
NullPointerException if the arrays are null.
Since it is unknown in advance how wide the first left column will be, we have to go over all the
strings and determine the maximum length. Using this maximum maxColumnLength we can build a
format string. The format string gets a format specifier that determines the width of a string, padded with
spaces. The format string has a leading minus sign, so this gives a left‑aligned string that is padded on the
18 Java Programming Exercises
right with spaces up to the maximum length maxColumnLength. In addition, the format string contains
a space to the right column of four spaces.
The right column contains either “paid” or “not paid”. That is, the string “paid” always occurs,
and only the word “not” is to be set dependent on a boolean value. This is done by the condition opera‑
tor, which either returns an empty string or the string “not” as a format argument for the format string.
In the last example, it is about finding and not about a complete match, so the find() method of Matcher
is used. In principle, tests of existence can also be formulated by .*FIND.* and matches(…), but match‑
ing makes a little more work for the regex engine than just providing the first find and not having to look
to the end.
1 • Advanced String Processing 19
The task can be solved with a one‑liner because the Matcher method results() returns a
Stream<MatchResult>, and for Stream objects the count() method determines the number of
occurrences.
If we take a closer look at the big numbers, we quickly realize that each large number contains the actual
number itself. The large zero contains 0, the large one contains 1, and so on. So, we don’t have to evaluate
several lines, it’s enough to take any line. We just take the first one.
After extracting the first line, we can search for the substring that makes up the single digits. The
blanks interfere a bit, so they are removed in the first step. A new String is created from the first line,
in which all spaces have been removed, and then the digits of each major character are aligned. For
example, if the line starts with 000, we know that the first digit in the result must be 0. We can simply
use replaceAll(…) to replace the sequence 000 with 0. For example, if there are two zeros in a row,
0000 correctly becomes 00.
Since not only three zeros have to be replaced by zero, but also two ones by a one, and there are ten
different replacements, we store the individual strings in an array beforehand. A loop runs through the
array, and in the body, there are repeated calls to replaceAll(…), which replaces all partial strings
from the search with the loop index, so that, for example, 000 becomes "" + 0, i.e., "0". At the end, we
convert the number to an integer and return the result.
If the incoming string is null, empty, or contains foreign characters, there will be exceptions in the
following. This behavior is fine.
20 Java Programming Exercises
The proposed solution proceeds in three steps: Building the pattern object, matching the string, and
replacing the match group with lowercase strings. The regex string must describe a sequence of uppercase
letters. Upper case letters, over the entire Unicode alphabet, determine \p{javaUpperCase}. We want
to have at least three uppercase letters in a row, which {3,} takes care of. Whether to keep the pattern
precompiled in a static variable depends entirely on how often the method is called. In general, it is a good
strategy to keep the Pattern objects in memory because translation always costs a little execution time.
On the other hand, you reference an object, and if you rarely need it, you don’t have to.
The method compile(…) gives us a Pattern object, and the matcher(…) method gives us a
Matcher object. We can well use the replaceAll(Function<MatchResult, String>) method,
which can perform a transformation of the found strings. The argument passed is a function that maps a
MatchResult to a string. Our function accesses the group, converts the string to lowercase, and returns
it. replaceAll(…) finds all places with the selected uppercase letters and calls this function mul‑
tiple times.
At the heart of the program is a regular expression that captures times. This regular expression consists of
four parts, which are also split into four lines in the code. The first part captures the hours, the part cap‑
tures the minutes, the third part is an optional white space between the time, and the last part, AM/PM.
1. The hours consist of at least one integer, the second integer being optional if, for example, 1
AM is written. In principle, we could write the expression a bit more precisely so that something
like 99 AM is not recognized, but we do not make that check here. The hours themselves are in
round brackets, a group named ?<hours>. All regular expression groups can be named so that
we can access them more easily later by that name and not have to use a group index.
2. The minute’s part is optional, that is, it is enclosed in round brackets altogether, and there is a
question mark at the end. The inside starts with a ?:, which is a small regular expression opti‑
mization so that this group is inaccessible via the API later. If hours and minutes are specified
at the same time, a colon separates them. The minutes themselves are also a named group, and
they consist of two decimal numbers. Again, we do not make any checks about possible ranges
of validity.
3. The third part is a white space, which is optional.
4. The last part must capture different notations of AM/PM. A dot could be placed between the
two symbols, perhaps even mistakenly just after a letter, so say A.M or AM. So that we don’t
have to specify case, we include a special pattern flag that checks case independently, so it
doesn’t matter whether we write AM, am, Am, or pM.
The convertToMilitaryTime(String) method gets the string with the time information as a
parameter. The Pattern object was stored as a constant, and the matcher(…) method connects the
Pattern with the string method parameter. The result is a Matcher. This type can do all the work
with replaceAll(Function<MatchResult, String> replacer): the method runs over all the
matches for us, calls our Function, and we can access the match from the MatchResult and replace
it with a string.
Regarding the Function: first, we access the group for the hours and convert it to an integer.
Converting an integer will not throw an exception because our regular expression ensures that only digits
occur. The peculiarity with minutes is that they can be missing. So, we have to go back to the group min‑
ute and ask if it exists at all. If it does not exist, we assign the variable minutes with 0; otherwise, we
convert the string with the minutes into an integer and set the variable minutes with it.
Now we evaluate the group ampm and declare a variable isTimeInPm, which becomes true if the
time is given in PM. For AM, the variable remains false. This variable helps with the conversion. If
isTimeInPm is true, then the time is “post meridiem”, i.e., afternoon, and 12 hours must be added. It
may happen that the text mistakenly enters 23 PM, for example; in this case, we want to correct the error
and do not add 12. Moreover, if the time of the hours is equal to 12 o`clock, we also do not correct. The
next check is specifically for 12:xx, which becomes 00xx clock. So, if isTimeInPm equals false,
then it is the time “ante meridiem”, that is the morning, and we subtract 12.
After the two variables hours and minutes are set, we generate a string with the hours and min‑
utes and use String.format(…) so that we get the times with only one digit padded with a 0. This is
the return of the Function.
In the center of the job is the class StringTokenizer, which is useful whenever.
1. Not (all) tokens are to be extracted in advance like with split(…), but step by step.
2. The separators consist of single characters, but no strings.
Similarly, we create an instance of StringTokenizer, but it’s important to note that the two specified
characters are not treated as a combined separator; instead, they are considered as individual characters
that can serve as a separator for the tokens in any combination.
With the method nextToken() we ask for the lines three times, and since we don’t know if there is
a fourth line, we look ahead with hasMoreTokens(). If there is a token, we consume it. Otherwise, we
choose the desired default country.
Since StringTokenizer is an Enumeration<Object>, in principle we could have used
hasMoreElements() and nextElement(), but the latter method has the awkward Object return
type.
The reversing of the string is done by the reverse(…)‑ method of the StringBuilder. We then out‑
put the result to the screen, separated by a space at the end.
Now we have to split the sentence and recognize the words.
com/tutego/exercise/string/PrintReverseWords.java
String string = "erehW did eht etarip esahcrup sih kooh? tA eht dnah‑dnoces pohs!";
System.out.println();
At the center is the regular expression [\p{punct}\s]+. It captures a sequence of punctuation marks,
parentheses, etc., and white space separating words. We make use of predefined character classes. It uses
\p{punct} for a character out of
!"#$%&'()*+,‑./:;<=>?@[\]^_'{|}~
and \s for the white space; it is the character class [ \t\n\x0B\f\r]. For a connection, we put both
into a new character class, and since characters can occur any number of times in a row, we add a plus.
Java supports splitting with regular expressions via the Pattern‑Matcher combination, and two
well‑known facades are the Scanner and the split(…) method. Both variants are shown in the pro‑
posed solution. The Scanner is always good if the number of matches can be large because with the
split(…) method the answer is always an array with all words. The Scanner implements Iterable
and at forEachRemaining(…) we put a method reference to the helper method printWordRe‑
versed(…) for the Consumer, which writes each word reversed on the screen.
while ( scanner.hasNext() ) {
String operator = scanner.next();
int number2 = scanner.nextInt();
if ( isValidRelation( number1, operator, number2 ) )
number1 = number2;
else
return false;
}
return true;
}
The actual method checkRelation(String) gets the string and checks the relations. However, the
method falls back on its own private method isValidRelation(int, String, int) so we want
to start with that. isValidRelation(…) gets a number, a comparison operator, and another number. It
checks if the comparison operator with the two numbers returns a true result. If so, the answer is true; if
the comparison is false, the answer is false just as in the case of a misplaced symbol because we evalu‑
ate only <, > and =.
24 Java Programming Exercises
The method checkRelation(…) builds a Scanner with the passed String and now uses a
combination of nextInt(), hasNext(), and next() to process tokens from the Scanner. At the
beginning, there must always be a number, which means we can initialize a variable number1 with the
first number. The data stream could be empty now, but if the Scanner has the next symbols, this will be
a comparison operator, which we will refer to. After the comparison operator comes to a second integer,
which we also read in and store in number2. Now we call our method isValidRelation(…), and this
method returns true if the comparison was fine. Then number2 will become the new number1, so in
the next loop pass, number2 will be assigned the following number. If isValidRelation(…) returns
false, then we can abort the method because at this point the comparison is false. If there was no break‑
out from the loop, all comparisons were correct, and the method ends with return true.
Let us consider the cell AA34 mentioned in the task as an example. In the first step, we need to separate
the column from the row. The column here would be AA, the row 34. We then need to convert the column
AA to the numeric representation, 27. Two separate methods handle these two steps. The main method
parseA1Notation(String) first extracts the row and column, and then calls an internal method
parseColumnIndex(String), which converts the column to a numeric value for us after the A1
notation.
Let’s start with the parseColumnIndex(String) method. We’ll take a few examples to make it
easier to read the calculation pattern.
What we can read is the following:
To convert the whole thing now into an algorithm, we use the Horner scheme. Let us illustrate this with
an example:
The Horner scheme is important for us because we don’t need to calculate powers anymore. If we go one
place further to the right, we multiply the old result by 26 and repeat the scheme for the other places. This
is precisely what the method parseColumnIndex(String) does. A loop runs over all characters,
extracts them, and queries the numeric representation with Character.getNumericValue(char).
This is defined not only for digits but also for letters. For the letter 'a' the result is 10, the same as for
'A'. For 'Z' it is 35. If we subtract 9 from this, we get the range of values 1–26. We take the old result,
multiply it by 26, and add the numeric representation of the letter. The next step is to calculate the new
numeric value of the next character, multiply the last result by 26, and again add the value of the last letter.
This performs the calculation exactly as we planned it.
The method parseA1Notation(String) has little work to do. First, we compile a Pattern that
extracts the column and row—since the column is all letters and the row is all digits, we can easily capture
that via the groups in the regular expression. If the string is wrong, and if we don’t have two matches, we
return an array of {0, 0}, signaling incorrect input. If there are two match groups, we take the column
information from the first one and convert it to an integer using our own parseColumnIndex(String)
method. The second string, according to the regular expression, is a valid string of digits, which Integer.
parseInt(String) converts to an int. The numeric column and row go into a small array, and that
goes back to the caller.
while ( scanner.hasNextDouble() ) {
double x = scanner.nextDouble();
if ( ! scanner.hasNextDouble() )
throw new IllegalStateException( "Missing second coordinate" );
26 Java Programming Exercises
double y = scanner.nextDouble();
svg.append( x ).append( "," ).append( y ).append( " " );
}
The file consists of sequences of integers separated by either a semicolon or a newline, generally speaking
by arbitrary white space. We need to find a tokenizer that we can feed with a regular expression that stands
for just these separators. Since we want to read from a file and process that with regular expressions, the
class Scanner is a good choice. This is also how the proposed solution does it.
The Scanner is connected to an input stream, the file we would like to read. The character encoding
is explicitly set to UTF‑8.
Then the Scanner is initialized with a regular expression for the delimiters. These delimiters are
set by the Scanner method useDelimiter(…). It is important to set the Locale.ENGLISH because
by default the Scanner is preconfigured with the Locale by the operating system, and if that is, for
example, German, the Scanner expects floating‑point numbers with a comma as separator. But the
source always has English formatted numbers.
After the Scanner is prepared, the program can produce the output. It starts with the SVG container
and the polygon start tag. The Scanner method hasNext() helps to iterate through the file. When the
hasNext() method returns a token, we always expect pairs. We can read the first integer, and now there
must be a second integer. But if the Scanner cannot give a new token, this is an error, and we raise an
exception. If the second number exists, it will also be read in. The pair can then be placed in the SVG
container.
At the end of the loop, we close the polygon tag and print the SVG element to the screen. For the
output, we don’t need to pay attention to the language for append(double) because the formatting of
the double is automatically in English.
if ( string.isEmpty() )
return "";
lastChar = currentChar;
}
}
result.append( lastChar );
if ( count > 1 )
result.append( count );
return result.toString();
}
if ( token.isEmpty() )
return "";
if ( token.length() == 1 )
return token;
while ( pattern.find() )
result.append( decodeToken( pattern.group() ) );
return result.toString();
}
In the first step, we want to compress the string. To achieve this, we first query whether the string contains
any text at all; if not, we are quickly done with the task.
To see how many of the same characters occur in the text in a row, we use a variable lastChar for
the last character seen so that we can compare a new character with the last character. In addition, we
note the number of same characters in count. Since this result is freshly built, we add a variable result
of the data type StringBuilder.
The for loop goes over each character and stores it in the auxiliary variable currentChar. Now,
two things can happen: The character currentChar just read can be the same as the previous character
in lastChar, or it can be a different character. We have to handle this difference.
The initial check determines if the previously observed character matches the currently read char‑
acter. If it’s a match, we simply increase the counter and continue the loop. However, if the newly read
character differs from the previous one, the local compression process concludes. We begin by writing
this character to the buffer. Then, we address the count: if more than one identical character was previ‑
ously counted, we input that count into the data stream. But if there was just one character, we don’t add
1 to the buffer, in accordance with the task’s instructions. After finalizing the character‑counter pair, it’s
essential to reset the counter to 1. We are almost done with the loop. The moment a new character is found,
we set lastChar to exactly the current character currentChar.
When we are done with the loop, we still have a character in lastChar and count. We therefore
perform the same query as before in the case distinction, and append the counter to the string if the coun‑
ter is greater than 1.
28 Java Programming Exercises
In the method for unpacking, we fall back on the pattern that results from the compression. There
are always pairs of a string and a number, with the special case that the pair is single, and the number
is missing. Using a regular expression, we run the entire string and look at all the pairs. To keep the
method from getting too big, we use a helper method called decodeToken(String) that takes a pair
and expands it.
First, the method must find out whether the token consists of only one character or of several charac‑
ters. If the string consists of only one character, then it must have been our symbol, and it comes into the
output. If the string is longer than 1, then there is a length encoding from the second position upward. With
substring(1) we extract the string and convert it to an integer, so that the repeat(int) method of
String can generate us exactly this number of characters token.charAt(0). With substring(1)
we extract the string and convert it to an integer, so that the repeat(int) method of String can gener‑
ate us exactly this number of characters token.charAt(0).
TABLE 1.4 Some characters with their positions in the Unicode standard
CHARACTER θ A a Ä ß ä ñ
Code point (decimal) 48 65 97 196 223 228 241
The natural ordering of strings is lexicographic, meaning that the position of the character in the Unicode
alphabet counts. Let’s illustrate this with some characters.
From the table, you can see that the digits are first, followed by the uppercase letters and then the
lowercase letters. The umlauts are far behind the capital letters and not sorted between the upper and
lower case letters.
Umlauts are regular letters in German, which do not come after “Z” in the order. The standard DIN
5007‑1 describes under “Ordering of character sequences (ABC rules)” two sorting procedures:
DIN 5007, variant 1 (used for words, for example, in dictionaries)
DIN 5007, variant 2 (special sorting for lists of names, such as in telephone directories)
There are similar rules for other languages. The lexicographical order does not support this. Therefore,
the Unicode Collation Algorithm describes how the sorting looks like in different national languages. For
an introduction, see also https://en.wikipedia.org/wiki/Unicode_collation_algorithm.
In Java Collator objects are available. They are initialized with a Locale object. In addition
to the language, so‑called levels can be passed; the Javadoc gives further examples under the heading
“Collator strength value”.
Mathematics
2
Integers and floating‑point numbers already appeared in the first exercises; we were using the common
mathematical operators to crunch numbers. But Java does not have an operator for everything, and so
the class Math offers further methods and constants; early on we used Math.random(), for example.
Throughout this chapter’s upcoming tasks, our focus will be on various rounding techniques, particularly
exploring the methods offered by the Math class. In addition, the java.math package provides two
classes that can be used to represent arbitrarily large numbers—there are tasks for these as well.
Prerequisites
• java.lang.Math
• java.math.BigInteger
• java.math.BigDecimal
The Java library supports different possibilities for conversion and rounding, among other things with
• Math.rint(double) → double.
• BigDecimal and setScale(..) → BigDecimal.
• NumberFormat, configured with setMaximumFractionDigits(…), then format(…)
→ String.
• DecimalFormat, configured with setRoundingMode(…), then format(…) → String.
• Formatter with a format string, then format(…) → String.
Four of the methods originate from Math, but when it comes to gigantic and precise floating‑point num‑
bers or string representation, other classes are involved. Since the methods differ slightly in the result, the
following task should make these differences clear once again.
Task:
-2.5
-1.9
-1.6
-1.5
-1.1
1.1
1.5
1.6
1.9
2.5
• Given an array of floating‑point numbers (positive and negative) and the sum converted to an
integer by Tin Tin.
• Captain CiaoCiao wants to find out which rounding was used to form the integer of the sum.
Therefore, the elements in the array are to be summed and compared to Tin Tin’s sum. The
rounding is done after the numbers are added.
• Implement a method RoundingMode detectRoundingMode(double[] numbers,
int sum) that gets a double array of numbers and the sum of Tin Tin and checks which
rounding mode was used.
• To allow the rounding mode to be represented, introduce an enumeration type:
enum RoundingMode {
CAST, ROUND, FLOOR, CEIL, RINT, UNKNOWN;
}
32 Java Programming Exercises
• Which rounding is bad for Captain CiaoCiao and good for Tin Tin? Which variation could Tin
Tin use to cheat?
Example:
Notes:
• There is an enumeration type RoundingMode in the java.math package, but for our case,
it does not fit the task.
• It may well happen that more than one rounding mode fits—such as when the sum of the
floating‑point values itself gives an integer—then the method is free to choose one of the round‑
ing modes.
• Calculate the arithmetic mean of two long values so that there is no overflow and wrong
results. The result should be a long again.
2 • Mathematics 33
Task:
Example:
T
«interface»
Number
Comparable
«final»
Fraction
SUGGESTED SOLUTIONS