Java
This is the up-to-date, practical guide to Java you’ve been looking for! Whether you’re a beginner, you’re switching to Java from another language, or you’re just looking to brush up on your Java skills, this is the only book you need. You’ll get a thorough grounding in the basics of the Java language, including classes, objects, arrays, strings, and exceptions. You'll also learn about more advanced topics: threads, algorithms, XML, JUnit testing, and much more. This book belongs on every Java programmer's shelf!
- Your complete guide to the Java Platform, Standard Edition 17
- Understand the Java language, from basic principles to advanced concepts
- Work with expressions, statements, classes, objects, and much more
- Download and consult practical code examples
You'll learn about:
- Java Basics:
Get to know the inner workings of Java, from classes and objects to data structures and algorithms. This book is up to date for Java SE 17!
- Advanced Topics:
Already mastered the basics? Explore what else Java can do, from floating point arithmetic to testing frameworks, threads, database management, and beyond.
- Practical Examples:
Gain hands-on experience with Java using tried and tested downloadable programs. These code examples allow you to work your way through the book, testing your newfound skills and knowledge along the journey.
Key Highlights:
- Classes and objects
- Arrays
- Exception handling
- Object-oriented programming
- Characters and strings
- Generics
- Class library
- Concurrent programming
- Data structures
- Lambda expressions
- JUnit testing
- JDK tools
View Full Table of Contents
- Preface
- Target Group
- What This Book Is Not
- My Life and Java, Or “Why a Java Book?”
- Software and Versions
- Which Java Version to Use
- Using This Book to Learn
- Personal Learning Strategies
- Focusing on the Essentials
- Special Sections
- Tasks
- Structure of This Book
- Conventions
- Program Listings
- Application Programming Interface Documentation in This Book
- Executable Programs
- Acknowledgments
- Resources for This Book
- Feedback
- 1 Introduction
- 1.1 Historical Background
- 1.2 On the Popularity of Java: The Key Features
- 1.2.1 Bytecode
- 1.2.2 Executing the Bytecode via a Virtual Machine
- 1.2.3 Platform Independence
- 1.2.4 Java as a Language, Runtime Environment, and Standard Library
- 1.2.5 Object Orientation in Java
- 1.2.6 Java Is Widespread and Well Known
- 1.2.7 Java Is Fast: Optimization and Just-In-Time Compilation
- 1.2.8 Pointers and References
- 1.2.9 Take Out the Trash, Garbage Collector!
- 1.2.10 Exception Handling
- 1.2.11 The Range of Libraries and Tools
- 1.2.12 Comparably Simple Syntax
- 1.2.13 Abandoning Controversial Concepts
- 1.2.14 Java Is Open Source
- 1.2.15 What Java Is Less Suitable for
- 1.3 Java versus Other Languages*
- 1.3.1 Java and C(++)
- 1.3.2 Java and JavaScript
- 1.3.3 A Word about Microsoft, Java, and J++
- 1.3.4 Java and C#/.NET
- 1.4 Further Development and Losses
- 1.4.1 The Development of Java and Its Future Prospects
- 1.4.2 Features, Enhancements, and Specification Requests
- 1.4.3 Applets
- 1.4.4 JavaFX
- 1.5 Java Platforms
- 1.5.1 Java Platform, Standard Edition
- 1.5.2 Java Platform, Micro Edition: Java for the Little Ones
- 1.5.3 Java for the Very, Very Little Ones
- 1.5.4 Java for the Big Ones: Jakarta EE (Formerly Java Platform, Enterprise Edition)
- 1.5.5 Real-Time Java
- 1.6 Java Platform, Standard Edition, Implementations
- 1.6.1 OpenJDK
- 1.6.2 Oracle JDK
- 1.7 Installing the Java Development Kit
- 1.7.1 Installing Oracle JDK on Windows
- 1.8 Compiling and Testing the First Program
- 1.8.1 A Square Numbers Program
- 1.8.2 The Compiler Run
- 1.8.3 The Runtime Environment
- 1.8.4 Common Compiler and Interpreter Issues
- 1.9 Development Environments
- 1.9.1 IntelliJ IDEA
- 1.9.2 Eclipse Integrated Development Environment
- 1.9.3 NetBeans
- 1.10 Further Reading
- 2 Imperative Language Concepts
- 2.1 Elements of the Java Programming Language
- 2.1.1 Tokens
- 2.1.2 Text Encoding by Unicode Characters
- 2.1.3 Identifiers
- 2.1.4 Literals
- 2.1.5 (Reserved) Keywords
- 2.1.6 Summary of the Lexical Analysis
- 2.1.7 Comments
- 2.2 From Classes to Statements
- 2.2.1 What Are Statements?
- 2.2.2 Class Declaration
- 2.2.3 The Journey Begins with main(String[])
- 2.2.4 The First Method Call: println(...)
- 2.2.5 Atomic Statements and Statement Sequences
- 2.2.6 More about print(...), println(...), and printf(...) for Screen Output
- 2.2.7 Application Programming Interface Documentation
- 2.2.8 Expressions
- 2.2.9 Expression Statements
- 2.2.10 First Insights into Object Orientation
- 2.2.11 Modifiers
- 2.2.12 Grouping Statements with Blocks
- 2.3 Data Types, Typing, Variables, and Assignments
- 2.3.1 Overview of Primitive Data Types
- 2.3.2 Variable Declarations
- 2.3.3 Automatic Type Detection with var
- 2.3.4 Final Variables and the final Modifier
- 2.3.5 Console Inputs
- 2.3.6 Truth Values
- 2.3.7 Integer Data Types
- 2.3.8 Underscores in Numbers
- 2.3.9 Alphanumeric Characters
- 2.3.10 The float and double Data Types
- 2.3.11 Good Names, Bad Names
- 2.3.12 No Automatic Initialization of Local Variables
- 2.4 Expressions, Operands, and Operators
- 2.4.1 Assignment Operator
- 2.4.2 Arithmetic Operators
- 2.4.3 Unary Minus and Plus
- 2.4.4 Prefix or Postfix Increment and Decrement
- 2.4.5 Assignment with Operation (Compound Assignment Operator)
- 2.4.6 Relational Operators and Equality Operators
- 2.4.7 Logical Operators: NOT, AND, OR, and XOR
- 2.4.8 Short-Circuit Operators
- 2.4.9 The Rank of Operators in Evaluation Order
- 2.4.10 Typecasting (Casting)
- 2.4.11 Overloaded Plus for Strings
- 2.4.12 Operators Missing*
- 2.5 Conditional Statements or Case Distinctions
- 2.5.1 Branching with the if Statement
- 2.5.2 Choosing the Alternative with an if-else Statement
- 2.5.3 The Condition Operator
- 2.5.4 The Switch Statement Provides an Alternative
- 2.5.5 Switch Expressions
- 2.6 Always the Same with Loops
- 2.6.1 The while Loop
- 2.6.2 The do-while Loop
- 2.6.3 The for Loop
- 2.6.4 Loop Conditions and Comparisons with ==*
- 2.6.5 Loop Termination with break and back to Test with continue
- 2.6.6 break and continue with Labels*
- 2.7 Methods of a Class
- 2.7.1 Components of a Method
- 2.7.2 Signature Description in the Java Application Programming Interface Documentation
- 2.7.3 Calling a Method
- 2.7.4 Declaring Methods without Parameters
- 2.7.5 Static Methods (Class Methods)
- 2.7.6 Parameters, Arguments, and Value Transfers
- 2.7.7 Ending Methods Prematurely with return
- 2.7.8 Unreachable Source Code for Methods*
- 2.7.9 Methods with Returns
- 2.7.10 Overloading Methods
- 2.7.11 Scope
- 2.7.12 Default Values for Unlisted Arguments*
- 2.7.13 Recursive Methods*
- 2.7.14 Towers of Hanoi*
- 2.8 Further Reading
- 3 Classes and Objects
- 3.1 Object-Oriented Programming
- 3.1.1 Why Object-Oriented Programming at All?
- 3.1.2 When I Think of Java, I Think of Reusability
- 3.2 Members of a Class
- 3.3 Natural Modeling Using Unified Modeling Language*
- 3.4 Creating New Objects
- 3.4.1 Creating an Instance of a Class Using the new Keyword
- 3.4.2 Declaring Reference Variables
- 3.4.3 Let’s Get to the Point: Accessing Object Variables and Methods
- 3.4.4 The Connection between new, the Heap, and the Garbage Collector
- 3.4.5 Overview of Point Methods
- 3.4.6 Using Constructors
- 3.5 ZZZZZnake
- 3.6 Tying Packages, Imports, and Compilation Units
- 3.6.1 Java Packages
- 3.6.2 Packages in the Standard Library
- 3.6.3 Full Qualification and Import Declaration
- 3.6.4 Reaching All Types of a Package with Type-Import-on-Demand
- 3.6.5 Hierarchical Structures across Packages and Mirroring in the File System
- 3.6.6 The Package Declaration
- 3.6.7 Unnamed Package (Default Package)
- 3.6.8 Compilation Unit
- 3.6.9 Static Import*
- 3.7 Using References, Diversity, Identity, and Equality
- 3.7.1 null References and the Question of Philosophy
- 3.7.2 Everything to null? Testing References
- 3.7.3 Assignments with References
- 3.7.4 Methods with Reference Types as Parameters
- 3.7.5 Identity of Objects
- 3.7.6 Equivalence and the equals(...) Method
- 3.8 Further Reading
- 4 Arrays and Their Areas of Use
- 4.1 Simple Field Work
- 4.1.1 Basic Components
- 4.1.2 Declaring Array Variables
- 4.1.3 Creating Array Objects with new
- 4.1.4 Arrays with { contents }
- 4.1.5 Reading the Length of an Array via the Object Variable Length
- 4.1.6 Accessing the Elements via the Index
- 4.1.7 Typical Array Errors
- 4.1.8 Passing Arrays to Methods
- 4.1.9 Multiple Return Values*
- 4.1.10 Preinitialized Arrays
- 4.2 The Extended for Loop
- 4.2.1 Using Anonymous Arrays in the Extended for Loop
- 4.2.2 Example: Searching Arrays with Strings
- 4.2.3 Creating Random Player Positions
- 4.3 A Method with a Variable Number of Arguments
- 4.3.1 System.out.printf(...) Accepts Any Number of Arguments
- 4.3.2 Finding the Average of Variable Arguments
- 4.3.3 Vararg Design Tips*
- 4.4 Multidimensional Arrays*
- 4.4.1 Nonrectangular Arrays*
- 4.5 Library Support for Arrays
- 4.5.1 Cloning Can Be Worthwhile: Propagating Arrays
- 4.5.2 Why Can Arrays “Do” So Little?
- 4.5.3 Copying Array Contents
- 4.6 Using the Arrays Class for Comparing, Filling, Searching, and Sorting
- 4.6.1 String Representation of an Array
- 4.6.2 Sorting
- 4.6.3 Parallel Sorting
- 4.6.4 Comparing Arrays of Primitives with Arrays.equals(...) and Arrays.deepEquals(...)*
- 4.6.5 Comparing Object Arrays Using Arrays.equals(...) and Arrays.deepEquals(...)*
- 4.6.6 Searching Differences Using Mismatch (...)*
- 4.6.7 Filling Arrays*
- 4.6.8 Copying Array Sections*
- 4.6.9 Binary Search*
- 4.6.10 Lexicographic Array Comparisons Using compare(...) and compareUnsigned(...)
- 4.6.11 Arrays for Lists with Arrays.asList(...): Convenient for Searching and Comparing*
- 4.6.12 A Long Snake
- 4.7 The Entry Point for the Runtime System: main(...)
- 4.7.1 Correct Declaration of the Start Method
- 4.7.2 Processing Command Line Arguments
- 4.7.3 The Return Type of main(...) and System.exit(int)*
- 4.8 Further Reading
- 5 Handling Characters and Strings
- 5.1 From ASCII via ISO-8859-1 to Unicode
- 5.1.1 ASCII
- 5.1.2 ISO/IEC 8859-1
- 5.1.3 Unicode
- 5.1.4 Unicode Character Encoding
- 5.1.5 Escape Sequences
- 5.1.6 Notation for Unicode Characters and Unicode Escapes
- 5.1.7 Java Versions Go Hand in Hand with the Unicode Standard*
- 5.2 Data Types for Characters and Strings
- 5.3 The Character Class
- 5.3.1 Is That So?
- 5.3.2 Converting Characters to Uppercase/Lowercase
- 5.3.3 From Character to String
- 5.3.4 From char to int: From Character to Number*
- 5.4 Strings
- 5.5 The String Class and Its Methods
- 5.5.1 String Literals as String Objects for Constant Strings
- 5.5.2 Concatenation with +
- 5.5.3 Multiline Text Blocks with “””
- 5.5.4 String Length and Testing for Empty Strings
- 5.5.5 Accessing a Specific Character with charAt(int)
- 5.5.6 Searching for Contained Characters and Strings
- 5.5.7 The Hangman Game
- 5.5.8 Good That We Have Compared
- 5.5.9 Extracting String Sections
- 5.5.10 Appending Strings, Merging Strings, Case Sensitivity, and Whitespace
- 5.5.11 Searched, Found, and Replaced
- 5.5.12 Creating String Objects with Constructors and from Repeats*
- 5.6 Mutable Strings with StringBuilder and StringBuffer
- 5.6.1 Creating StringBuilder Objects
- 5.6.2 Converting StringBuilder to Other String Formats
- 5.6.3 Requesting Characters or Strings
- 5.6.4 Appending Data
- 5.6.5 Setting, Deleting, and Reversing Characters and Strings
- 5.6.6 Length and Capacity of a StringBuilder Object*
- 5.6.7 Comparison of StringBuilder Instances and Strings with StringBuilder
- 5.6.8 hashCode() with StringBuilder*
- 5.7 CharSequence as Base Type
- 5.7.1 Basic Operations of the Interface
- 5.7.2 Static compare(...) Method in CharSequence
- 5.7.3 Default Methods in the CharSequence Interface*
- 5.8 Converting Primitives and Strings
- 5.8.1 Converting Different Types to String Representations
- 5.8.2 Converting String Contents to a Primitive Value
- 5.8.3 String Representation in Binary, Hex, and Octal Formats*
- 5.8.4 parse*(...) and print*() Methods in DatatypeConverter*
- 5.9 Concatenating Strings
- 5.9.1 Concatenating Strings with StringJoiner
- 5.10 Decomposing Strings
- 5.10.1 Splitting Strings via split(...)
- 5.10.2 Yes We Can, Yes We Scan: The Scanner Class
- 5.11 Formatting Outputs
- 5.11.1 Formatting and Outputting via format()
- 5.12 Further Reading
- 6 Writing Custom Classes
- 6.1 Declaring Custom Classes with Members
- 6.1.1 Minimum Class
- 6.1.2 Declaring Object Variables
- 6.1.3 Declaring Methods
- 6.1.4 Shadowed Variables
- 6.1.5 The this Reference
- 6.2 Privacy and Visibility
- 6.2.1 For the Public: public
- 6.2.2 Not Public: Passwords Are private
- 6.2.3 Why Not Free Methods and Variables for All?
- 6.2.4 private Is Not Quite Private: It Depends on Who Sees It*
- 6.2.5 Declaring Access Methods for Object Variables
- 6.2.6 Setters and Getters according to the JavaBeans Specification
- 6.2.7 Package-Visibility
- 6.2.8 Visibility Summary
- 6.3 One for All: Static Methods and Class Variables
- 6.3.1 Why Static Members Are Useful
- 6.3.2 Static Members with static
- 6.3.3 Using Static Members via References?*
- 6.3.4 Why Case Sensitivity Is Important*
- 6.3.5 Static Variables for Data Exchange*
- 6.3.6 Static Members and Object Members*
- 6.4 Constants and Enumerations
- 6.4.1 Constants via Static Final Variables
- 6.4.2 Type-Unsafe Enumerations
- 6.4.3 Enumeration Types: Type-Safe Enumerations with enum
- 6.5 Creating and Destroying Objects
- 6.5.1 Writing Constructors
- 6.5.2 Relationship of Method and Constructor
- 6.5.3 The Default Constructor
- 6.5.4 Parameterized and Overloaded Constructors
- 6.5.5 Copy Constructors
- 6.5.6 Calling Another Constructor of the Same Class via this(...)
- 6.5.7 Immutable Objects and Wither Methods
- 6.5.8 We Don’t Miss You: The Garbage Collector
- 6.6 Class and Object Initialization*
- 6.6.1 Initializing Object Variables
- 6.6.2 Static Blocks as Class Initializers
- 6.6.3 Initializing Class Variables
- 6.6.4 Compiled Assignments of the Class Variables
- 6.6.5 Instance Initializer
- 6.6.6 Setting Final Values in the Constructor and Static Blocks
- 6.7 Conclusion
- 7 Object-Oriented Relationship
- 7.1 Associations between Objects
- 7.1.1 Association Types
- 7.1.2 Unidirectional 1-to-1 Relationship
- 7.1.3 Becoming Friends: Bidirectional 1-to-1 Relationships
- 7.1.4 Unidirectional 1-to-n Relationships
- 7.2 Inheritance
- 7.2.1 Inheritance in Java
- 7.2.2 Modeling Events
- 7.2.3 The Implicit Base Class java.lang.Object
- 7.2.4 Single and Multiple Inheritance*
- 7.2.5 Do Children See Everything? The Protected Visibility
- 7.2.6 Constructors in Inheritance and super(...)
- 7.3 Types in Hierarchies
- 7.3.1 Automatic and Explicit Typecasting
- 7.3.2 The Substitution Principle
- 7.3.3 Testing Types with the instanceof Operator
- 7.3.4 Pattern Matching for instanceof
- 7.4 Overriding Methods
- 7.4.1 Providing Methods in Subclasses with a New Behavior
- 7.4.2 With super to the Parents
- 7.5 Testing Dynamic Bindings
- 7.5.1 Bound to toString()
- 7.5.2 Implementing System.out.println(Object)
- 7.6 Final Classes and Final Methods
- 7.6.1 Final Classes
- 7.6.2 Non-Overridable (final) Methods
- 7.7 Abstract Classes and Abstract Methods
- 7.7.1 Abstract Classes
- 7.7.2 Abstract Methods
- 7.8 Further Information on Overriding and Dynamic Binding
- 7.8.1 No Dynamic Binding for Private, Static, and final Methods
- 7.8.2 Covariant Return Types
- 7.8.3 Array Types and Covariance*
- 7.8.4 Dynamic Binding even with Constructor Calls*
- 7.8.5 No Dynamic Binding for Covered Object Variables*
- 7.9 A Programming Task
- 8 Interfaces, Enumerations, Sealed Classes, Records
- 8.1 Interfaces
- 8.1.1 Interfaces Are New Types
- 8.1.2 Declaring Interfaces
- 8.1.3 Abstract Methods in Interfaces
- 8.1.4 Implementing Interfaces
- 8.1.5 A Polymorphism Example with Interfaces
- 8.1.6 Multiple Inheritance with Interfaces
- 8.1.7 No Risk of Collision with Multiple Inheritance*
- 8.1.8 Extending Interfaces: Subinterfaces
- 8.1.9 Constant Declarations for Interfaces
- 8.1.10 Subsequent Implementation of Interfaces*
- 8.1.11 Static Programmed Methods in Interfaces
- 8.1.12 Extending and Modifying Interfaces
- 8.1.13 Default Methods
- 8.1.14 Declaring and Using Extended Interfaces
- 8.1.15 Public and Private Interface Methods
- 8.1.16 Extended Interfaces, Multiple Inheritance, and Ambiguities*
- 8.1.17 Creating Building Blocks with Default Methods*
- 8.1.18 Marker Interfaces*
- 8.1.19 (Abstract) Classes and Interfaces in Comparison
- 8.2 Enumeration Types
- 8.2.1 Methods on Enum Objects
- 8.2.2 Enumerations with Custom Methods, Constructors, and Initializers*
- 8.3 Sealed Classes and Interfaces
- 8.3.1 Sealed Classes and Interfaces
- 8.3.2 Subclasses Are Final, Sealed, and Non-Sealed
- 8.3.3 Abbreviated Notations
- 8.4 Records
- 8.4.1 Simple Records
- 8.4.2 Records with Methods
- 8.4.3 Customizing Record Constructors
- 8.4.4 Adding Constructors
- 8.4.5 Sealed Interfaces and Records
- 8.4.6 Records: Summary
- 9 There Must Be Exceptions
- 9.1 Fencing In Problem Areas
- 9.1.1 Exceptions in Java with try and catch
- 9.1.2 Checked and Unchecked Exceptions
- 9.1.3 A NumberFormatException (Unchecked Exception)
- 9.1.4 Appending a Date/Timestamp to a Text File (Checked Exception)
- 9.1.5 Repeating Canceled Sections*
- 9.1.6 Empty catch Blocks
- 9.1.7 Catching Multiple Exceptions
- 9.1.8 Combining Identical catch Blocks with Multi-Catch
- 9.2 Redirecting Exceptions and throws at the Head of Methods/Constructors
- 9.2.1 throws in Constructors and Methods
- 9.3 The Class Hierarchy of Exceptions
- 9.3.1 Members of the Exception Object
- 9.3.2 Base Type Throwable
- 9.3.3 The Exception Hierarchy
- 9.3.4 Catching Super-Exceptions
- 9.3.5 Already Caught?
- 9.3.6 Procedure of an Exceptional Situation
- 9.3.7 No General Catching!
- 9.3.8 Known RuntimeException Classes
- 9.3.9 Interception Is Possible, but Not Mandatory
- 9.4 Final Handling Using finally
- 9.4.1 The Ignorant Version
- 9.4.2 The Well-Intentioned Attempt
- 9.4.3 From Now On, Closing Is Part of the Agenda
- 9.4.4 Summary
- 9.4.5 A try without a catch, but a try-finally
- 9.5 Triggering Custom Exceptions
- 9.5.1 Triggering Exceptions via throw
- 9.5.2 Knowing and Using Existing Runtime Exception Types
- 9.5.3 Testing Parameters and Good Error Messages
- 9.5.4 Declaring New Exception Classes
- 9.5.5 Custom Exceptions as Subclasses of Exception or RuntimeException?
- 9.5.6 Catching and Redirecting Exceptions*
- 9.5.7 Changing the Call Stack of Exceptions*
- 9.5.8 Nested Exceptions*
- 9.6 try with Resources (Automatic Resource Management)
- 9.6.1 try with Resources
- 9.6.2 The AutoCloseable Interface
- 9.6.3 Exceptions to close()
- 9.6.4 Types That Are AutoCloseable and Closeable
- 9.6.5 Using Multiple Resources
- 9.6.6 Suppressed Exceptions*
- 9.7 Special Features of Exception Handling*
- 9.7.1 Return Values for Thrown Exceptions
- 9.7.2 Exceptions and Returns Disappear: The Duo return and finally
- 9.7.3 throws on Overridden Methods
- 9.7.4 Unreachable catch Clauses
- 9.8 Hard Errors: Error*
- 9.9 Assertions*
- 9.9.1 Using Assertions in Custom Programs
- 9.9.2 Enabling Assertions and Runtime Errors
- 9.9.3 Enabling or Disabling Assertions More Detailed
- 9.10 Conclusion
- 10 Nested Types
- 10.1 Nested Classes, Interfaces, and Enumerations
- 10.2 Static Nested Types
- 10.2.1 Modifiers and Visibility
- 10.2.2 Records as Containers
- 10.2.3 Implementing Static Nested Types*
- 10.3 Non-Static Nested Types
- 10.3.1 Creating Instances of Inner Classes
- 10.3.2 The this Reference
- 10.3.3 Class Files Generated by the Compiler*
- 10.4 Local Classes
- 10.4.1 Example with a Custom Declaration
- 10.4.2 Using a Local Class for a Timer
- 10.5 Anonymous Inner Classes
- 10.5.1 Using an Anonymous Inner Class for the Timer
- 10.5.2 Implementing Anonymous Inner Classes*
- 10.5.3 Constructors of Anonymous Inner Classes
- 10.5.4 Accessing Local Variables from Local and Anonymous Classes*
- 10.5.5 Nested Classes Access Private Members
- 10.6 Nests
- 10.7 Conclusion
- 11 Special Types of Java SE
- 11.1 Object Is the Mother of All Classes
- 11.1.1 Class Objects
- 11.1.2 Object Identification with toString()
- 11.1.3 Object Equivalence with equals(...) and Identity
- 11.1.4 Cloning an Object Using clone()*
- 11.1.5 Returning Hash Values via hashCode()*
- 11.1.6 System.identityHashCode(...) and the Problem of Non-Unique Object References*
- 11.1.7 Synchronization*
- 11.2 Weak References and Cleaners
- 11.3 The java.util.Objects Utility Class
- 11.3.1 Built-In Null Tests for equals(...)/hashCode()
- 11.3.2 Objects.toString(…)
- 11.3.3 null Checks with Built-In Exception Handling
- 11.3.4 Tests for null
- 11.3.5 Checking Index-Related Program Arguments for Correctness
- 11.4 Comparing Objects and Establishing Order
- 11.4.1 Naturally Ordered or Not?
- 11.4.2 compare*() Method of the Comparable and Comparator Interfaces
- 11.4.3 Return Values Encode the Order
- 11.4.4 Sorting Candy by Calories Using a Sample Comparator
- 11.4.5 Tips for Comparator and Comparable Implementations
- 11.4.6 Static and Default Methods in Comparator
- 11.5 Wrapper Classes and Autoboxing
- 11.5.1 Creating Wrapper Objects
- 11.5.2 Conversions to a String Representation
- 11.5.3 Parsing from a String Representation
- 11.5.4 The Number Base Class for Numeric Wrapper Objects
- 11.5.5 Performing Comparisons with compare*(...), compareTo(...), equals(...), and Hash Values
- 11.5.6 Static Reduction Methods in Wrapper Classes
- 11.5.7 Constants for the Size of a Primitive Type*
- 11.5.8 Handling Unsigned Numbers*
- 11.5.9 The Integer and Long Classes
- 11.5.10 The Double and Float Classes for Floats
- 11.5.11 The Boolean Class
- 11.5.12 Autoboxing: Boxing and Unboxing
- 11.6 Iterator, Iterable*
- 11.6.1 The Iterator Interface
- 11.6.2 The Supplier of the Iterator
- 11.6.3 The Iterable Interface
- 11.6.4 Extended for and Iterable
- 11.6.5 Internal Iteration
- 11.6.6 Implementing a Custom Iterable*
- 11.7 Annotations in Java Platform, Standard Edition
- 11.7.1 Places for Annotations
- 11.7.2 Annotation Types from java.lang
- 11.7.3 @Deprecated
- 11.7.4 Annotations with Additional Information
- 11.7.5 @SuppressWarnings
- 11.8 Further Reading
- 12 Generics<T>
- 12.1 Introduction to Java Generics
- 12.1.1 Man versus Machine: Type Checking of the Compiler and the Runtime Environment
- 12.1.2 Rockets
- 12.1.3 Declaring Generic Types
- 12.1.4 Using Generics
- 12.1.5 Diamonds Are Forever
- 12.1.6 Generic Interfaces
- 12.1.7 Generic Methods/Constructors and Type Inference
- 12.2 Implementing Generics, Type Erasure, and Raw Types
- 12.2.1 Implementation Options
- 12.2.2 Type Erasure
- 12.2.3 Problems with Type Erasure
- 12.2.4 Raw Types
- 12.3 Restricting Types via Bounds
- 12.3.1 Simple Restrictions with extends
- 12.3.2 Other Supertypes with &
- 12.4 Type Parameters in the throws Clause*
- 12.4.1 Declaring a Class with Type Variable <E extends Exception>
- 12.4.2 Parameterized Type for Type Variable <E extends Exception>
- 12.5 Inheritance and Invariance with Generics
- 12.5.1 Arrays Are Covariant
- 12.5.2 Generics Aren’t Covariant, but Invariant
- 12.5.3 Wildcards with ?
- 12.5.4 Bounded Wildcards
- 12.5.5 Bounded Wildcard Types and Bounded Type Variables
- 12.5.6 The PECS Principle
- 12.6 Consequences of Type Erasure: Type Tokens, Arrays*
- 12.6.1 Type Tokens
- 12.6.2 Supertype Tokens
- 12.6.3 Generics and Arrays
- 12.7 Further Reading
- 13 Lambda Expressions and Functional Programming
- 13.1 Functional Interfaces and Lambda Expressions
- 13.1.1 Classes Implement Interfaces
- 13.1.2 Lambda Expressions Implement Interfaces
- 13.1.3 Functional Interfaces
- 13.1.4 The Type of a Lambda Expression Depends on the Target Type
- 13.1.5 @FunctionalInterface Annotations
- 13.1.6 Syntax for Lambda Expressions
- 13.1.7 The Environment of Lambda Expressions and Variable Accesses
- 13.1.8 Exceptions in Lambda Expressions
- 13.1.9 Classes with an Abstract Method as a Functional Interface?*
- 13.2 Method References
- 13.2.1 Motivation
- 13.2.2 Method References with ::
- 13.2.3 Variations of Method References
- 13.3 Constructor References
- 13.3.1 Writing Constructor References
- 13.3.2 Parameterless and Parameterized Constructors
- 13.3.3 Useful Predefined Interfaces for Constructor References
- 13.4 Functional Programming
- 13.4.1 Code = Data
- 13.4.2 Programming Paradigms: Imperative or Declarative
- 13.4.3 Principles of Functional Programming
- 13.4.4 Imperative Programming and Functional Programming
- 13.4.5 Comparator as an Example of Higher-Order Functions
- 13.4.6 Viewing Lambda Expressions as Mappings or Functions
- 13.5 Functional Interfaces from the java.util.function Package
- 13.5.1 Blocks with Code and the Functional Interface Consumer
- 13.5.2 Supplier
- 13.5.3 Predicates and java.util.function.Predicate
- 13.5.4 Functions via the Functional Interface java.util.function.Function
- 13.5.5 I Take Two
- 13.5.6 Functional Interfaces with Primitives
- 13.6 Optional Is Not a Non-Starter
- 13.6.1 Using null
- 13.6.2 The Optional Type
- 13.6.3 Starting Functional Interfaces with Optional
- 13.6.4 Primitive-Optional with Special Optional* Classes
- 13.7 What Is So Functional Now?
- 13.7.1 Recyclability
- 13.7.2 Stateless, Immutable
- 13.8 Further Reading
- 14 Architecture, Design, and Applied Object Orientation
- 14.1 SOLID Modeling
- 14.1.1 Three Rules
- 14.1.2 SOLID
- 14.1.3 Don’t Be STUPID
- 14.2 Architecture, Design, and Implementation
- 14.3 Design Patterns
- 14.3.1 Motivation for Design Patterns
- 14.3.2 Singleton
- 14.3.3 Factory Methods
- 14.3.4 Implementing the Observer Pattern with Listeners
- 14.4 Further Reading
- 15 Java Platform Module System
- 15.1 Class Loader and Module/Classpath
- 15.1.1 Loading Classes per Request
- 15.1.2 Watching the Class Loader at Work
- 15.1.3 JMOD Files and JAR Files
- 15.1.4 Where the Classes Come from: Search Locations and Special Class Loaders
- 15.1.5 Setting the Search Path
- 15.2 Importing Modules
- 15.2.1 Who Sees Whom?
- 15.2.2 Platform Modules and a JMOD Example
- 15.2.3 Using Internal Platform Features: –add-exports
- 15.2.4 Integrating New Modules
- 15.3 Developing Custom Modules
- 15.3.1 Module com.tutego.candytester
- 15.3.2 Module Declaration with module-info.java and Exports
- 15.3.3 Module com.tutego.main
- 15.3.4 Module info File with requires
- 15.3.5 Writing Module Inserters: Java Virtual Machine Switches -p and -m
- 15.3.6 Experiments with the Module Info File
- 15.3.7 Automatic Modules
- 15.3.8 Unnamed Modules
- 15.3.9 Readability and Accessibility
- 15.3.10 Module Migration
- 15.4 Further Reading
- 16 The Class Library
- 16.1 The Java Class Philosophy
- 16.1.1 Modules, Packages, and Types
- 16.1.2 Overview of the Packages of the Standard Library
- 16.2 Simple Time Measurement and Profiling*
- 16.3 The Class Class
- 16.3.1 Obtaining a Class Object
- 16.3.2 A Class Is a Type
- 16.4 The Utility Classes System and Members
- 16.4.1 Memory of the Java Virtual Machine
- 16.4.2 Number of CPUs or Cores
- 16.4.3 System Properties of the Java Environment
- 16.4.4 Setting Custom Properties from the Console*
- 16.4.5 Newline Characters and line.separator
- 16.4.6 Environment Variables of the Operating System
- 16.5 The Languages of Different Countries
- 16.5.1 Regional Languages via Locale Objects
- 16.6 Overview of Important Date Classes
- 16.6.1 Unix Time: January 1, 1970
- 16.6.2 System.currentTimeMillis()
- 16.6.3 Simple Time Conversions via TimeUnit
- 16.7 Date-Time API
- 16.7.1 Initial Overview
- 16.7.2 Human Time and Machine Time
- 16.7.3 The LocalDate Date Class
- 16.8 Logging with Java
- 16.8.1 Logging Application Programming Interfaces
- 16.8.2 Logging with java.util.logging
- 16.9 Maven: Resolving Build Management and Dependencies
- 16.9.1 Dependency to Be Accepted
- 16.9.2 Local and the Remote Repository
- 16.9.3 Lifecycles, Stages, and Maven Plugins
- 16.10 Further Reading
- 17 Introduction to Concurrent Programming
- 17.1 Concurrency and Parallelism
- 17.1.1 Multitasking, Processes, and Threads
- 17.1.2 Threads and Processes
- 17.1.3 How Concurrent Programs Can Increase Speed
- 17.1.4 How Java Can Provide for Concurrency
- 17.2 Generating Existing Threads and New Threads
- 17.2.1 Main Thread
- 17.2.2 Who Am I?
- 17.2.3 Implementing the Runnable Interface
- 17.2.4 Starting Thread with Runnable
- 17.2.5 Parameterizing Runnable
- 17.2.6 Extending the Thread Class*
- 17.3 Thread Members and States
- 17.3.1 The Name of a Thread
- 17.3.2 The States of a Thread*
- 17.3.3 Sleepers Wanted
- 17.3.4 When Threads Are Finished
- 17.3.5 Terminating a Thread Politely Using Interrupts
- 17.3.6 Unhandled Exceptions, Thread End, and UncaughtExceptionHandler
- 17.3.7 The stop() from the Outside and the Rescue with ThreadDeath*
- 17.3.8 Stopping and Resuming the Work*
- 17.3.9 Priority*
- 17.4 Enter the Executor
- 17.4.1 The Executor Interface
- 17.4.2 Happy as a Group: The Thread Pools
- 17.4.3 Threads with return via Callable
- 17.4.4 Memories of the Future: The Future Return
- 17.4.5 Processing Multiple Callable Objects
- 17.4.6 CompletionService and ExecutorCompletionService
- 17.4.7 ScheduledExecutorService: Repetitive Tasks and Time Controls
- 17.4.8 Asynchronous Programming with CompletableFuture (CompletionStage)
- 17.5 Further Reading
- 18 Introduction to Data Structures and Algorithms
- 18.1 Lists
- 18.1.1 First List Example
- 18.1.2 Selection Criterion ArrayList or LinkedList
- 18.1.3 The List Interface
- 18.1.4 ArrayList
- 18.1.5 LinkedList
- 18.1.6 The Array Adapter Arrays.asList(...)
- 18.1.7 ListIterator*
- 18.1.8 Understanding toArray(...) of Collection: Recognizing Traps
- 18.1.9 Managing Primitive Elements in Data Structures
- 18.2 Sets
- 18.2.1 A First Example of a Set
- 18.2.2 Methods of the Set Interface
- 18.2.3 HashSet
- 18.2.4 TreeSet: The Sorted Set
- 18.2.5 The Interfaces NavigableSet and SortedSet
- 18.2.6 LinkedHashSet
- 18.3 Associative Memory
- 18.3.1 The HashMap and TreeMap Classes and Static Map Methods
- 18.3.2 Inserting and Querying the Associative Memory
- 18.4 The Stream API
- 18.4.1 Declarative Programming
- 18.4.2 Internal versus External Iteration
- 18.4.3 What Is a Stream?
- 18.5 Creating a Stream
- 18.5.1 Stream.of*(…)
- 18.5.2 Stream.generate(…)
- 18.5.3 Stream.iterate(…)
- 18.5.4 Parallel or Sequential Streams
- 18.6 Terminal Operations
- 18.6.1 Number of Elements
- 18.6.2 And Now All: forEach*(…)
- 18.6.3 Getting Individual Elements from the Stream
- 18.6.4 Existence Tests with Predicates
- 18.6.5 Reducing a Stream to Its Smallest or Largest Element
- 18.6.6 Reducing a Stream with Its Own Functions
- 18.6.7 Writing Results to a Container, Part 1: collect(...)
- 18.6.8 Writing Results to a Container, Part 2: Collector and Collectors
- 18.6.9 Writing Results to a Container, Part 3: Groupings
- 18.6.10 Transferring Stream Elements to an Array or an Iterator
- 18.7 Intermediary Operations
- 18.7.1 Element Previews
- 18.7.2 Filtering Elements
- 18.7.3 Stateful Intermediary Operations
- 18.7.4 Prefix Operations
- 18.7.5 Images
- 18.8 Further Reading
- 19 Files and Data Streams
- 19.1 Old and New Worlds in java.io and java.nio
- 19.1.1 java.io Package with the File Class
- 19.1.2 NIO.2 and the java.nio Package
- 19.2 File Systems and Paths
- 19.2.1 FileSystem and Path
- 19.2.2 The Files Utility Class
- 19.3 Random Access Files
- 19.3.1 Opening a RandomAccessFile for Reading and Writing
- 19.3.2 Reading from RandomAccessFile
- 19.3.3 Writing with RandomAccessFile
- 19.3.4 The Length of the RandomAccessFile
- 19.3.5 Back and Forth within the File
- 19.4 Base Classes for Input/Output
- 19.4.1 The Four Abstract Base Classes
- 19.4.2 The Abstract Base Class OutputStream
- 19.4.3 The Abstract Base Class InputStream
- 19.4.4 The Abstract Base Class Writer
- 19.4.5 The Appendable Interface*
- 19.4.6 The Abstract Base Class Reader
- 19.4.7 The Interfaces Closeable, AutoCloseable, and Flushable
- 19.5 Reading from Files and Writing to Files
- 19.5.1 Obtaining Byte-Oriented Data Streams via Files
- 19.5.2 Obtaining Character-Oriented Data Streams via Files
- 19.5.3 The Function of OpenOption in the Files.new*(...) Methods
- 19.5.4 Loading Resources from the Module Path and from JAR Files
- 19.6 Further Reading
- 20 Introduction to Database Management with JDBC
- 20.1 Relational Databases and Java Access
- 20.1.1 The Relational Model
- 20.1.2 Java Application Programming Interfaces for Accessing Relational Databases
- 20.1.3 The JDBC API and Implementations: The JDBC Driver
- 20.1.4 H2 Is the Tool in Java
- 20.2 A Sample Query
- 20.2.1 Steps to Query the Database
- 20.2.2 Accessing the Relational Database with Java
- 20.3 Further Reading
- 21 Bits and Bytes, Mathematics and Money
- 21.1 Bits and Bytes
- 21.1.1 The Bit Operators: Complement, AND, OR, and XOR
- 21.1.2 Representation of Integers in Java: Two’s Complement
- 21.1.3 The Binary, Octal, and Hexadecimal Place Value Systems
- 21.1.4 Effect of Typecasting on Bit Patterns
- 21.1.5 Working without Signs
- 21.1.6 The Shift Operators
- 21.1.7 Setting, Clearing, Reversing, and Testing a Bit
- 21.1.8 Bit Methods of the Integer and Long Classes
- 21.2 Floating Point Arithmetic in Java
- 21.2.1 Special Values for Infinity, Zero, and Not a Number
- 21.2.2 Standard Notation and Scientific Notation for Floats*
- 21.2.3 Mantissas and Exponents*
- 21.3 The Members of the Math Class
- 21.3.1 Object Variables of the Math Class
- 21.3.2 Absolute Values and Signs
- 21.3.3 Maximums/Minimums
- 21.3.4 Rounding Values
- 21.3.5 Remainder of an Integer Division*
- 21.3.6 Division with Rounding toward Negative Infinity and Alternative Remainders*
- 21.3.7 Multiply-Accumulate
- 21.3.8 Square Root and Exponential Methods
- 21.3.9 The Logarithm*
- 21.3.10 Angle Methods*
- 21.3.11 Random Numbers
- 21.4 Accuracy and the Value Range of Type and Overflow Control*
- 21.4.1 The Largest and Smallest Values
- 21.4.2 Overflow and Everything Entirely Exact
- 21.4.3 What in the World Does the ulp Method Do?
- 21.5 Random Numbers: Random, ThreadLocalRandom, and SecureRandom
- 21.5.1 The Random Class
- 21.5.2 ThreadLocalRandom
- 21.5.3 The SecureRandom Class*
- 21.6 Large Numbers*
- 21.6.1 The BigInteger Class
- 21.6.2 Example: Quite Long Factorials with BigInteger
- 21.6.3 Large Floats with BigDecimal
- 21.6.4 Conveniently Setting the Calculation Accuracy via MathContext
- 21.6.5 Calculating even Faster with Mutable Implementations
- 21.7 Money and Currency
- 21.7.1 Representing Amounts of Money
- 21.7.2 ISO 4217
- 21.7.3 Representing Currencies in Java
- 21.8 Further Reading
- 22 Testing with JUnit
- 22.1 Software Tests
- 22.1.1 Procedure for Writing Test Cases
- 22.2 The JUnit Testing Framework
- 22.2.1 JUnit Versions
- 22.2.2 Integrating JUnit
- 22.2.3 Test-Driven Development and the Test-First Approach
- 22.2.4 Test, Implement, Test, Implement, Test, Rejoice
- 22.2.5 Running JUnit Tests
- 22.2.6 assert*(...) Methods of the Assertions Class
- 22.2.7 Testing Exceptions
- 22.2.8 Setting Limits for Execution Times
- 22.2.9 Labels with @DisplayName
- 22.2.10 Nested Tests
- 22.2.11 Ignoring Tests
- 22.2.12 Canceling Tests with Methods of the Assumptions Class
- 22.2.13 Parameterized Tests
- 22.3 Java Assertion Libraries and AssertJ
- 22.4 Structure of Large Test Cases
- 22.4.1 Fixtures
- 22.4.2 Collections of Test Classes and Class Organization
- 22.5 Good Design Enables Effective Testing
- 22.6 Dummy, Fake, Stub, and Mock
- 22.7 JUnit Extensions and Testing Add-Ons
- 22.7.1 Web Tests
- 22.7.2 Testing the Database Interface
- 22.8 Further Reading
- 23 The Tools of the JDK
- 23.1 Overview
- 23.1.1 Structure and Common Switches
- 23.2 Translating Java Sources
- 23.2.1 The Java Compiler of the Java Development Kit
- 23.2.2 Native Compilers
- 23.3 The Java Runtime Environment
- 23.3.1 Switches of the Java Virtual Machine
- 23.3.2 The Difference between java.exe and javaw.exe
- 23.4 Documentation Comments with Javadoc
- 23.4.1 Setting a Documentation Comment
- 23.4.2 Creating Documentation with the javadoc Tool
- 23.4.3 HTML Tags in Documentation Comments*
- 23.4.4 Generated Files
- 23.4.5 Documentation Comments at a Glance*
- 23.4.6 Javadoc and Doclets*
- 23.4.7 Deprecated Types and Members
- 23.4.8 Javadoc Verification with DocLint
- 23.5 The JAR Archive Format
- 23.5.1 Using the jar Utility
- 23.5.2 The Manifest
- 23.5.3 Launching Applications in Java Archives: Executable JAR Files
- 23.6 Further Reading
- The Author
- Index