Work with the essential and advanced features of the Java 17 release. This book covers features such as annotations, reflection, and generics. These topics are then complemented by details of how to use lambda expressions, allowing you to build powerful and efficient Java programs. Furthermore, added to this edition you'll find topics on network programming, Java RMI, the process API, and custom runtime images. The authors provide a multitude of diagrams and complete programs to help you visualize and better understand the topics covered in this book.
More Java 17, Third Edition starts with a series of chapters on the essential language features provided by Java before moving on to Java module development and packaging, and improved interop with other languages. After reading this book, you'll have the know-how of a professional Java programmer and be able to tackle most projects with confidence.
What You Will Learn
- Use essential and advanced features of the Java language
- Code Java annotations
- Work with reflection and generics
- Manage streams with the Stream API
Who This Book Is For
Those new to Java programming who are continuing the Java learning journey; it is recommended that you read an introductory Java programming book first, such as Java 17 for Absolute Beginners, from Apress.
Author(s): Kishori Sharan, Peter Späth
Edition: 3
Publisher: Apress
Year: 2021
Language: English
Pages: 979
Tags: Java; Java 17
Table of Contents
About the Authors
About the Technical Reviewers
Introduction
Chapter 1: Annotations
What Are Annotations?
Declaring an Annotation Type
Restrictions on Annotation Types
Restriction #1
Restriction #2
Restriction #3
Restriction #4
Restriction #5
Restriction #6
Default Value of an Annotation Element
Annotation Type and Its Instances
Using Annotations
Primitive Types
String Types
Class Types
Enum Type
Annotation Type
Array Type Annotation Element
No Null Value in an Annotation
Shorthand Annotation Syntax
Marker Annotation Types
Meta-Annotation Types
The Target Annotation Type
The Retention Annotation Type
The Inherited Annotation Type
The Documented Annotation Type
The Repeatable Annotation Type
Commonly Used Standard Annotations
Deprecating APIs
Suppressing Named Compile-Time Warnings
Overriding Methods
Declaring Functional Interfaces
Annotating Packages
Annotating Modules
Accessing Annotations at Runtime
Evolving Annotation Types
Annotation Processing at Source Code Level
Summary
Exercises
Chapter 2: Reflection
What Is Reflection?
Reflection in Java
Loading a Class
Using Class Literals
Using the Object::getClass() Method
Using the Class::forName() Method
Class Loaders
Reflecting on Classes
Reflecting on Fields
Reflecting on Executables
Reflecting on Methods
Reflecting on Constructors
Creating Objects
Invoking Methods
Accessing Fields
Deep Reflection
Deep Reflection Within a Module
Deep Reflection Across Modules
Deep Reflection and Unnamed Modules
Deep Reflection on JDK Modules
Reflecting on Arrays
Expanding an Array
Who Should Use Reflection?
Summary
Exercises
Chapter 3: Generics
What Are Generics?
Supertype-Subtype Relationship
Raw Types
Unbounded Wildcards
Upper-Bounded Wildcards
Lower-Bounded Wildcards
Generic Methods and Constructors
Type Inference in Generic Object Creation
No Generic Exception Classes
No Generic Anonymous Classes
Generics and Arrays
Runtime Class Type of Generic Objects
Heap Pollution
Varargs Methods and Heap Pollution Warnings
Summary
Exercises
Chapter 4: Lambda Expressions
What Is a Lambda Expression?
Why Do We Need Lambda Expressions?
Syntax for Lambda Expressions
Omitting Parameter Types
Using Local Variable Syntax for Parameters
Declaring a Single Parameter
Declaring No Parameters
Parameters with Modifiers
Declaring the Body of Lambda Expressions
Target Typing
Functional Interfaces
Using the @FunctionalInterface Annotation
Generic Functional Interface
Intersection Type and Lambda Expressions
Commonly Used Functional Interfaces
Using the Function Interface
Using the Predicate Interface
Using Functional Interfaces
Method References
Static Method References
Instance Method References
Supertype Instance Method References
Constructor References
Generic Method References
Lexical Scoping
Variable Capture
Jumps and Exits
Recursive Lambda Expressions
Comparing Objects
Summary
Exercises
Chapter 5: Threads
What Is a Thread?
Creating Threads in Java
Specifying Your Code for a Thread
Inheriting Your Class from the Thread Class
Implementing the Runnable Interface
Using a Method Reference
A Quick Example
Using Multiple Threads in a Program
Issues in Using Multiple Threads
Java Memory Model
Atomicity
Visibility
Ordering
Object’s Monitor and Thread Synchronization
Rule #1
Rule #2
The Producer/Consumer Synchronization Problem
Which Thread Is Executing?
Letting a Thread Sleep
I Will Join You in Heaven
Be Considerate to Others and Yield
Lifecycle of a Thread
Priority of a Thread
Is It a Demon or a Daemon?
Am I Interrupted?
Threads Work in a Group
Volatile Variables
Stopping, Suspending, and Resuming Threads
Spin-Wait Hints
Handling an Uncaught Exception in a Thread
Thread Concurrency Packages
Atomic Variables
CAS
Scalar Atomic Variable Classes
Atomic Array Classes
Atomic Field Updater Classes
Atomic Compound Variable Classes
Explicit Locks
Synchronizers
Semaphores
Barriers
Phasers
Latches
Exchangers
The Executor Framework
Result-Bearing Tasks
Scheduling a Task
Handling Uncaught Exceptions in a Task Execution
Executor’s Completion Service
The Fork/Join Framework
Steps in Using the Fork/Join Framework
Step 1: Declaring a Class to Represent a Task
Step 2: Implementing the compute() Method
Step 3: Creating a Fork/Join Thread Pool
Step 4: Creating the Fork/Join Task
Step 5: Submitting the Task to the Fork/Join Pool for Execution
A Fork/Join Example
Thread-Local Variables
Setting Stack Size of a Thread
Summary
Exercises
Chapter 6: Streams
What Are Streams?
Streams Have No Storage
Infinite Streams
Internal Iteration vs. External Iteration
Imperative vs. Functional
Stream Operations
Ordered Streams
Streams Are Not Reusable
Architecture of the Streams API
A Quick Example
Creating Streams
Streams from Values
Empty Streams
Streams from Functions
Streams from Arrays
Streams from Collections
Streams from Files
Streams from Other Sources
Representing an Optional Value
Applying Operations to Streams
Debugging a Stream Pipeline
Applying the ForEach Operation
Applying the Map Operation
Flattening Streams
Applying the Filter Operation
Applying the Reduce Operation
Collecting Data Using Collectors
Collecting Summary Statistics
Collecting Data in Maps
Joining Strings Using Collectors
Grouping Data
Partitioning Data
Adapting the Collector Results
Finding and Matching in Streams
Parallel Streams
Summary
Exercises
Chapter 7: Implementing Services
What Is a Service?
Discovering Services
Providing Service Implementations
Defining the Service Interface
Obtaining Service Provider Instances
Defining the Service
Defining Service Providers
Defining a Default Prime Service Provider
Defining a Faster Prime Service Provider
Defining a Probable Prime Service Provider
Testing the Prime Service
Testing Prime Service in Legacy Mode
Summary
Exercises
Chapter 8: Network Programming
What Is Network Programming?
Network Protocol Suite
IP Addressing Scheme
IPv4 Addressing Scheme
IPv6 Addressing Scheme
Special IP Addresses
Loopback IP Address
Unicast IP Address
Multicast IP Address
Anycast IP Address
Broadcast IP Address
Unspecified IP Address
Port Numbers
Socket API and Client-Server Paradigm
The Socket Primitive
The Bind Primitive
The Listen Primitive
The Accept Primitive
The Connect Primitive
The Send/Sendto Primitive
The Receive/ReceiveFrom Primitive
The Close Primitive
Representing a Machine Address
Representing a Socket Address
Creating a TCP Server Socket
Creating a TCP Client Socket
Putting a TCP Server and Clients Together
Working with UDP Sockets
Creating a UDP Echo Server
A Connected UDP Socket
UDP Multicast Sockets
URI, URL, and URN
URI and URL As Java Objects
Accessing the Contents of a URL
Non-blocking Socket Programming
Socket Security Permissions
Asynchronous Socket Channels
Setting Up an Asynchronous Server Socket Channel
Setting Up an Asynchronous Client Socket Channel
Putting the Server and the Client Together
Datagram-Oriented Socket Channels
Creating the Datagram Channel
Setting the Channel Options
Sending Datagrams
Multicasting Using Datagram Channels
Creating the Datagram Channel
Setting the Channel Options
Binding the Channel
Setting the Multicast Network Interface
Joining the Multicast Group
Receiving a Message
Closing the Channel
Further Reading
Summary
Exercises
Chapter 9: Java Remote Method Invocation
What Is Java Remote Method Invocation?
The RMI Architecture
Developing an RMI Application
Writing the Remote Interface
Implementing the Remote Interface
Writing the RMI Server Program
Writing the RMI Client Program
Separating the Server and Client Code
Running the RMI Application
Running the RMI Registry
Running the RMI Server
Running an RMI Client Program
Troubleshooting an RMI Application
java.rmi.server.ExportException
java.security.AccessControlException
java.lang.ClassNotFoundException
Debugging an RMI Application
Dynamic Class Downloading
Garbage Collection of Remote Objects
Summary
Exercises
Chapter 10: Scripting in Java
What Is Scripting in Java?
Installing Script Engines in Maven
Executing Your First Script
Using Other Scripting Languages
Exploring the javax.script Package
The ScriptEngine and ScriptEngineFactory Interfaces
The AbstractScriptEngine Class
The ScriptEngineManager Class
The Compilable Interface and the CompiledScript Class
The Invocable Interface
The Bindings Interface and the SimpleBindings Class
The ScriptContext Interface and the SimpleScriptContext Class
The ScriptException Class
Discovering and Instantiating Script Engines
Executing Scripts
Passing Parameters
Passing Parameters from Java Code to Scripts
Passing Parameters from Scripts to Java Code
Advanced Parameter Passing Techniques
Bindings
Scope
Defining the Script Context
Putting Them Together
Using a Custom ScriptContext
Return Value of the eval( ) Method
Reserved Keys for Engine Scope Bindings
Changing the Default ScriptContext
Sending Script Output to a File
Invoking Procedures in Scripts
Implementing Java Interfaces in Scripts
Using Compiled Scripts
Using Java in Scripting Languages
Declaring Variables
Importing Java Classes
Implementing a Script Engine
The Expression Class
The JKScriptEngine Class
The JKScriptEngineFactory Class
Packaging the JKScript Files
Using the JKScript Script Engine
JavaFX in Groovy
Summary
Exercises
Chapter 11: Process API
What Is the Process API?
Knowing the Runtime Environment
The Current Process
Querying the Process State
Comparing Processes
Creating a Process
Obtaining a Process Handle
Terminating Processes
Managing Process Permissions
Summary
Exercises
Chapter 12: Packaging Modules
The JAR Format
What Is a Multi-release JAR?
Creating Multi-release JARs
Rules for Multi-release JARs
Multi-release JARs and JAR URL
Multi-release Manifest Attribute
The JMOD Format
Using the jmod Tool
Summary
Exercises
Chapter 13: Custom Runtime Images
What Is a Custom Runtime Image?
Creating Custom Runtime Images
Binding Services
Using Plugins with the jlink Tool
The jimage Tool
Summary
Exercises
Chapter 14: Miscellanea
Deleted Chapters from Previous Editions
More JDK17 Novelties
Local Variables with Automatic Types
Launch Single-File Source Code Programs
Enhanced switch Statements
Text Blocks
Enhanced instanceof Operator
Value Classes: Records
Sealed Classes
Summary
Appendix: Solutions to the Exercises
Exercises in Chapter 1
Exercises in Chapter 2
Exercises in Chapter 3
Exercises in Chapter 4
Exercises in Chapter 5
Exercises in Chapter 6
Exercises in Chapter 7
Exercises in Chapter 8
Exercises in Chapter 9
Exercises in Chapter 10
Exercises in Chapter 11
Exercises in Chapter 12
Exercises in Chapter 13
Index