Problems
Use the following problems to test your programming prowess on Objects
, immutability, switch
expressions, and pattern matching. I strongly encourage you to give each problem a try before you turn to the solutions and download the example programs:
- Explaining and exemplifying UTF-8, UTF-16, and UTF-32: Provide a detailed explanation of what UTF-8, UTF-16, and UTF-32 are. Include several snippets of code to show how these work in Java.
- Checking a sub-range in the range from 0 to length: Write a program that checks whether the given sub-range [given start, given start + given end) is within the bounds of the range from [0, given length). If the given sub-range is not in the [0, given length) range, then throw an
IndexOutOfBoundsException
. - Returning an identity string: Write a program that returns a string representation of an object without calling the overridden
toString()
orhashCode()
. - Hooking unnamed classes and instance main methods: Give a quick introduction to JDK 21 unnamed classes and instance main methods.
- Adding code snippets in Java API documentation: Provide examples of adding code snippets in Java API documentation via the new
@snippet
tag. - Invoking default methods from
Proxy
instances: Write several programs that invoke interfacedefault
methods fromProxy
instances in JDK 8, JDK 9, and JDK 16. - Converting between bytes and hex-encoded strings: Provide several snippets of code for converting between bytes and hex-encoded strings (including byte arrays).
- Exemplify the initialization-on-demand holder design pattern: Write a program that implements the initialization-on-demand holder design pattern in the classical way (before JDK 16) and another program that implements this design pattern based on the fact that, from JDK 16+, Java inner classes can have static members and static initializers.
- Adding nested classes in anonymous classes: Write a meaningful example that uses nested classes in anonymous classes (pre-JDK 16, and JDK 16+).
- Exemplify erasure vs. overloading: Explain in a nutshell what type erasure in Java and polymorphic overloading are, and exemplify how they work together.
- Xlinting default constructors: Explain and exemplify the JDK 16+ hint for classes with default constructors,
-Xlint:missing-explicit-ctor
. - Working with the receiver parameter: Explain the role of the Java receiver parameter and exemplify its usage in code.
- Implementing an immutable stack: Provide a program that creates an immutable stack implementation from zero (implement
isEmpty()
,push()
,pop()
, andpeek()
operations). - Revealing a common mistake with Strings: Write a simple use case of strings that contain a common mistake (for instance, related to the
String
immutability characteristic). - Using the enhanced NullPointerException: Exemplify, from your experience, the top 5 causes of
NullPointerException
and explain how JDK 14 improves NPE messages. - Using yield in switch expressions: Explain and exemplify the usage of the
yield
keyword withswitch
expressions in JDK 13+. - Tackling the case null clause in switch: Write a bunch of examples to show different approaches for handling
null
values inswitch
expressions (including JDK 17+ approaches). - Taking on the hard way to discover equals(): Explain and exemplify how
equals()
is different from the==
operator. - Hooking instanceof in a nutshell: Provide a brief overview with snippets of code to highlight the main aspect of the
instanceof
operator. - Introducing pattern matching: Provide a theoretical dissertation including the main aspects and terminology for pattern matching in Java.
- Introducing type pattern matching for instanceof: Provide the theoretical and practical support for using the type pattern matching for
instanceof
. - Handling the scope of a binding variable in type patterns for instanceof: Explain in detail, including snippets of code, the scope of binding variables in type patterns for
instanceof
. - Rewriting equals() via type patterns for instanceof: Exemplify in code the implementation of
equals()
(including for generic classes) before and after type patterns forinstanceof
have been introduced. - Tackling type patterns for instanceof and generics: Provide several examples that use the combo type patterns for
instanceof
and generics. - Tackling type patterns for instanceof and streams: Can we use type patterns for
instanceof
and the Stream API together? If yes, provide at least an example. - Introducing type pattern matching for switch: Type patterns are available for
instanceof
but are also available forswitch
. Provide here the theoretical headlines and an example of this topic. - Adding guarded pattern labels in switch: Provide a brief coverage of guarded pattern labels in
switch
for JDK 17 and 21. - Dealing with pattern label dominance in switch: Pattern label dominance in
switch
is a cool feature, so exemplify it here in a comprehensive approach with plenty of examples. - Dealing with completeness (type coverage) in pattern labels for switch: This is another cool topic for
switch
expressions. Explain and exemplify it in detail (theory ad examples). - Understanding the unconditional patterns and nulls in switch expressions: Explain how
null
values are handled by unconditional patterns ofswitch
expressions before and after JDK 19.
The following sections describe solutions to the preceding problems. Remember that there usually isn’t a single correct way to solve a particular problem. Also remember that the explanations shown here include only the most interesting and important details needed to solve the problems. Download the example solutions to see additional details and to experiment with the programs at https://github.com/PacktPublishing/Java-Coding-Problems-Second-Edition/tree/main/Chapter02.