Core Java Se 9 For The Impatient [2 ed.] 2017947587, 9780134694726, 0134694724

Core Java 9 Cay S. Horstmann is a concise guide that includes all the latest changes up to Java SE 9 and 10. This traini

1,971 314 21MB

English Pages 566 [1818] Year 2017

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Core Java Se 9 For The Impatient [2 ed.]
 2017947587, 9780134694726, 0134694724

  • Commentary
  • decrypted from 12D1849263575040F05C851E3FA6EC65 source file

Table of contents :
Title Page
Copyright Page
Dedication Page
Contents
Preface
Acknowledgments
About the Author
Chapter 1. Fundamental Programming Structures
1.1 Our First Program
1.1.1 Dissecting the “Hello, World” Program
1.1.2 Compiling and Running a Java Program
1.1.3 Method Calls
1.1.4 JShell
1.2 Primitive Types
1.2.1 Signed Integer Types
1.2.2 Floating-Point Types
1.2.3 The char Type
1.2.4 The boolean Type
1.3 Variables
1.3.1 Variable Declarations
1.3.2 Names
1.3.3 Initialization
1.3.4 Constants
1.4 Arithmetic Operations
1.4.1 Assignment
1.4.2 Basic Arithmetic
1.4.3 Mathematical Methods
1.4.4 Number Type Conversions
1.4.5 Relational and Logical Operators
1.4.6 Big Numbers
1.5 Strings
1.5.1 Concatenation
1.5.2 Substrings
1.5.3 String Comparison
1.5.4 Converting Between Numbers and Strings
1.5.5 The String API
1.5.6 Code Points and Code Units
1.6 Input and Output
1.6.1 Reading Input
1.6.2 Formatted Output
1.7 Control Flow
1.7.1 Branches
1.7.2 Loops
1.7.3 Breaking and Continuing
1.7.4 Local Variable Scope
1.8 Arrays and Array Lists
1.8.1 Working with Arrays
1.8.2 Array Construction
1.8.3 Array Lists
1.8.4 Wrapper Classes for Primitive Types
1.8.5 The Enhanced for Loop
1.8.6 Copying Arrays and Array Lists
1.8.7 Array Algorithms
1.8.8 Command-Line Arguments
1.8.9 Multidimensional Arrays
1.9 Functional Decomposition
1.9.1 Declaring and Calling Static Methods
1.9.2 Array Parameters and Return Values
1.9.3 Variable Arguments
Exercises
Chapter 2. Object-Oriented Programming
2.1 Working with Objects
2.1.1 Accessor and Mutator Methods
2.1.2 Object References
2.2 Implementing Classes
2.2.1 Instance Variables
2.2.2 Method Headers
2.2.3 Method Bodies
2.2.4 Instance Method Invocations
2.2.5 The this Reference
2.2.6 Call by Value
2.3 Object Construction
2.3.1 Implementing Constructors
2.3.2 Overloading
2.3.3 Calling One Constructor from Another
2.3.4 Default Initialization
2.3.5 Instance Variable Initialization
2.3.6 Final Instance Variables
2.3.7 The Constructor with No Arguments
2.4 Static Variables and Methods
2.4.1 Static Variables
2.4.2 Static Constants
2.4.3 Static Initialization Blocks
2.4.4 Static Methods
2.4.5 Factory Methods
2.5 Packages
2.5.1 Package Declarations
2.5.2 The jar Command
2.5.3 The Class Path
2.5.4 Package Access
2.5.5 Importing Classes
2.5.6 Static Imports
2.6 Nested Classes
2.6.1 Static Nested Classes
2.6.2 Inner Classes
2.6.3 Special Syntax Rules for Inner Classes
2.7 Documentation Comments
2.7.1 Comment Insertion
2.7.2 Class Comments
2.7.3 Method Comments
2.7.4 Variable Comments
2.7.5 General Comments
2.7.6 Links
2.7.7 Package, Module, and Overview Comments
2.7.8 Comment Extraction
Exercises
Chapter 3. Interfaces and Lambda Expressions
3.1 Interfaces
3.1.1 Declaring an Interface
3.1.2 Implementing an Interface
3.1.3 Converting to an Interface Type
3.1.4 Casts and the instanceof Operator
3.1.5 Extending Interfaces
3.1.6 Implementing Multiple Interfaces
3.1.7 Constants
3.2 Static, Default, and Private Methods
3.2.1 Static Methods
3.2.2 Default Methods
3.2.3 Resolving Default Method Conflicts
3.2.4 Private Methods
3.3 Examples of Interfaces
3.3.1 The Comparable Interface
3.3.2 The Comparator Interface
3.3.3 The Runnable Interface
3.3.4 User Interface Callbacks
3.4 Lambda Expressions
3.4.1 The Syntax of Lambda Expressions
3.4.2 Functional Interfaces
3.5 Method and Constructor References
3.5.1 Method References
3.5.2 Constructor References
3.6 Processing Lambda Expressions
3.6.1 Implementing Deferred Execution
3.6.2 Choosing a Functional Interface
3.6.3 Implementing Your Own Functional Interfaces
3.7 Lambda Expressions and Variable Scope
3.7.1 Scope of a Lambda Expression
3.7.2 Accessing Variables from the Enclosing Scope
3.8 Higher-Order Functions
3.8.1 Methods that Return Functions
3.8.2 Methods That Modify Functions
3.8.3 Comparator Methods
3.9 Local and Anonymous Classes
3.9.1 Local Classes
3.9.2 Anonymous Classes
Exercises
Chapter 4. Inheritance and Reflection
4.1 Extending a Class
4.1.1 Super- and Subclasses
4.1.2 Defining and Inheriting Subclass Methods
4.1.3 Method Overriding
4.1.4 Subclass Construction
4.1.5 Superclass Assignments
4.1.6 Casts
4.1.7 Final Methods and Classes
4.1.8 Abstract Methods and Classes
4.1.9 Protected Access
4.1.10 Anonymous Subclasses
4.1.11 Inheritance and Default Methods
4.1.12 Method Expressions with super
4.2 Object: The Cosmic Superclass
4.2.1 The toString Method
4.2.2 The equals Method
4.2.3 The hashCode Method
4.2.4 Cloning Objects
4.3 Enumerations
4.3.1 Methods of Enumerations
4.3.2 Constructors, Methods, and Fields
4.3.3 Bodies of Instances
4.3.4 Static Members
4.3.5 Switching on an Enumeration
4.4 Runtime Type Information and Resources
4.4.1 The Class Class
4.4.2 Loading Resources
4.4.3 Class Loaders
4.4.4 The Context Class Loader
4.4.5 Service Loaders
4.5 Reflection
4.5.1 Enumerating Class Members
4.5.2 Inspecting Objects
4.5.3 Invoking Methods
4.5.4 Constructing Objects
4.5.5 JavaBeans
4.5.6 Working with Arrays
4.5.7 Proxies
Exercises
Chapter 5. Exceptions, Assertions, and Logging
5.1 Exception Handling
5.1.1 Throwing Exceptions
5.1.2 The Exception Hierarchy
5.1.3 Declaring Checked Exceptions
5.1.4 Catching Exceptions
5.1.5 The Try-with-Resources Statement
5.1.6 The finally Clause
5.1.7 Rethrowing and Chaining Exceptions
5.1.8 Uncaught Exceptions and the Stack Trace
5.1.9 The Objects.requireNonNull Method
5.2 Assertions
5.2.1 Using Assertions
5.2.2 Enabling and Disabling Assertions
5.3 Logging
5.3.1 Using Loggers
5.3.2 Loggers
5.3.3 Logging Levels
5.3.4 Other Logging Methods
5.3.5 Logging Configuration
5.3.6 Log Handlers
5.3.7 Filters and Formatters
Exercises
Chapter 6. Generic Programming
6.1 Generic Classes
6.2 Generic Methods
6.3 Type Bounds
6.4 Type Variance and Wildcards
6.4.1 Subtype Wildcards
6.4.2 Supertype Wildcards
6.4.3 Wildcards with Type Variables
6.4.4 Unbounded Wildcards
6.4.5 Wildcard Capture
6.5 Generics in the Java Virtual Machine
6.5.1 Type Erasure
6.5.2 Cast Insertion
6.5.3 Bridge Methods
6.6 Restrictions on Generics
6.6.1 No Primitive Type Arguments
6.6.2 At Runtime, All Types Are Raw
6.6.3 You Cannot Instantiate Type Variables
6.6.4 You Cannot Construct Arrays of Parameterized Types
6.6.5 Class Type Variables Are Not Valid in Static Contexts
6.6.6 Methods May Not Clash after Erasure
6.6.7 Exceptions and Generics
6.7 Reflection and Generics
6.7.1 The Class Class
6.7.2 Generic Type Information in the Virtual Machine
Exercises
Chapter 7. Collections
7.1 An Overview of the Collections Framework
7.2 Iterators
7.3 Sets
7.4 Maps
7.5 Other Collections
7.5.1 Properties
7.5.2 Bit Sets
7.5.3 Enumeration Sets and Maps
7.5.4 Stacks, Queues, Deques, and Priority Queues
7.5.5 Weak Hash Maps
7.6 Views
7.6.1 Small Collections
7.6.2 Ranges
7.6.3 Unmodifiable Views
Exercises
Chapter 8. Streams
8.1 From Iterating to Stream Operations
8.2 Stream Creation
8.3 The filter, map, and flatMap Methods
8.4 Extracting Substreams and Combining Streams
8.5 Other Stream Transformations
8.6 Simple Reductions
8.7 The Optional Type
8.7.1 How to Work with Optional Values
8.7.2 How Not to Work with Optional Values
8.7.3 Creating Optional Values
8.7.4 Composing Optional Value Functions with flatMap
8.7.5 Turning an Optional Into a Stream
8.8 Collecting Results
8.9 Collecting into Maps
8.10 Grouping and Partitioning
8.11 Downstream Collectors
8.12 Reduction Operations
8.13 Primitive Type Streams
8.14 Parallel Streams
Exercises
Chapter 9. Processing Input and Output
9.1 Input/Output Streams, Readers, and Writers
9.1.1 Obtaining Streams
9.1.2 Reading Bytes
9.1.3 Writing Bytes
9.1.4 Character Encodings
9.1.5 Text Input
9.1.6 Text Output
9.1.7 Reading and Writing Binary Data
9.1.8 Random-Access Files
9.1.9 Memory-Mapped Files
9.1.10 File Locking
9.2 Paths, Files, and Directories
9.2.1 Paths
9.2.2 Creating Files and Directories
9.2.3 Copying, Moving, and Deleting Files
9.2.4 Visiting Directory Entries
9.2.5 ZIP File Systems
9.3 HTTP Connections
9.3.1 The URLConnection and HttpURLConnection Classes
9.3.2 The HTTP Client API
9.4 Regular Expressions
9.4.1 The Regular Expression Syntax
9.4.2 Finding One Match
9.4.3 Finding All Matches
9.4.4 Groups
9.4.5 Splitting along Delimiters
9.4.6 Replacing Matches
9.4.7 Flags
9.5 Serialization
9.5.1 The Serializable Interface
9.5.2 Transient Instance Variables
9.5.3 The readObject and writeObject Methods
9.5.4 The readResolve and writeReplace Methods
9.5.5 Versioning
Exercises
Chapter 10. Concurrent Programming
10.1 Concurrent Tasks
10.1.1 Running Tasks
10.1.2 Futures
10.2 Asynchronous Computations
10.2.1 Completable Futures
10.2.2 Composing Completable Futures
10.2.3 Long-Running Tasks in User-Interface Callbacks
10.3 Thread Safety
10.3.1 Visibility
10.3.2 Race Conditions
10.3.3 Strategies for Safe Concurrency
10.3.4 Immutable Classes
10.4 Parallel Algorithms
10.4.1 Parallel Streams
10.4.2 Parallel Array Operations
10.5 Threadsafe Data Structures
10.5.1 Concurrent Hash Maps
10.5.2 Blocking Queues
10.5.3 Other Threadsafe Data Structures
10.6 Atomic Counters and Accumulators
10.7 Locks and Conditions
10.7.1 Locks
10.7.2 The synchronized Keyword
10.7.3 Waiting on Conditions
10.8 Threads
10.8.1 Starting a Thread
10.8.2 Thread Interruption
10.8.3 Thread-Local Variables
10.8.4 Miscellaneous Thread Properties
10.9 Processes
10.9.1 Building a Process
10.9.2 Running a Process
10.9.3 Process Handles
Exercises
Chapter 11. Annotations
11.1 Using Annotations
11.1.1 Annotation Elements
11.1.2 Multiple and Repeated Annotations
11.1.3 Annotating Declarations
11.1.4 Annotating Type Uses
11.1.5 Making Receivers Explicit
11.2 Defining Annotations
11.3 Standard Annotations
11.3.1 Annotations for Compilation
11.3.2 Annotations for Managing Resources
11.3.3 Meta-Annotations
11.4 Processing Annotations at Runtime
11.5 Source-Level Annotation Processing
11.5.1 Annotation Processors
11.5.2 The Language Model API
11.5.3 Using Annotations to Generate Source Code
Exercises
Chapter 12. The Date and Time API
12.1 The Time Line
12.2 Local Dates
12.3 Date Adjusters
12.4 Local Time
12.5 Zoned Time
12.6 Formatting and Parsing
12.7 Interoperating with Legacy Code
Exercises
Chapter 13. Internationalization
13.1 Locales
13.1.1 Specifying a Locale
13.1.2 The Default Locale
13.1.3 Display Names
13.2 Number Formats
13.3 Currencies
13.4 Date and Time Formatting
13.5 Collation and Normalization
13.6 Message Formatting
13.7 Resource Bundles
13.7.1 Organizing Resource Bundles
13.7.2 Bundle Classes
13.8 Character Encodings
13.9 Preferences
Exercises
Chapter 14. Compiling and Scripting
14.1 The Compiler API
14.1.1 Invoking the Compiler
14.1.2 Launching a Compilation Task
14.1.3 Reading Source Files from Memory
14.1.4 Writing Byte Codes to Memory
14.1.5 Capturing Diagnostics
14.2 The Scripting API
14.2.1 Getting a Scripting Engine
14.2.2 Bindings
14.2.3 Redirecting Input and Output
14.2.4 Calling Scripting Functions and Methods
14.2.5 Compiling a Script
14.3 The Nashorn Scripting Engine
14.3.1 Running Nashorn from the Command Line
14.3.2 Invoking Getters, Setters, and Overloaded Methods
14.3.3 Constructing Java Objects
14.3.4 Strings in JavaScript and Java
14.3.5 Numbers
14.3.6 Working with Arrays
14.3.7 Lists and Maps
14.3.8 Lambdas
14.3.9 Extending Java Classes and Implementing Java Interfaces
14.3.10 Exceptions
14.4 Shell Scripting with Nashorn
14.4.1 Executing Shell Commands
14.4.2 String Interpolation
14.4.3 Script Inputs
Exercises
Chapter 15. The Java Platform Module System
15.1 The Module Concept
15.2 Naming Modules
15.3 The Modular “Hello, World!” Program
15.4 Requiring Modules
15.5 Exporting Packages
15.6 Modules and Reflective Access
15.7 Modular JARs
15.8 Automatic Modules and the Unnamed Module
15.9 Command-Line Flags for Migration
15.10 Transitive and Static Requirements
15.11 Qualified Exporting and Opening
15.12 Service Loading
15.13 Tools for Working with Modules
Exercises
Index

Citation preview

WOW! eBook www.wowebook.org

Core Java® SE 9 for the Impatient Second Edition Cay S. Horstmann

Boston • Columbus • Indianapolis • New York • San Francisco • Amsterdam • Cape Town Dubai • London • Madrid • Milan • Munich • Paris • Montreal • Toronto • Delhi • Mexico City São Paulo • Sydney • Hong Kong • Seoul • Singapore • Taipei • Tokyo

WOW! eBook www.wowebook.org

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and the publisher was aware of a trademark claim, the designations have been printed with initial capital letters or in all capitals. The author and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential damages in connection with or arising out of the use of the information or programs contained herein. For information about buying this title in bulk quantities, or for special sales opportunities (which may include electronic versions; custom cover designs; and content particular to your business, training goals, marketing focus, or branding interests), please contact our corporate sales department at [email protected] or (800) 382-3419. For government sales inquiries, please contact [email protected]. For questions about sales outside the United States, please contact [email protected]. Visit us on the Web: informit.com/aw Library of Congress Control Number: 2017947587 Copyright © 2018 Pearson Education, Inc. Screenshots of Eclipse. Published by The Eclipse Foundation. Screenshots of Java. Published by Oracle. All rights reserved. Printed in the United States of America. This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise. For information regarding permissions, request forms and the appropriate contacts within the Pearson Education Global Rights & Permissions Department, please visit www.pearsoned.com/permissions/. ISBN-13: 978-0-13-469472-6 ISBN-10: 0-13-469472-4 1 17

WOW! eBook www.wowebook.org

To Chi—the most patient person in my life.

WOW! eBook www.wowebook.org

Contents Preface Acknowledgments About the Author 1 FUNDAMENTAL PROGRAMMING STRUCTURES 1.1 Our First Program 1.1.1 Dissecting the “Hello, World” Program 1.1.2 Compiling and Running a Java Program 1.1.3 Method Calls 1.1.4 JShell 1.2 Primitive Types 1.2.1 Signed Integer Types 1.2.2 Floating-Point Types 1.2.3 The char Type 1.2.4 The boolean Type 1.3 Variables 1.3.1 Variable Declarations 1.3.2 Names 1.3.3 Initialization 1.3.4 Constants 1.4 Arithmetic Operations 1.4.1 Assignment 1.4.2 Basic Arithmetic 1.4.3 Mathematical Methods 1.4.4 Number Type Conversions 1.4.5 Relational and Logical Operators 1.4.6 Big Numbers 1.5 Strings 1.5.1 Concatenation 1.5.2 Substrings 1.5.3 String Comparison 1.5.4 Converting Between Numbers and Strings WOW! eBook www.wowebook.org

1.5.5 The String API 1.5.6 Code Points and Code Units 1.6 Input and Output 1.6.1 Reading Input 1.6.2 Formatted Output 1.7 Control Flow 1.7.1 Branches 1.7.2 Loops 1.7.3 Breaking and Continuing 1.7.4 Local Variable Scope 1.8 Arrays and Array Lists 1.8.1 Working with Arrays 1.8.2 Array Construction 1.8.3 Array Lists 1.8.4 Wrapper Classes for Primitive Types 1.8.5 The Enhanced for Loop 1.8.6 Copying Arrays and Array Lists 1.8.7 Array Algorithms 1.8.8 Command-Line Arguments 1.8.9 Multidimensional Arrays 1.9 Functional Decomposition 1.9.1 Declaring and Calling Static Methods 1.9.2 Array Parameters and Return Values 1.9.3 Variable Arguments Exercises 2 OBJECT-ORIENTED PROGRAMMING 2.1 Working with Objects 2.1.1 Accessor and Mutator Methods 2.1.2 Object References 2.2 Implementing Classes 2.2.1 Instance Variables 2.2.2 Method Headers 2.2.3 Method Bodies 2.2.4 Instance Method Invocations WOW! eBook www.wowebook.org

2.2.5 The this Reference 2.2.6 Call by Value 2.3 Object Construction 2.3.1 Implementing Constructors 2.3.2 Overloading 2.3.3 Calling One Constructor from Another 2.3.4 Default Initialization 2.3.5 Instance Variable Initialization 2.3.6 Final Instance Variables 2.3.7 The Constructor with No Arguments 2.4 Static Variables and Methods 2.4.1 Static Variables 2.4.2 Static Constants 2.4.3 Static Initialization Blocks 2.4.4 Static Methods 2.4.5 Factory Methods 2.5 Packages 2.5.1 Package Declarations 2.5.2 The jar Command 2.5.3 The Class Path 2.5.4 Package Access 2.5.5 Importing Classes 2.5.6 Static Imports 2.6 Nested Classes 2.6.1 Static Nested Classes 2.6.2 Inner Classes 2.6.3 Special Syntax Rules for Inner Classes 2.7 Documentation Comments 2.7.1 Comment Insertion 2.7.2 Class Comments 2.7.3 Method Comments 2.7.4 Variable Comments 2.7.5 General Comments 2.7.6 Links 2.7.7 Package, Module, and Overview Comments WOW! eBook www.wowebook.org

2.7.8 Comment Extraction Exercises 3 INTERFACES AND LAMBDA EXPRESSIONS 3.1 Interfaces 3.1.1 Declaring an Interface 3.1.2 Implementing an Interface 3.1.3 Converting to an Interface Type 3.1.4 Casts and the instanceof Operator 3.1.5 Extending Interfaces 3.1.6 Implementing Multiple Interfaces 3.1.7 Constants 3.2 Static, Default, and Private Methods 3.2.1 Static Methods 3.2.2 Default Methods 3.2.3 Resolving Default Method Conflicts 3.2.4 Private Methods 3.3 Examples of Interfaces 3.3.1 The Comparable Interface 3.3.2 The Comparator Interface 3.3.3 The Runnable Interface 3.3.4 User Interface Callbacks 3.4 Lambda Expressions 3.4.1 The Syntax of Lambda Expressions 3.4.2 Functional Interfaces 3.5 Method and Constructor References 3.5.1 Method References 3.5.2 Constructor References 3.6 Processing Lambda Expressions 3.6.1 Implementing Deferred Execution 3.6.2 Choosing a Functional Interface 3.6.3 Implementing Your Own Functional Interfaces 3.7 Lambda Expressions and Variable Scope 3.7.1 Scope of a Lambda Expression 3.7.2 Accessing Variables from the Enclosing Scope WOW! eBook www.wowebook.org

3.8 Higher-Order Functions 3.8.1 Methods that Return Functions 3.8.2 Methods That Modify Functions 3.8.3 Comparator Methods 3.9 Local and Anonymous Classes 3.9.1 Local Classes 3.9.2 Anonymous Classes Exercises 4 INHERITANCE AND REFLECTION 4.1 Extending a Class 4.1.1 Super- and Subclasses 4.1.2 Defining and Inheriting Subclass Methods 4.1.3 Method Overriding 4.1.4 Subclass Construction 4.1.5 Superclass Assignments 4.1.6 Casts 4.1.7 Final Methods and Classes 4.1.8 Abstract Methods and Classes 4.1.9 Protected Access 4.1.10 Anonymous Subclasses 4.1.11 Inheritance and Default Methods 4.1.12 Method Expressions with super 4.2 Object: The Cosmic Superclass 4.2.1 The toString Method 4.2.2 The equals Method 4.2.3 The hashCode Method 4.2.4 Cloning Objects 4.3 Enumerations 4.3.1 Methods of Enumerations 4.3.2 Constructors, Methods, and Fields 4.3.3 Bodies of Instances 4.3.4 Static Members 4.3.5 Switching on an Enumeration 4.4 Runtime Type Information and Resources WOW! eBook www.wowebook.org

4.4.1 The Class Class 4.4.2 Loading Resources 4.4.3 Class Loaders 4.4.4 The Context Class Loader 4.4.5 Service Loaders 4.5 Reflection 4.5.1 Enumerating Class Members 4.5.2 Inspecting Objects 4.5.3 Invoking Methods 4.5.4 Constructing Objects 4.5.5 JavaBeans 4.5.6 Working with Arrays 4.5.7 Proxies Exercises 5 EXCEPTIONS, ASSERTIONS, AND LOGGING 5.1 Exception Handling 5.1.1 Throwing Exceptions 5.1.2 The Exception Hierarchy 5.1.3 Declaring Checked Exceptions 5.1.4 Catching Exceptions 5.1.5 The Try-with-Resources Statement 5.1.6 The finally Clause 5.1.7 Rethrowing and Chaining Exceptions 5.1.8 Uncaught Exceptions and the Stack Trace 5.1.9 The Objects.requireNonNull Method 5.2 Assertions 5.2.1 Using Assertions 5.2.2 Enabling and Disabling Assertions 5.3 Logging 5.3.1 Using Loggers 5.3.2 Loggers 5.3.3 Logging Levels 5.3.4 Other Logging Methods 5.3.5 Logging Configuration

WOW! eBook www.wowebook.org

5.3.6 Log Handlers 5.3.7 Filters and Formatters Exercises 6 GENERIC PROGRAMMING 6.1 Generic Classes 6.2 Generic Methods 6.3 Type Bounds 6.4 Type Variance and Wildcards 6.4.1 Subtype Wildcards 6.4.2 Supertype Wildcards 6.4.3 Wildcards with Type Variables 6.4.4 Unbounded Wildcards 6.4.5 Wildcard Capture 6.5 Generics in the Java Virtual Machine 6.5.1 Type Erasure 6.5.2 Cast Insertion 6.5.3 Bridge Methods 6.6 Restrictions on Generics 6.6.1 No Primitive Type Arguments 6.6.2 At Runtime, All Types Are Raw 6.6.3 You Cannot Instantiate Type Variables 6.6.4 You Cannot Construct Arrays of Parameterized Types 6.6.5 Class Type Variables Are Not Valid in Static Contexts 6.6.6 Methods May Not Clash after Erasure 6.6.7 Exceptions and Generics 6.7 Reflection and Generics 6.7.1 The Class Class 6.7.2 Generic Type Information in the Virtual Machine Exercises 7 COLLECTIONS 7.1 An Overview of the Collections Framework 7.2 Iterators 7.3 Sets WOW! eBook www.wowebook.org

7.4 Maps 7.5 Other Collections 7.5.1 Properties 7.5.2 Bit Sets 7.5.3 Enumeration Sets and Maps 7.5.4 Stacks, Queues, Deques, and Priority Queues 7.5.5 Weak Hash Maps 7.6 Views 7.6.1 Small Collections 7.6.2 Ranges 7.6.3 Unmodifiable Views Exercises 8 STREAMS 8.1 From Iterating to Stream Operations 8.2 Stream Creation 8.3 The filter, map, and flatMap Methods 8.4 Extracting Substreams and Combining Streams 8.5 Other Stream Transformations 8.6 Simple Reductions 8.7 The Optional Type 8.7.1 How to Work with Optional Values 8.7.2 How Not to Work with Optional Values 8.7.3 Creating Optional Values 8.7.4 Composing Optional Value Functions with flatMap 8.7.5 Turning an Optional Into a Stream 8.8 Collecting Results 8.9 Collecting into Maps 8.10 Grouping and Partitioning 8.11 Downstream Collectors 8.12 Reduction Operations 8.13 Primitive Type Streams 8.14 Parallel Streams

WOW! eBook www.wowebook.org

Exercises 9 PROCESSING INPUT AND OUTPUT 9.1 Input/Output Streams, Readers, and Writers 9.1.1 Obtaining Streams 9.1.2 Reading Bytes 9.1.3 Writing Bytes 9.1.4 Character Encodings 9.1.5 Text Input 9.1.6 Text Output 9.1.7 Reading and Writing Binary Data 9.1.8 Random-Access Files 9.1.9 Memory-Mapped Files 9.1.10 File Locking 9.2 Paths, Files, and Directories 9.2.1 Paths 9.2.2 Creating Files and Directories 9.2.3 Copying, Moving, and Deleting Files 9.2.4 Visiting Directory Entries 9.2.5 ZIP File Systems 9.3 HTTP Connections 9.3.1 The URLConnection and HttpURLConnection Classes 9.3.2 The HTTP Client API 9.4 Regular Expressions 9.4.1 The Regular Expression Syntax 9.4.2 Finding One Match 9.4.3 Finding All Matches 9.4.4 Groups 9.4.5 Splitting along Delimiters 9.4.6 Replacing Matches 9.4.7 Flags 9.5 Serialization 9.5.1 The Serializable Interface 9.5.2 Transient Instance Variables 9.5.3 The readObject and writeObject Methods

WOW! eBook www.wowebook.org

9.5.4 The readResolve and writeReplace Methods 9.5.5 Versioning Exercises 10 CONCURRENT PROGRAMMING 10.1 Concurrent Tasks 10.1.1 Running Tasks 10.1.2 Futures 10.2 Asynchronous Computations 10.2.1 Completable Futures 10.2.2 Composing Completable Futures 10.2.3 Long-Running Tasks in User-Interface Callbacks 10.3 Thread Safety 10.3.1 Visibility 10.3.2 Race Conditions 10.3.3 Strategies for Safe Concurrency 10.3.4 Immutable Classes 10.4 Parallel Algorithms 10.4.1 Parallel Streams 10.4.2 Parallel Array Operations 10.5 Threadsafe Data Structures 10.5.1 Concurrent Hash Maps 10.5.2 Blocking Queues 10.5.3 Other Threadsafe Data Structures 10.6 Atomic Counters and Accumulators 10.7 Locks and Conditions 10.7.1 Locks 10.7.2 The synchronized Keyword 10.7.3 Waiting on Conditions 10.8 Threads 10.8.1 Starting a Thread 10.8.2 Thread Interruption 10.8.3 Thread-Local Variables 10.8.4 Miscellaneous Thread Properties 10.9 Processes WOW! eBook www.wowebook.org

10.9.1 Building a Process 10.9.2 Running a Process 10.9.3 Process Handles Exercises 11 ANNOTATIONS 11.1 Using Annotations 11.1.1 Annotation Elements 11.1.2 Multiple and Repeated Annotations 11.1.3 Annotating Declarations 11.1.4 Annotating Type Uses 11.1.5 Making Receivers Explicit 11.2 Defining Annotations 11.3 Standard Annotations 11.3.1 Annotations for Compilation 11.3.2 Annotations for Managing Resources 11.3.3 Meta-Annotations 11.4 Processing Annotations at Runtime 11.5 Source-Level Annotation Processing 11.5.1 Annotation Processors 11.5.2 The Language Model API 11.5.3 Using Annotations to Generate Source Code Exercises 12 THE DATE AND TIME API 12.1 The Time Line 12.2 Local Dates 12.3 Date Adjusters 12.4 Local Time 12.5 Zoned Time 12.6 Formatting and Parsing 12.7 Interoperating with Legacy Code Exercises 13 INTERNATIONALIZATION 13.1 Locales WOW! eBook www.wowebook.org

13.1.1 Specifying a Locale 13.1.2 The Default Locale 13.1.3 Display Names 13.2 Number Formats 13.3 Currencies 13.4 Date and Time Formatting 13.5 Collation and Normalization 13.6 Message Formatting 13.7 Resource Bundles 13.7.1 Organizing Resource Bundles 13.7.2 Bundle Classes 13.8 Character Encodings 13.9 Preferences Exercises 14 COMPILING AND SCRIPTING 14.1 The Compiler API 14.1.1 Invoking the Compiler 14.1.2 Launching a Compilation Task 14.1.3 Reading Source Files from Memory 14.1.4 Writing Byte Codes to Memory 14.1.5 Capturing Diagnostics 14.2 The Scripting API 14.2.1 Getting a Scripting Engine 14.2.2 Bindings 14.2.3 Redirecting Input and Output 14.2.4 Calling Scripting Functions and Methods 14.2.5 Compiling a Script 14.3 The Nashorn Scripting Engine 14.3.1 Running Nashorn from the Command Line 14.3.2 Invoking Getters, Setters, and Overloaded Methods 14.3.3 Constructing Java Objects 14.3.4 Strings in JavaScript and Java 14.3.5 Numbers 14.3.6 Working with Arrays WOW! eBook www.wowebook.org

14.3.7 Lists and Maps 14.3.8 Lambdas 14.3.9 Extending Java Classes and Implementing Java Interfaces 14.3.10 Exceptions 14.4 Shell Scripting with Nashorn 14.4.1 Executing Shell Commands 14.4.2 String Interpolation 14.4.3 Script Inputs Exercises 15 THE JAVA PLATFORM MODULE SYSTEM 15.1 The Module Concept 15.2 Naming Modules 15.3 The Modular “Hello, World!” Program 15.4 Requiring Modules 15.5 Exporting Packages 15.6 Modules and Reflective Access 15.7 Modular JARs 15.8 Automatic Modules and the Unnamed Module 15.9 Command-Line Flags for Migration 15.10 Transitive and Static Requirements 15.11 Qualified Exporting and Opening 15.12 Service Loading 15.13 Tools for Working with Modules Exercises Index

WOW! eBook www.wowebook.org

Preface Java is now over twenty years old, and the classic book, Core Java, covers, in meticulous detail, not just the language but all core libraries and a multitude of changes between versions, spanning two volumes and well over 2,000 pages. However, if you just want to be productive with modern Java, there is a much faster, easier pathway for learning the language and core libraries. In this book, I don't retrace history and don't dwell on features of past versions. I show you the good parts of Java as it exists today, with Java 9, so you can put your knowledge to work quickly. As with my previous "Impatient" books, I quickly cut to the chase, showing you what you need to know to solve a programming problem without lecturing about the superiority of one paradigm over another. I also present the information in small chunks, organized so that you can quickly retrieve it when needed. Assuming you are proficient in some other programming language, such as C++, JavaScript, Objective C, PHP, or Ruby, with this book you will learn how to become a competent Java programmer. I cover all aspects of Java that a developer needs to know, including the powerful concepts of lambda expressions and streams. I tell you where to find out more about old-fashioned concepts that you might still see in legacy code, but I don't dwell on them. A key reason to use Java is to tackle concurrent programming. With parallel algorithms and threadsafe data structures readily available in the Java library, the way application programmers should handle concurrent programming has completely changed. I provide fresh coverage, showing you how to use the powerful library features instead of error-prone low-level constructs. Traditionally, books on Java have focused on user interface programming—but nowadays, few developers produce user interfaces on desktop computers. If you intend to use Java for server-side programming or Android programming, you will be able to use this book effectively without being distracted by desktop GUI code. Finally, this book is written for application programmers, not for a college course and not for systems wizards. The book covers issues that application programmers need to wrestle with, such as logging and working with files—but you won't learn how to implement a linked list by hand or how to write a web server. I hope you enjoy this rapid-fire introduction into modern Java, and I hope it will make your work with Java productive and enjoyable. If you find errors or have suggestions for improvement, please visit http://horstmann.com/javaimpatient and leave a comment. On that page, you will WOW! eBook www.wowebook.org

also find a link to an archive file containing all code examples from the book.

WOW! eBook www.wowebook.org

Acknowledgments My thanks go, as always, to my editor Greg Doench, who enthusiastically supported the vision of a short book that gives a fresh introduction to Java SE 9. Dmitry Kirsanov and Alina Kirsanova once again turned an XHTML manuscript into an attractive book with amazing speed and attention to detail. My special gratitude goes to the excellent team of reviewers for both editions who spotted many errors and gave thoughtful suggestions for improvement. They are: Andres Almiray, Gail Anderson, Paul Anderson, Marcus Biel, Brian Goetz, Marty Hall, Mark Lawrence, Doug Lea, Simon Ritter, Yoshiki Shibata, and Christian Ullenboom. Cay Horstmann San Francisco July 2017

WOW! eBook www.wowebook.org

About the Author Cay S. Horstmann is the author of Java SE 8 for the Really Impatient and Scala for the Impatient (both from Addison-Wesley), is principal author of Core Java™, Volumes I and II, Tenth Edition (Prentice Hall, 2016), and has written a dozen other books for professional programmers and computer science students. He is a professor of computer science at San Jose State University and is a Java Champion.

WOW! eBook www.wowebook.org

Chapter 1. Fundamental Programming Structures Topics in This Chapter 1.1 Our First Program 1.2 Primitive Types 1.3 Variables 1.4 Arithmetic Operations 1.5 Strings 1.6 Input and Output 1.7 Control Flow 1.8 Arrays and Array Lists 1.9 Functional Decomposition Exercises In this chapter, you will learn about the basic data types and control structures of the Java language. I assume that you are an experienced programmer in some other language and that you are familiar with concepts such as variables, loops, function calls, and arrays, but perhaps with a different syntax. This chapter will get you up to speed on the Java way. I will also give you some tips on the most useful parts of the Java API for manipulating common data types. The key points of this chapter are: 1. In Java, all methods are declared in a class. You invoke a nonstatic method on an object of the class to which the method belongs. 2. Static methods are not invoked on objects. Program execution starts with the static main method. 3. Java has eight primitive types: four signed integral types, two floating-point types, char, and boolean. 4. The Java operators and control structures are very similar to those of C or JavaScript. 5. The Math class provides common mathematical functions. 6. String objects are sequences of characters or, more precisely, Unicode code

WOW! eBook www.wowebook.org

points in the UTF-16 encoding. 7. With the System.out object, you can display output in a terminal window. A Scanner tied to System.in lets you read terminal input. 8. Arrays and collections can be used to collect elements of the same type.

1.1 Our First Program When learning any new programming language, it is traditional to start with a program that displays the message “Hello, World!”. That is what we will do in the following sections.

1.1.1 Dissecting the “Hello, World” Program Without further ado, here is the “Hello, World” program in Java. Click here to view code image package ch01.sec01; // Our first Java program public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }

Let’s examine this program: • Java is an object-oriented language. In your program, you manipulate (mostly) objects by having them do work. Each object that you manipulate belongs to a specific class, and we say that the object is an instance of that class. A class defines what an object's state can be and and what it can do. In Java, all code is defined inside classes. We will look at objects and classes in detail in Chapter 2. This program is made up of a single class HelloWorld. • main is a method, that is, a function declared inside a class. The main method is the first method that is called when the program runs. It is declared as static to indicate that the method does not operate on any objects. (When main gets called, there are only a handful of predefined objects, and none of them are instances of the HelloWorld class.) The method is declared as void to indicate that it does not return any value. See Section 1.8.8, “Command-Line Arguments” (page 49) for the meaning of the parameter declaration String[] args.

WOW! eBook www.wowebook.org

• In Java, you can declare many features as public or private, and there are a couple of other visibility levels as well. Here, we declare the HelloWorld class and the main method as public, which is the most common arrangement for classes and methods. • A package is a set of related classes. It is a good idea to place each class in a package so you can group related classes together and avoid conflicts when multiple classes have the same name. In this book, we'll use chapter and section numbers as package names. The full name of our class is ch01.sec01.HelloWorld. Chapter 2 has more to say about packages and package naming conventions. • The line starting with // is a comment. All characters between // and the end of the line are ignored by the compiler and are meant for human readers only. • Finally, we come to the body of the main method. In our example, it consists of a single line with a command to print a message to System.out, an object representing the “standard output” of the Java program. As you can see, Java is not a scripting language that can be used to quickly dash off a few commands. It is squarely intended as a language for larger programs that benefit from being organized into classes, packages, and modules. (Modules are introduced in Chapter 15.) Java is also quite simple and uniform. Some languages have global variables and functions as well as variables and methods inside classes. In Java, everything is declared inside a class. This uniformity can lead to somewhat verbose code, but it makes it easy to understand the meaning of a program. Note You have just seen a // comment that extends to the end of the line. You can also have multiline comments between /* and */ delimiters, such as Click here to view code image /* This is the first sample program in Core Java for the Impatient. The program displays the traditional greeting "Hello, World!". */

There is a third comment style, called documentation comment, with /** and */ as delimiters, that you will see in the next chapter.

WOW! eBook www.wowebook.org

1.1.2 Compiling and Running a Java Program To compile and run this program, you need to install the Java Development Kit (JDK) and, optionally, an integrated development environment (IDE). You should also download the sample code, which you will find at the companion website for this book, http://horstmann.com/javaimpatient. Since instructions for installing software don't make for interesting reading, I put them on the companion website as well. Once you have installed the JDK, open a terminal window, change to the directory containing the ch01 directory, and run the commands Click here to view code image javac ch01/sec01/HelloWorld.java java ch01.sec01.HelloWorld

The familiar greeting will appear in the terminal window (see Figure 1-1).

Figure 1-1 Running a Java program in a terminal window Note that two steps were involved to execute the program. The javac command compiles the Java source code into an intermediate machine-independent WOW! eBook www.wowebook.org

representation, called byte codes, and saves them in class files. The java command launches a virtual machine that loads the class files and executes the byte codes. Once compiled, byte codes can run on any Java virtual machine, whether on your desktop computer or on a device in a galaxy far, far away. The promise of “write once, run anywhere” was an important design criterion for Java. Note The javac compiler is invoked with the name of a file, with slashes separating the path segments, and an extension .java. The java virtual machine launcher is invoked with the name of a class, with dots separating the package segments, and no extension. To run the program in an IDE, you need to first make a project, as described in the installation instructions. Then, select the HelloWorld class and tell the IDE to run it. Figure 1-2 shows how this looks in Eclipse. Eclipse is a popular IDE, but there are many other excellent choices. As you get more comfortable with Java programming, you should try out a few and pick one that you like.

WOW! eBook www.wowebook.org

Figure 1-2 Running a Java program inside the Eclipse IDE Congratulations! You have just followed the time-honored ritual of running the “Hello, World!” program in Java. Now we are ready to examine the basics of the Java language.

1.1.3 Method Calls Let us have a closer look at the single statement of the main method: Click here to view code image System.out.println("Hello, World!");

System.out is an object. It is an instance of a class called PrintStream. The PrintStream class has methods println, print, and so on. These methods are called instance methods because they operate on objects, or instances, of the class. To invoke an instance method on an object, you use the dot notation

WOW! eBook www.wowebook.org

object.methodName(arguments)

In this case, there is just one argument, the string "Hello, World!". Let's try it with another example. Strings such as "Hello, World!" are instances of the String class. The String class has a method length that returns the length of a String object. To call the method, you again use the dot notation: "Hello, World!".length()

The length method is invoked on the object "Hello, World!", and it has no arguments. Unlike the println method, the length method returns a result. One way of using that result is to print it: Click here to view code image System.out.println("Hello, World!".length());

Give it a try. Make a Java program with this statement and run it to see how long the string is. In Java, you need to construct most objects (unlike the System.out and "Hello, World!" objects, which are already there, ready for you to use). Here is a simple example. An object of the Random class can generate random numbers. You construct a Random object with the new operator: new Random()

After the class name is the list of construction arguments, which is empty in this example. You can call a method on the constructed object. The call new Random().nextInt()

yields the next integer that the newly constructed random number generator has to offer. If you want to invoke more than one method on an object, store it in a variable (see Section 1.3, “Variables,” page 14). Here we print two random numbers: Click here to view code image Random generator = new Random(); System.out.println(generator.nextInt()); System.out.println(generator.nextInt());

WOW! eBook www.wowebook.org

Note The Random class is declared in the java.util package. To use it in your program, add an import statement, like this: package ch01.sec01; import java.util.Random; public class MethodDemo { ... }

We will look at packages and the import statement in more detail in Chapter 2.

1.1.4 JShell In Section 1.1.2, “Compiling and Running a Java Program” (page 3), you saw how to compile and run a Java program. Java 9 introduces another way of working with Java. The JShell program provides a “read-evaluate-print loop” (REPL) where you type a Java expression, JShell evaluates your input, prints the result, and waits for your next input. To start JShell, simply type jshell in a terminal window (Figure 1-3).

WOW! eBook www.wowebook.org

Figure 1-3 Running JShell JShell starts with a greeting, followed by a prompt: Click here to view code image | |

Welcome to JShell -- Version 9-ea For an introduction type: /help intro

jshell>

Now type any Java expression, such as "Hello, World!".length()

JShell responds with the result and another prompt. $1 ==> 13 jshell>

Note that you do not type System.out.println. JShell automatically prints the value of every expression that you enter. The $1 in the output indicates that the result is available in further calculations. For example, if you type 3 * $1 + 3 WOW! eBook www.wowebook.org

the response is $2 ==> 42

If you need a variable many times, you can give it a more memorable name. You have to follow the Java syntax and specify both the type and the name (see Section 1.3, “Variables,” page 14). For example, jshell> int answer = 42 answer ==> 42

You can have JShell fill in the type for you. Type an expression and instead of hitting the Enter key, hit Shift+Tab and then the V key. For example, when you type new Random()

followed by Shift+Tab and the V key, you get jshell> Random

= new Random()

with the cursor positioned just before the = symbol. Now type a variable name and hit Enter: Click here to view code image jshell> Random generator = new Random() generator ==> java.util.Random@3fee9989

Another useful feature is tab completion. Type generator.

followed by the Tab key. You get a list of all methods that you can invoke on the generator variable: Click here to view code image jshell> generator. doubles( equals( ints( longs( nextDouble() nextFloat() nextLong() notify() toString() wait(

getClass() nextBoolean() nextGaussian() notifyAll()

hashCode() nextBytes( nextInt( setSeed(

Now type ne and hit the Tab key again. The method name is completed to next, and you get a shorter list: Click here to view code image jshell> generator.next nextBoolean() nextBytes(

nextDouble()

WOW! eBook www.wowebook.org

nextFloat()

nextGaussian()

nextInt(

nextLong()

Type a D and Tab again, and now the only completion, nextDouble(), is filled in. Hit Enter to accept it: Click here to view code image jshell> generator.nextDouble() $8 ==> 0.9560346568377398

Note Note that in the autocompletion list, methods that require an argument are only followed by a left parenthesis, such as nextInt(, but methods without arguments have both parentheses, such as nextBoolean(). To repeat a command, hit the ↑ key until you see the line that you want to reissue or edit. You can move the cursor in the line with the ← and → keys, and add or delete characters. Hit Enter when you are done. For example, hit ↑ and replace Double with Int, then hit Enter: jshell> generator.nextInt() $9 ==> -352355569

By default, JShell imports the following packages: java.io java.math java.net java.nio.file java.util java.util.concurrent java.util.function java.util.prefs java.util.regex java.util.stream

That's why you can use the Random class in JShell without any import statements. If you need to import another class, you can type the import statement at the JShell prompt. Or, more conveniently, you can have JShell search for it, by typing Shift+Tab and the I key. For example, type Duration followed by Shift+Tab and the I key. You get a list of potential actions: Click here to view code image jshell> Duration

WOW! eBook www.wowebook.org

0: Do nothing 1: import: java.time.Duration 2: import: javafx.util.Duration 3: import: javax.xml.datatype.Duration Choice:

Type 1, and you receive a confirmation: Imported: java.time.Duration

followed by jshell> Duration

so that you can pick up where you left off, but with the import in place. These commands are enough to get you started with JShell. To get help, type /help and Enter. To exit, type /exit and Enter, or simply Ctrl+D. JShell makes it easy and fun to learn about the Java language and library, without having to launch a heavy-duty development environment, and without fussing with public static void main.

1.2 Primitive Types Even though Java is an object-oriented programming language, not all Java values are objects. Instead, some values belong to primitive types. Four of these types are signed integer types, two are floating-point number types, one is the character type char that is used in the encoding for strings, and one is the boolean type for truth values. We will look at these types in the following sections.

1.2.1 Signed Integer Types The signed integer types are for numbers without fractional parts. Negative values are allowed. Java provides the four signed integer types shown in Table 1-1. Table 1-1 Java Signed Integer Types Type

Storage requirement

byte 1 byte short 2 bytes int

4 bytes

long 8 bytes

Range (inclusive) –128 to 127 –32,768 to 32,767 –2,147,483,648 to 2,147,483,647 (just over 2 billion) –9,223,372,036,854,775,808 to

WOW! eBook www.wowebook.org

9,223,372,036,854,775,807

Note The constants Integer.MIN_VALUE and Integer.MAX_VALUE are the smallest and largest int values. The Long, Short, and Byte classes also have MIN_VALUE and MAX_VALUE constants. In most situations, the int type is the most practical. If you want to represent the number of inhabitants of our planet, you’ll need to resort to a long. The byte and short types are mainly intended for specialized applications, such as low-level file handling, or for large arrays when storage space is at a premium. Note If the long type is not sufficient, use the BigInteger class. See Section 1.4.6, “Big Numbers” (page 23) for details. In Java, the ranges of the integer types do not depend on the machine on which you will be running your program. After all, Java is designed as a “write once, run anywhere” language. In contrast, the integer types in C and C++ programs depend on the processor for which a program is compiled. You write long integer literals with a suffix L (for example, 4000000000L). There is no syntax for literals of type byte or short. Use the cast notation (see Section 1.4.4, “Number Type Conversions,” page 20), for example, (byte) 127. Hexadecimal literals have a prefix 0x (for example, 0xCAFEBABE). Binary values have a prefix 0b. For example, 0b1001 is 9. Caution Octal numbers have a prefix 0. For example, 011 is 9. This can be confusing, so it seems best to stay away from octal literals and leading zeroes. You can add underscores to number literals, such as 1_000_000 (or 0b1111_0100_0010_0100_0000) to denote one million. The underscores are for human eyes only, the Java compiler simply removes them. WOW! eBook www.wowebook.org

Note If you work with integer values that can never be negative and you really need an additional bit, you can, with some care, interpret signed integer values as unsigned. For example, a byte value b represents the range from –128 to 127. If you want a range from 0 to 255, you can still store it in a byte. Due to the nature of binary arithmetic, addition, subtraction, and multiplication will all work, provided they don't overflow. For other operations, call Byte.toUnsignedInt(b) to get an int value between 0 and 255, then process the integer value, and cast the result back to byte. The Integer and Long classes have methods for unsigned division and remainder.

1.2.2 Floating-Point Types The floating-point types denote numbers with fractional parts. The two floating-point types are shown in Table 1-2. Table 1-2 Floating-Point Types Type

Storage requirement

Range

float 4 bytes

Approximately ±3.40282347E+38F (6–7 significant decimal digits)

double 8 bytes

Approximately ±1.79769313486231570E+308 (15 significant decimal digits)

Many years ago, when memory was a scarce resource, four-byte floating-point numbers were in common use. But seven decimal digits don't go very far, and nowadays, “double precision” numbers are the default. It only makes sense to use float when you need to store a large number of them. Numbers of type float have a suffix F (for example, 3.14F). Floating-point literals without an F suffix (such as 3.14) have type double. You can optionally supply the D suffix (for example, 3.14D). Note You can specify floating-point literals in hexadecimal. For example, WOW! eBook www.wowebook.org

0.0009765625 = 2–10 can be written as 0x1.0p-10. In hexadecimal notation, you use a p, not an e, to denote the exponent. (An e is a hexadecimal digit.) Note that, even though the digits are written in hexadecimal, the exponent (that is, the power of 2) is written in decimal. There are special floating-point values Double.POSITIVE_INFINITY for ∞, Double.NEGATIVE_INFINITY for –∞, and Double.NaN for “not a number.” For example, the result of computing 1.0 / 0.0 is positive infinity. Computing 0.0 / 0.0 or the square root of a negative number yields NaN. Caution All “not a number” values are considered to be distinct from each other. Therefore, you cannot use the test if (x == Double.NaN) to check whether x is a NaN. Instead, call if (Double.isNaN(x)). There are also methods Double.isInfinite to test for ±∞, and Double.isFinite to check that a floating-point number is neither infinite nor a NaN. Floating-point numbers are not suitable for financial calculations in which roundoff errors cannot be tolerated. For example, the command System.out.println(2.0 - 1.1) prints 0.8999999999999999, not 0.9 as you would expect. Such roundoff errors are caused by the fact that floatingpoint numbers are represented in the binary number system. There is no precise binary representation of the fraction 1/10, just as there is no accurate representation of the fraction 1/3 in the decimal system. If you need precise numerical computations with arbitrary precision and without roundoff errors, use the BigDecimal class, introduced in Section 1.4.6, “Big Numbers” (page 23).

1.2.3 The char Type The char type describes “code units” in the UTF-16 character encoding used by Java. The details are rather technical—see Section 1.5, “Strings” (page 24). You probably won't use the char type very much. Occasionally, you may encounter character literals, enclosed in single quotes. For example, 'J' is a character literal with value 74 (or hexadecimal 4A), the code unit for denoting the Unicode character “U+004A Latin Capital Letter J.” A code unit can be expressed in hexadecimal, with the \u prefix. For example, '\u004A' is the

WOW! eBook www.wowebook.org

same as 'J'. A more exotic example is '\u263A', the code unit for , “U+263A White Smiling Face.” The special codes '\n', '\r', '\t', '\b' denote a line feed, carriage return, tab, and backspace. Use a backslash to escape a single quote '\'' and a backslash '\\'.

1.2.4 The boolean Type The boolean type has two values, false and true. In Java, the boolean type is not a number type. There is no relationship between boolean values and the integers 0 and 1.

1.3 Variables In the following sections, you will learn how to declare and initialize variables and constants.

1.3.1 Variable Declarations Java is a strongly typed language. Each variable can only hold values of a specific type. When you declare a variable, you need to specify the type, the name, and an optional initial value. For example, int total = 0;

You can declare multiple variables of the same type in a single statement: Click here to view code image int total = 0, count; // count is an uninitialized integer

Most Java programmers prefer to use separate declarations for each variable. Consider this variable declation: Click here to view code image Random generator = new Random();

Here, the name of the object's class occurs twice. The first Random is the type of the variable generator. The second Random is a part of the new expression for constructing an object of that class.

1.3.2 Names The name of a variable (as well as a method or class) must begin with a letter. It can WOW! eBook www.wowebook.org

consist of any letters, digits, and the symbols _ and $. However, the $ symbol is intended for automatically generated names, and you should not use it in your names. Finally, the _ by itself is not a valid variable name. Here, letters and digits can be from any alphabet, not just the Latin alphabet. For example, π and élévation are valid variable names. Letter case is significant: count and Count are different names. You cannot use spaces or symbols in a name. Finally, you cannot use a keyword such as double as a name. By convention, names of variables and methods start with a lowercase letter, and names of classes start with an uppercase letter. Java programmers like “camel case,” where uppercase letters are used when names consist of multiple words, like countOfInvalidInputs.

1.3.3 Initialization When you declare a variable in a method, you must initialize it before you can use it. For example, the following code results in a compile-time error: Click here to view code image int count; count++; // Error—uses an uninitialized variable

The compiler must be able to verify that a variable has been initialized before it has been used. For example, the following code is also an error: Click here to view code image int count; if (total == 0) { count = 0; } else { count++; // Error—count might not be initialized }

You are allowed to declare a variable anywhere within a method. It is considered good style to declare a variable as late as possible, just before you need it for the first time. For example, Click here to view code image Scanner in = new Scanner(System.in); // See Section 1.6.1 for reading input System.out.println("How old are you?"); int age = in.nextInt();

The variable is declared at the point at which its initial value is available. WOW! eBook www.wowebook.org

1.3.4 Constants The final keyword denotes a value that cannot be changed once it has been assigned. In other languages, one would call such a value a constant. For example, final int DAYS_PER_WEEK = 7;

By convention, uppercase letters are used for names of constants. You can also declare a constant outside a method, using the static keyword: Click here to view code image public class Calendar { public static final int DAYS_PER_WEEK = 7; ... }

Then the constant can be used in multiple methods. Inside Calendar, you refer to the constant as DAYS_PER_WEEK. To use the constant in another class, prepend the class name: Calendar.DAYS_PER_WEEK. Note The System class declares a constant Click here to view code image public static final PrintStream out

that you can use anywhere as System.out. This is one of the few examples of a constant that is not written in uppercase. It is legal to defer the initialization of a final variable, provided it is initialized exactly once before it is used for the first time. For example, the following is legal: final int DAYS_IN_FEBRUARY; if (leapYear) { DAYS_IN_FEBRUARY = 29; } else { DAYS_IN_FEBRUARY = 28; }

That is the reason for calling them “final” variables. Once a value has been assigned, it is final and can never be changed.

WOW! eBook www.wowebook.org

Note Sometimes, you need a set of related constants, such as Click here to view code image public static final int MONDAY = 0; public static final int TUESDAY = 1; ...

In this case, you can define an enumerated type like this: Click here to view code image enum Weekday { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY };

Then, Weekday is a type with values Weekday.MONDAY and so on. Here is how you declare and initialize a Weekday variable: Click here to view code image Weekday startDay = Weekday.MONDAY;

We will discuss enumerated types in Chapter 4.

1.4 Arithmetic Operations Java uses the familiar operators of any C-based language (see Table 1-3). We will review them in the following sections. Table 1-3 Java Operators Operators

Associativity

[] . () (method call)

Left

! ~ ++ -- + (unary) - (unary) () (cast) new

Right

* / % (modulus)

Left

+ -

Left

> >>> (arithmetic shift)

Left

< > = instanceof

Left

== !=

Left

& (bitwise and)

Left

WOW! eBook www.wowebook.org

^ (bitwise exclusive or)

Left

| (bitwise or)

Left

&& (logical and)

Left

|| (logical or)

Left

? : (conditional)

Left

= += -= *= /= %= = >>>= &= ^= |=

Right

Note In this table, operators are listed by decreasing precedence. For example, since + has a higher precedence than 0) ...

Contrast this call with words[i].compareTo(words[j]). The compare method is called on the comparator object, not the string itself. Note Even though the LengthComparator object has no state, you still need to make an instance of it. You need the instance to call the compare method—it is not a static method. To sort an array, pass a LengthComparator object to the Arrays.sort method: Click here to view code image

WOW! eBook www.wowebook.org

String[] friends = { "Peter", "Paul", "Mary" }; Arrays.sort(friends, new LengthComparator());

Now the array is either ["Paul", "Mary", "Peter"] or ["Mary", "Paul", "Peter"]. You will see in Section 3.4.2, “Functional Interfaces” (page 115) how to use a Comparator much more easily, using a lambda expression.

3.3.3 The Runnable Interface At a time when just about every processor has multiple cores, you want to keep those cores busy. You may want to run certain tasks in a separate thread, or give them to a thread pool for execution. To define the task, you implement the Runnable interface. This interface has just one method. Click here to view code image class HelloTask implements Runnable { public void run() { for (int i = 0; i < 1000; i++) { System.out.println("Hello, World!"); } } }

If you want to execute this task in a new thread, create the thread from the Runnable and start it. Click here to view code image Runnable task = new HelloTask(); Thread thread = new Thread(task); thread.start();

Now the run method executes in a separate thread, and the current thread can proceed with other work. Note In Chapter 10, you will see other ways of executing a Runnable.

Note There is also a Callable interface for tasks that return a result of type WOW! eBook www.wowebook.org

T.

3.3.4 User Interface Callbacks In a graphical user interface, you have to specify actions to be carried out when the user clicks a button, selects a menu option, drags a slider, and so on. These actions are often called callbacks because some code gets called back when a user action occurs. In Java-based GUI libraries, interfaces are used for callbacks. For example, in JavaFX, the following interface is used for reporting events: Click here to view code image public interface EventHandler { void handle(T event); }

This too is a generic interface where T is the type of event that is being reported, such as an ActionEvent for a button click. To specify the action, implement the interface: Click here to view code image class CancelAction implements EventHandler { public void handle(ActionEvent event) { System.out.println("Oh noes!"); } }

Then, make an object of that class and add it to the button: Click here to view code image Button cancelButton = new Button("Cancel"); cancelButton.setOnAction(new CancelAction());

Note Since Oracle positions JavaFX as the successor to the Swing GUI toolkit, I use JavaFX in these examples. (Don't worry—you need not know any more about JavaFX than the couple of statements you just saw.) The details don’t matter; in every user interface toolkit, be it Swing, JavaFX, or Android, you give a button some code that you want to run when the button is clicked. Of course, this way of defining a button action is rather tedious. In other languages, WOW! eBook www.wowebook.org

you just give the button a function to execute, without going through the detour of making a class and instantiating it. The next section shows how you can do the same in Java.

3.4 Lambda Expressions A lambda expression is a block of code that you can pass around so it can be executed later, once or multiple times. In the preceding sections, you have seen many situations where it is useful to specify such a block of code: • To pass a comparison method to Arrays.sort • To run a task in a separate thread • To specify an action that should happen when a button is clicked However, Java is an object-oriented language where (just about) everything is an object. There are no function types in Java. Instead, functions are expressed as objects, instances of classes that implement a particular interface. Lambda expressions give you a convenient syntax for creating such instances.

3.4.1 The Syntax of Lambda Expressions Consider again the sorting example from Section 3.3.2, “The Comparator Interface” (page 111). We pass code that checks whether one string is shorter than another. We compute Click here to view code image first.length() - second.length()

What are first and second? They are both strings. Java is a strongly typed language, and we must specify that as well: Click here to view code image (String first, String second) -> first.length() - second.length()

You have just seen your first lambda expression. Such an expression is simply a block of code, together with the specification of any variables that must be passed to the code. Why the name? Many years ago, before there were any computers, the logician Alonzo Church wanted to formalize what it means for a mathematical function to be effectively computable. (Curiously, there are functions that are known to exist, but nobody knows how to compute their values.) He used the Greek letter lambda (λ) to mark parameters, somewhat like Click here to view code image WOW! eBook www.wowebook.org

λfirst. λsecond. first.length() - second.length()

Note Why the letter λ? Did Church run out of letters of the alphabet? Actually, the venerable Principia Mathematica (see http://plato.stanford.edu/entries/principia-mathematica) used the ^ accent to denote function parameters, which inspired Church to use an uppercase lambda Λ. But in the end, he switched to the lowercase version. Ever since, an expression with parameter variables has been called a lambda expression. If the body of a lambda expression carries out a computation that doesn’t fit in a single expression, write it exactly like you would have written a method: enclosed in {} and with explicit return statements. For example, Click here to view code image (String first, String second) -> { int difference = first.length() < second.length(); if (difference < 0) return -1; else if (difference > 0) return 1; else return 0; }

If a lambda expression has no parameters, supply empty parentheses, just as with a parameterless method: Click here to view code image Runnable task = () -> { for (int i = 0; i < 1000; i++) doWork(); }

If the parameter types of a lambda expression can be inferred, you can omit them. For example, Click here to view code image Comparator comp = (first, second) -> first.length() - second.length(); // Same as (String first, String second)

Here, the compiler can deduce that first and second must be strings because the lambda expression is assigned to a string comparator. (We will have a closer look at this assignment in the next section.) If a method has a single parameter with inferred type, you can even omit the parentheses: WOW! eBook www.wowebook.org

Click here to view code image EventHandler listener = event -> System.out.println("Oh noes!"); // Instead of (event) -> or (ActionEvent event) ->

You never specify the result type of a lambda expression. However, the compiler infers it from the body and checks that it matches the expected type. For example, the expression Click here to view code image (String first, String second) -> first.length() - second.length()

can be used in a context where a result of type int is expected (or a compatible type such as Integer, long, or double).

3.4.2 Functional Interfaces As you already saw, there are many interfaces in Java that express actions, such as Runnable or Comparator. Lambda expressions are compatible with these interfaces. You can supply a lambda expression whenever an object of an interface with a single abstract method is expected. Such an interface is called a functional interface. To demonstrate the conversion to a functional interface, consider the Arrays.sort method. Its second parameter requires an instance of Comparator, an interface with a single method. Simply supply a lambda: Click here to view code image Arrays.sort(words, (first, second) -> first.length() - second.length());

Behind the scenes, the second parameter variable of the Arrays.sort method receives an object of some class that implements Comparator. Invoking the compare method on that object executes the body of the lambda expression. The management of these objects and classes is completely implementation-dependent and highly optimized. In most programming languages that support function literals, you can declare function types such as (String, String) -> int, declare variables of those types, put functions into those variables, and invoke them. In Java, there is only one thing you can do with a lambda expression: put it in a variable whose type is a functional interface, so that it is converted to an instance of that interface.

WOW! eBook www.wowebook.org

Note You cannot assign a lambda expression to a variable of type Object, the common supertype of all classes in Java (see Chapter 4). Object is a class, not a functional interface. The Java API provides a large number of functional interfaces (see Section 3.6.2, “Choosing a Functional Interface,” page 120). One of them is Click here to view code image public interface Predicate { boolean test(T t); // Additional default and static methods }

The ArrayList class has a removeIf method whose parameter is a Predicate. It is specifically designed for receiving a lambda expression. For example, the following statement removes all null values from an array list: Click here to view code image list.removeIf(e -> e == null);

3.5 Method and Constructor References Sometimes, there is already a method that carries out exactly the action that you’d like to pass on to some other code. There is special syntax for a method reference that is even shorter than a lambda expression calling the method. A similar shortcut exists for constructors. You will see both in the following sections.

3.5.1 Method References Suppose you want to sort strings regardless of letter case. You could call Click here to view code image Arrays.sort(strings, (x, y) -> x.compareToIgnoreCase(y));

Instead, you can pass this method expression: Click here to view code image Arrays.sort(strings, String::compareToIgnoreCase);

The expression String::compareToIgnoreCase is a method reference that is equivalent to the lambda expression (x, y) ->

WOW! eBook www.wowebook.org

x.compareToIgnoreCase(y). Here is another example. The Objects class defines a method isNull. The call Objects.isNull(x) simply returns the value of x == null. It seems hardly worth having a method for this case, but it was designed to be passed as a method expression. The call Click here to view code image list.removeIf(Objects::isNull);

removes all null values from a list. As another example, suppose you want to print all elements of a list. The ArrayList class has a method forEach that applies a function to each element. You could call Click here to view code image list.forEach(x -> System.out.println(x));

It would be nicer, however, if you could just pass the println method to the forEach method. Here is how to do that: Click here to view code image list.forEach(System.out::println);

As you can see from these examples, the :: operator separates the method name from the name of a class or object. There are three variations: 1. Class::instanceMethod 2. Class::staticMethod 3. object::instanceMethod In the first case, the first parameter becomes the receiver of the method, and any other parameters are passed to the method. For example, String::compareToIgnoreCase is the same as (x, y) -> x.compareToIgnoreCase(y). In the second case, all parameters are passed to the static method. The method expression Objects::isNull is equivalent to x -> Objects.isNull(x). In the third case, the method is invoked on the given object, and the parameters are passed to the instance method. Therefore, System.out::println is equivalent to x -> System.out.println(x). Note WOW! eBook www.wowebook.org

When there are multiple overloaded methods with the same name, the compiler will try to find from the context which one you mean. For example, there are multiple versions of the println method. When passed to the forEach method of an ArrayList, the println(String) method is picked. You can capture the this parameter in a method reference. For example, this::equals is the same as x -> this.equals(x). Note In an inner class, you can capture the this reference of an enclosing class as EnclosingClass.this::method. You can also capture super—see Chapter 4.

3.5.2 Constructor References Constructor references are just like method references, except that the name of the method is new. For example, Employee::new is a reference to an Employee constructor. If the class has more than one constructor, then it depends on the context which constructor is chosen. Here is an example for using such a constructor reference. Suppose you have a list of strings List names = ...;

You want a list of employees, one for each name. As you will see in Chapter 8, you can use streams to do this without a loop: Turn the list into a stream, and then call the map method. It applies a function and collects all results. Click here to view code image Stream stream = names.stream().map(Employee::new);

Since names.stream() contains String objects, the compiler knows that Employee::new refers to the constructor Employee(String). You can form constructor references with array types. For example, int[]::new is a constructor reference with one parameter: the length of the array. It is equivalent to the lambda expression n -> new int[n]. Array constructor references are useful to overcome a limitation of Java: It is not possible to construct an array of a generic type. (See Chapter 6 for details.) For that WOW! eBook www.wowebook.org

reason, methods such as Stream.toArray return an Object array, not an array of the element type: Click here to view code image Object[] employees = stream.toArray();

But that is unsatisfactory. The user wants an array of employees, not objects. To solve this problem, another version of toArray accepts a constructor reference: Click here to view code image Employee[] buttons = stream.toArray(Employee[]::new);

The toArray method invokes this constructor to obtain an array of the correct type. Then it fills and returns the array.

3.6 Processing Lambda Expressions Up to now, you have seen how to produce lambda expressions and pass them to a method that expects a functional interface. In the following sections, you will see how to write your own methods that can consume lambda expressions.

3.6.1 Implementing Deferred Execution The point of using lambdas is deferred execution. After all, if you wanted to execute some code right now, you’d do that, without wrapping it inside a lambda. There are many reasons for executing code later, such as: • Running the code in a separate thread • Running the code multiple times • Running the code at the right point in an algorithm (for example, the comparison operation in sorting) • Running the code when something happens (a button was clicked, data has arrived, and so on) • Running the code only when necessary Let's look at a simple example. Suppose you want to repeat an action n times. The action and the count are passed to a repeat method: Click here to view code image repeat(10, () -> System.out.println("Hello, World!"));

To accept the lambda, we need to pick (or, in rare cases, provide) a functional interface. In this case, we can just use Runnable:

WOW! eBook www.wowebook.org

Click here to view code image public static void repeat(int n, Runnable action) { for (int i = 0; i < n; i++) action.run(); }

Note that the body of the lambda expression is executed when action.run() is called. Now let's make this example a bit more sophisticated. We want to tell the action in which iteration it occurs. For that, we need to pick a functional interface that has a method with an int parameter and a void return. Instead of rolling your own, I strongly recommend that you use one of the standard ones described in the next section. The standard interface for processing int values is Click here to view code image public interface IntConsumer { void accept(int value); }

Here is the improved version of the repeat method: Click here to view code image public static void repeat(int n, IntConsumer action) { for (int i = 0; i < n; i++) action.accept(i); }

And here is how you call it: Click here to view code image repeat(10, i -> System.out.println("Countdown: " + (9 - i)));

3.6.2 Choosing a Functional Interface In most functional programming languages, function types are structural. To specify a function that maps two strings to an integer, you use a type that looks something like Function2 or (String, String) -> int. In Java, you instead declare the intent of the function using a functional interface such as Comparator. In the theory of programming languages this is called nominal typing. Of course, there are many situations where you want to accept “any function” without particular semantics. There are a number of generic function types for that purpose (see Table 3-1), and it's a very good idea to use one of them when you can. Table 3-1 Common Functional Interfaces WOW! eBook www.wowebook.org

Functional Interface

Runnable

Supplier

Consumer

Parameter Return types type

none

none

T

BiConsumer T, U

Function

T

BiFunction

UnaryOperator T

BinaryOperatorT, T

Predicate

T

BiPredicate T, U

Abstract method Description name

Other methods

run

Runs an action without arguments or return value

T

get

Supplies a value of type T

void

Consumes a accept value of type andThen T

void

Consumes accept values of types andThen T and U

R

A function compose, apply with argument andThen, of type T identity

R

A function with apply andThen arguments of types T and U

T

A unary apply operator on the type T

compose, andThen, identity

T

A binary apply operator on the type T

andThen, maxBy, minBy

booleantest

A booleanvalued function

and, or, negate, isEqual

booleantest

A booleanvalued and, or, function with negate two arguments

void

WOW! eBook www.wowebook.org

For example, suppose you write a method to process files that match a certain criterion. Should you use the descriptive java.io.FileFilter class or a Predicate? I strongly recommend that you use the standard Predicate. The only reason not to do so would be if you already have many useful methods producing FileFilter instances. Note Most of the standard functional interfaces have nonabstract methods for producing or combining functions. For example, Predicate.isEqual(a) is the same as a::equals, but it also works if a is null. There are default methods and, or, negate for combining predicates. For example, Click here to view code image Predicate.isEqual(a).or(Predicate.isEqual(b))

is the same as Click here to view code image x -> a.equals(x) || b.equals(x)

Table 3-2 lists the 34 available specializations for primitive types int, long, and double. It is a good idea to use these specializations to reduce autoboxing. For that reason, I used an IntConsumer instead of a Consumer in the example of the preceding section. Table 3-2 Functional Interfaces for Primitive Types p, q is int, long, double; P, Q is Int, Long, Double Functional Interface BooleanSupplier

Parameter types Return type Abstract method name boolean getAsBoolean none

PSupplier

none

p

getAsP

PConsumer

p

void

accept

ObjPConsumer

T, p

void

accept

PFunction

p

T

apply

PToQFunction

p

q

applyAsQ

WOW! eBook www.wowebook.org

p

applyAsP

ToPBiFunction T, U

p

applyAsP

PUnaryOperator

p

p

applyAsP

PBinaryOperator

p, p

p

applyAsP

PPredicate

p

boolean

test

ToPFunction

T

3.6.3 Implementing Your Own Functional Interfaces Ever so often, you will be in a situation where none of the standard functional interfaces work for you. Then you need to roll your own. Suppose you want to fill an image with color patterns, where the user supplies a function yielding the color for each pixel. There is no standard type for a mapping (int, int) -> Color. You could use BiFunction, but that involves autoboxing. In this case, it makes sense to define a new interface Click here to view code image @FunctionalInterface public interface PixelFunction { Color apply(int x, int y); }

Note It is a good idea to tag functional interfaces with the @FunctionalInterface annotation. This has two advantages. First, the compiler checks that the annotated entity is an interface with a single abstract method. Second, the javadoc page includes a statement that your interface is a functional interface. Now you are ready to implement a method: Click here to view code image BufferedImage createImage(int width, int height, PixelFunction f) { BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++)

WOW! eBook www.wowebook.org

for (int y = 0; y < height; y++) { Color color = f.apply(x, y); image.setRGB(x, y, color.getRGB()); } return image; }

To call it, supply a lambda expression that yields a color value for two integers: Click here to view code image BufferedImage frenchFlag = createImage(150, 100, (x, y) -> x < 50 ? Color.BLUE : x < 100 ? Color.WHITE : Color.RED);

3.7 Lambda Expressions and Variable Scope In the following sections, you will learn how variables work inside lambda expressions. This information is somewhat technical but essential for working with lambda expressions.

3.7.1 Scope of a Lambda Expression The body of a lambda expression has the same scope as a nested block. The same rules for name conflicts and shadowing apply. It is illegal to declare a parameter or a local variable in the lambda that has the same name as a local variable. Click here to view code image int first = 0; Comparator comp = (first, second) -> first.length() second.length(); // Error: Variable first already defined

Inside a method, you can’t have two local variables with the same name, therefore you can’t introduce such variables in a lambda expression either. As another consequence of the “same scope” rule, the this keyword in a lambda expression denotes the this parameter of the method that creates the lambda. For example, consider Click here to view code image public class Application() { public void doWork() { Runnable runner = () -> { ...; System.out.println(this.toString()); ... }; ... }

WOW! eBook www.wowebook.org

}

The expression this.toString() calls the toString method of the Application object, not the Runnable instance. There is nothing special about the use of this in a lambda expression. The scope of the lambda expression is nested inside the doWork method, and this has the same meaning anywhere in that method.

3.7.2 Accessing Variables from the Enclosing Scope Often, you want to access variables from an enclosing method or class in a lambda expression. Consider this example: Click here to view code image public static void repeatMessage(String text, int count) { Runnable r = () -> { for (int i = 0; i < count; i++) { System.out.println(text); } }; new Thread(r).start(); }

Note that the lambda expression accesses the parameter variables defined in the enclosing scope, not in the lambda expression itself. Consider a call Click here to view code image repeatMessage("Hello", 1000); // Prints Hello 1000 times in a separate thread

Now look at the variables count and text inside the lambda expression. If you think about it, something nonobvious is going on here. The code of the lambda expression may run long after the call to repeatMessage has returned and the parameter variables are gone. How do the text and count variables stay around when the lambda expression is ready to execute? To understand what is happening, we need to refine our understanding of a lambda expression. A lambda expression has three ingredients: 1. A block of code 2. Parameters 3. Values for the free variables—that is, the variables that are not parameters and not defined inside the code WOW! eBook www.wowebook.org

In our example, the lambda expression has two free variables, text and count. The data structure representing the lambda expression must store the values for these variables—in our case, "Hello" and 1000. We say that these values have been captured by the lambda expression. (It's an implementation detail how that is done. For example, one can translate a lambda expression into an object with a single method, so that the values of the free variables are copied into instance variables of that object.) Note The technical term for a block of code together with the values of free variables is a closure. In Java, lambda expressions are closures. As you have seen, a lambda expression can capture the value of a variable in the enclosing scope. To ensure that the captured value is well defined, there is an important restriction. In a lambda expression, you can only reference variables whose value doesn't change. This is sometimes described by saying that lambda expressions capture values, not variables. For example, the following is a compiletime error: Click here to view code image for (int i = 0; i < n; i++) { new Thread(() -> System.out.println(i)).start(); // Error—cannot capture i }

The lambda expression tries to capture i, but this is not legal because i changes. There is no single value to capture. The rule is that a lambda expression can only access local variables from an enclosing scope that are effectively final. An effectively final variable is never modified—it either is or could be declared as final. Note The same rule applies to variables captured by local classes (see Section 3.9, “Local and Anonymous Classes,” page 129). In the past, the rule was more draconian and required captured variables to actually be declared final. This is no longer the case.

WOW! eBook www.wowebook.org

Note The variable of an enhanced for loop is effectively final since its scope is a single iteration. The following is perfectly legal: Click here to view code image for (String arg : args) { new Thread(() -> System.out.println(arg)).start(); // OK to capture arg }

A new variable arg is created in each iteration and assigned the next value from the args array. In contrast, the scope of the variable i in the preceding example was the entire loop. As a consequence of the “effectively final” rule, a lambda expression cannot mutate any captured variables. For example, Click here to view code image public static void repeatMessage(String text, int count, int threads) { Runnable r = () -> { while (count > 0) { count--; // Error: Can't mutate captured variable System.out.println(text); } }; for (int i = 0; i < threads; i++) new Thread(r).start(); }

This is actually a good thing. As you will see in Chapter 10, if two threads update count at the same time, its value is undefined. Note Don't count on the compiler to catch all concurrent access errors. The prohibition against mutation only holds for local variables. If count is an instance variable or static variable of an enclosing class, then no error is reported even though the result is just as undefined.

Caution WOW! eBook www.wowebook.org

One can circumvent the check for inappropriate mutations by using an array of length 1: Click here to view code image int[] counter = new int[1]; button.setOnAction(event -> counter[0]++);

The counter variable is effectively final—it is never changed since it always refers to the same array, so you can access it in the lambda expression. Of course, code like this is not threadsafe. Except possibly for a callback in a single-threaded UI, this is a terrible idea. You will see how to implement a threadsafe shared counter in Chapter 10.

3.8 Higher-Order Functions In a functional programming language, functions are first-class citizens. Just like you can pass numbers to methods and have methods that produce numbers, you can have arguments and return values that are functions. Functions that process or return functions are called higher-order functions. This sounds abstract, but it is very useful in practice. Java is not quite a functional language because it uses functional interfaces, but the principle is the same. In the following sections, we will look at some examples and examine the higher-order functions in the Comparator interface.

3.8.1 Methods that Return Functions Suppose sometimes we want to sort an array of strings in ascending order and other times in descending order. We can make a method that produces the correct comparator: Click here to view code image public static Comparator compareInDirecton(int direction) { return (x, y) -> direction * x.compareTo(y); }

The call compareInDirection(1) yields an ascending comparator, and the call compareInDirection(-1) a descending comparator. The result can be passed to another method (such as Arrays.sort) that expects such an interface. Click here to view code image WOW! eBook www.wowebook.org

Arrays.sort(friends, compareInDirection(-1));

In general, don’t be shy to write methods that produce functions (or, technically, instances of classes that implement a functional interface). This is useful to generate custom functions that you pass to methods with functional interfaces.

3.8.2 Methods That Modify Functions In the preceding section, you saw a method that yields an increasing or decreasing string comparator. We can generalize this idea by reversing any comparator: Click here to view code image public static Comparator reverse(Comparator comp) { return (x, y) -> comp.compare(y, x); }

This method operates on functions. It receives a function and returns a modified function. To get case-insensitive descending order, use Click here to view code image reverse(String::compareToIgnoreCase)

Note The Comparator interface has a default method reversed that produces the reverse of a given comparator in just this way.

3.8.3 Comparator Methods The Comparator interface has a number of useful static methods that are higherorder functions generating comparators. The comparing method takes a “key extractor” function that maps a type T to a comparable type (such as String). The function is applied to the objects to be compared, and the comparison is then made on the returned keys. For example, suppose a Person class has a method getLastName. Then you can sort an array of Person objects by last name like this: Click here to view code image Arrays.sort(people, Comparator.comparing(Person::getLastName));

You can chain comparators with the thenComparing method to break ties. For

WOW! eBook www.wowebook.org

example, sort an array of people by last name, then use the first name for people with the same last name: Click here to view code image Arrays.sort(people, Comparator .comparing(Person::getLastName) .thenComparing(Person::getFirstName));

There are a few variations of these methods. You can specify a comparator to be used for the keys that the comparing and thenComparing methods extract. For example, here we sort people by the length of their names: Click here to view code image Arrays.sort(people, Comparator.comparing(Person::getLastName, (s, t) -> s.length() - t.length()));

Moreover, both the comparing and thenComparing methods have variants that avoid boxing of int, long, or double values. An easier way of sorting by name length would be Click here to view code image Arrays.sort(people, Comparator.comparingInt(p -> p.getLastName().length()));

If your key function can return null, you will like the nullsFirst and nullsLast adapters. These static methods take an existing comparator and modify it so that it doesn’t throw an exception when encountering null values but ranks them as smaller or larger than regular values. For example, suppose getMiddleName returns a null when a person has no middle name. Then you can use Comparator.comparing(Person::getMiddleName(), Comparator.nullsFirst(...)). The nullsFirst method needs a comparator—in this case, one that compares two strings. The naturalOrder method makes a comparator for any class implementing Comparable. Here is the complete call for sorting by potentially null middle names. I use a static import of java.util.Comparator.* to make the expression more legible. Note that the type for naturalOrder is inferred. Click here to view code image Arrays.sort(people, comparing(Person::getMiddleName, nullsFirst(naturalOrder())));

The static reverseOrder method gives the reverse of the natural order.

WOW! eBook www.wowebook.org

3.9 Local and Anonymous Classes Long before there were lambda expressions, Java had a mechanism for concisely defining classes that implement an interface (functional or not). For functional interfaces, you should definitely use lambda expressions, but once in a while, you may want a concise form for an interface that isn't functional. You will also encounter the classic constructs in legacy code.

3.9.1 Local Classes You can define a class inside a method. Such a class is called a local class. You would do this for classes that are just tactical. This occurs often when a class implements an interface and the caller of the method only cares about the interface, not the class. For example, consider a method Click here to view code image public static IntSequence randomInts(int low, int high)

that generates an infinite sequence of random integers with the given bounds. Since IntSequence is an interface, the method must return an object of some class implementing that interface. The caller doesn't care about the class, so it can be declared inside the method: Click here to view code image private static Random generator = new Random(); public static IntSequence randomInts(int low, int high) { class RandomSequence implements IntSequence { public int next() { return low + generator.nextInt(high low + 1); } public boolean hasNext() { return true; } } return new RandomSequence(); }

Note A local class is not declared as public or private since it is never accessible outside the method.

WOW! eBook www.wowebook.org

There are two advantages of making a class local. First, its name is hidden in the scope of the method. Second, the methods of the class can access variables from the enclosing scope, just like the variables of a lambda expression. In our example, the next method captures three variables: low, high, and generator. If you turned RandomInt into a nested class, you would have to provide an explicit constructor that receives these values and stores them in instance variables (see Exercise 16).

3.9.2 Anonymous Classes In the example of the preceding section, the name RandomSequence was used exactly once: to construct the return value. In this case, you can make the class anonymous: Click here to view code image public static IntSequence randomInts(int low, int high) { return new IntSequence() { public int next() { return low + generator.nextInt(high low + 1); } public boolean hasNext() { return true; } } }

The expression new Interface() { methods }

means: Define a class implementing the interface that has the given methods, and construct one object of that class. Note As always, the () in the new expression indicate the construction arguments. A default constructor of the anonymous class is invoked. Before Java had lambda expressions, anonymous inner classes were the most concise syntax available for providing runnables, comparators, and other functional objects. You will often see them in legacy code. Nowadays, they are only necessary when you need to provide two or more methods, as in the preceding example. If the IntSequence interface has a default hasNext method, as in Exercise 16, you can simply use a lambda expression: Click here to view code image WOW! eBook www.wowebook.org

public static IntSequence randomInts(int low, int high) { return () -> low + generator.nextInt(high - low + 1); }

Exercises 1. Provide an interface Measurable with a method double getMeasure() that measures an object in some way. Make Employee implement Measurable. Provide a method double average(Measurable[] objects) that computes the average measure. Use it to compute the average salary of an array of employees. 2. Continue with the preceding exercise and provide a method Measurable largest(Measurable[] objects). Use it to find the name of the employee with the largest salary. Why do you need a cast? 3. What are all the supertypes of String? Of Scanner? Of ImageOutputStream? Note that each type is its own supertype. A class or interface without declared supertype has supertype Object. 4. Implement a static of method of the IntSequence class that yields a sequence with the arguments. For example, IntSequence.of(3, 1, 4, 1, 5, 9) yields a sequence with six values. Extra credit if you return an instance of an anonymous inner class. 5. Add a static method with the name constant of the IntSequence class that yields an infinite constant sequence. For example, IntSequence.constant(1) yields values 1 1 1..., ad infinitum. Extra credit if you do this with a lambda expression. 6. The SquareSequence class doesn't actually deliver an infinite sequence of squares due to integer overflow. Specifically, how does it behave? Fix the problem by defining a Sequence interface and a SquareSequence class that implements Sequence. 7. In this exercise, you will try out what happens when a method is added to an interface. In Java 7, implement a class DigitSequence that implements Iterator, not IntSequence. Provide methods hasNext, next, and a do-nothing remove. Write a program that prints the elements of an instance. In Java 8, the Iterator class gained another method, forEachRemaining. Does your code still compile when you switch to Java 8? If you put your Java 7 class in a JAR file and don't recompile, does it work in Java 8? What if you call the forEachRemaining method? Also, the remove method has become a WOW! eBook www.wowebook.org

default method in Java 8, throwing an UnsupportedOperationException. What happens when remove is called on an instance of your class? 8. Implement the method void luckySort(ArrayList strings, Comparator comp) that keeps calling Collections.shuffle on the array list until the elements are in increasing order, as determined by the comparator. 9. Implement a class Greeter that implements Runnable and whose run method prints n copies of "Hello, " + target, where n and target are set in the constructor. Construct two instances with different messages and execute them concurrently in two threads. 10. Implement methods Click here to view code image public static void runTogether(Runnable... tasks) public static void runInOrder(Runnable... tasks)

The first method should run each task in a separate thread and then return. The second method should run all methods in the current thread and return when the last one has completed. 11. Using the listFiles(FileFilter) and isDirectory methods of the java.io.File class, write a method that returns all subdirectories of a given directory. Use a lambda expression instead of a FileFilter object. Repeat with a method expression and an anonymous inner class. 12. Using the list(FilenameFilter) method of the java.io.File class, write a method that returns all files in a given directory with a given extension. Use a lambda expression, not a FilenameFilter. Which variable from the enclosing scope does it capture? 13. Given an array of File objects, sort it so that directories come before files, and within each group, elements are sorted by path name. Use a lambda expression to specify the Comparator. 14. Write a method that takes an array of Runnable instances and returns a Runnable whose run method executes them in order. Return a lambda expression. 15. Write a call to Arrays.sort that sorts employees by salary, breaking ties by name. Use Comparator.thenComparing. Then do this in reverse order. 16. Implement the RandomSequence in Section 3.9.1, “Local Classes” (page 129) as a nested class, outside the randomInts method.

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

WOW! eBook www.wowebook.org

Chapter 4. Inheritance and Reflection Topics in This Chapter 4.1 Extending a Class 4.2 Object: The Cosmic Superclass 4.3 Enumerations 4.4 Runtime Type Information and Resources 4.5 Reflection Exercises The preceding chapters introduced you to classes and interfaces. In this chapter, you will learn about another fundamental concept of object-oriented programming: inheritance. Inheritance is the process of creating new classes that are built on existing classes. When you inherit from an existing class, you reuse (or inherit) its methods, and you can add new methods and fields. Note Instance variables and static variables are collectively called fields. The fields, methods, and nested classes/interfaces inside a class are collectively called its members. This chapter also covers reflection, the ability to find out more about classes and their members in a running program. Reflection is a powerful feature, but it is undeniably complex. Since reflection is of greater interest to tool builders than to application programmers, you can probably glance over that part of the chapter upon first reading and come back to it later. The key points of this chapter are: 1. A subclass can inherit or override methods from the superclass, provided they are not private. 2. Use the super keyword to invoke a superclass method or constructor. 3. A final method cannot be overridden; a final class cannot be extended. 4. An abstract method has no implementation; an abstract class cannot be instantiated. WOW! eBook www.wowebook.org

5. A protected member of a superclass is accessible in a subclass method, but only when applied to objects of the same subclass. It is also accessible in its package. 6. Every class is a subclass of Object which provides the toString, equals, hashCode, and clone methods. 7. Each enumerated type is a subclass of Enum which provides instance methods toString and compareTo, and a static valueOf method. 8. The Class class provides information about a Java type, which can be a class, array, interface, primitive type, or void. 9. You can use a Class object to load resources that are placed alongside class files. 10. You can load classes from locations other than the class path by using a class loader. 11. The ServiceLoader class provides a mechanism for locating and selecting service implementations. 12. The reflection library enables programs to discover members of objects, access variables, and invoke methods. 13. Proxy objects dynamically implement arbitrary interfaces, routing all method invocations to a handler.

4.1 Extending a Class Let’s return to the Employee class that we discussed in Chapter 2. Suppose (alas) you work for a company at which managers are treated differently from other employees. Managers are, of course, just like employees in many respects. Both employees and managers are paid a salary. However, while employees are expected to complete their assigned tasks in return for their salary, managers get bonuses if they actually achieve what they are supposed to do. This is the kind of situation that can be modeled with inheritance.

4.1.1 Super- and Subclasses Let's define a new class, Manager, retaining some functionality of the Employee class but specifying how managers are different. Click here to view code image public class Manager extends Employee { added fields added or overriding methods

WOW! eBook www.wowebook.org

}

The keyword extends indicates that you are making a new class that derives from an existing class. The existing class is called the superclass and the new class is called the subclass. In our example, the Employee class is the superclass and the Manager class is the subclass. Note that the superclass is not "superior" to its subclass. The opposite is true: Subclasses have more functionality than their superclasses. The super/sub terminology comes from set theory. The set of managers is a subset of the set of employees.

4.1.2 Defining and Inheriting Subclass Methods Our Manager class has a new instance variable to store the bonus and a new method to set it: Click here to view code image public class Manager extends Employee { private double bonus; ... public void setBonus(double bonus) { this.bonus = bonus; } }

When you have a Manager object, you can of course apply the setBonus method, as well as nonprivate methods from the Employee class. Those methods are inherited. Click here to view code image Manager boss = new Manager(...); boss.setBonus(10000); // Defined in subclass boss.raiseSalary(5); // Inherited from superclass

4.1.3 Method Overriding Sometimes, a superclass method needs to be modified in a subclass. For example, suppose that the getSalary method is expected to report the total salary of an employee. Then the inherited method is not sufficient for the Manager class. Instead, you need to override the method so that it returns the sum of the base salary and the bonus. Click here to view code image public class Manager extends Employee { ...

WOW! eBook www.wowebook.org

public double getSalary() { // Overrides superclass method return super.getSalary() + bonus; } }

This method invokes the superclass method, which retrieves the base salary, and adds the bonus. Note that a subclass method cannot access the private instance variables of the superclass directly. That is why the Manager.getSalary method calls the public Employee.getSalary method. The super keyword is used for invoking a superclass method. Note Unlike this, super is not a reference to an object, but a directive to bypass dynamic method lookup (see Section 4.1.5, “Superclass Assignments,” page 139) and invoke a specific method instead. It is not required to call the superclass method when overriding a method, but it is common to do so. When you override a method, you must be careful to match the parameter types exactly. For example, suppose that the Employee class has a method Click here to view code image public boolean worksFor(Employee supervisor)

If you override this method in the Manager class, you cannot change the parameter type, even though surely no manager would report to a mere employee. Suppose you defined a method Click here to view code image public class Manager extends Employee { ... public boolean worksFor(Manager supervisor) { ... } }

This is simply a new method, and now Manager has two separate worksFor methods. You can protect yourself against this type of error by tagging methods that are intended to override superclass methods with the @Override annotation: Click here to view code image @Override public boolean worksFor(Employee supervisor) WOW! eBook www.wowebook.org

If you made a mistake and are defining a new method, the compiler reports an error. You can change the return type to a subtype when overriding a method. (In technical terms, covariant return types are permitted.) For example, if the Employee class has a method Click here to view code image public Employee getSupervisor()

then the Manager class can override it with the method Click here to view code image @Override public Manager getSupervisor()

Caution When you override a method, the subclass method must be at least as accessible as the superclass method. In particular, if the superclass method is public, then the subclass method must also be declared public. It is a common error to accidentally omit the public modifier for the subclass method. The compiler then complains about the weaker access privilege.

4.1.4 Subclass Construction Let us supply a constructor for the Manager class. Since the Manager constructor cannot access the private instance variables of the Employee class, it must initialize them through a superclass constructor. Click here to view code image public Manager(String name, double salary) { super(name, salary); bonus = 0; }

Here, the keyword super indicates a call to the constructor of the Employee superclass with name and salary as arguments. The superclass constructor call must be the first statement in the constructor for the subclass. If the subclass does not explicitly call any superclass constructor, the superclass must have a no-argument constructor which is implicitly called.

4.1.5 Superclass Assignments It is legal to assign an object from a subclass to a variable whose type is a superclass, WOW! eBook www.wowebook.org

for example: Click here to view code image Manager boss = new Manager(...); Employee empl = boss; // OK to assign to superclass variable

Now consider what happens when one invokes a method on the superclass variable. Click here to view code image double salary = empl.getSalary();

Even though the type of empl is Employee, the Manager.getSalary method is invoked. When invoking a method, the virtual machine looks at the actual class of the object and locates its version of the method. This process is called dynamic method lookup. Why would you want to assign a Manager object to an Employee variable? It allows you to write code that works for all employees, be they managers or janitors or instances of another Employee subclass. Click here to view code image Employee[] staff = new Employee[...]; staff[0] = new Employee(...); staff[1] = new Manager(...); // OK to assign to superclass variable staff[2] = new Janitor(...); ... double sum = 0; for (Employee empl : staff) sum += empl.getSalary();

Thanks to dynamic method lookup, the call empl.getSalary() invokes the getSalary method belonging to the object to which empl refers, which may be Employee.getSalary, Manager.getSalary, and so on. Caution In Java, superclass assignment also works for arrays: You can assign a Manager[] array to an Employee[] variable. (The technical term is that Java arrays are covariant.) This is convenient, but it is also unsound—that is, a possible cause of type errors. Consider this example: Click here to view code image Manager[] bosses = new Manager[10]; Employee[] empls = bosses; // Legal in Java

WOW! eBook www.wowebook.org

empls[0] = new Employee(...); // Runtime error

The compiler accepts the last statement since it is generally legal to store an Employee in an Employee[] array. However, here empls and bosses reference the same Manager[] array, which cannot hold a lowly Employee. This mistake is only caught at runtime, when the virtual machine throws an ArrayStoreException.

4.1.6 Casts In the preceding section, you saw how a variable empl of type Employee can refer to objects whose class is Employee, Manager, or another subclass of Employee. That is useful for code that deals with objects from multiple classes. There is just one drawback. You can only invoke methods that belong to the superclass. Consider, for example, Click here to view code image Employee empl = new Manager(...); empl.setBonus(10000); // Compile-time error

Even though this call could succeed at runtime, it is a compile-time error. The compiler checks that you only invoke methods that exist for the receiver type. Here, empl is of type Employee and that class has no setBonus method. As with interfaces, you can use the instanceof operator and a cast to turn a superclass reference to a subclass. Click here to view code image if (empl instanceof Manager) { Manager mgr = (Manager) empl; mgr.setBonus(10000); }

4.1.7 Final Methods and Classes When you declare a method as final, no subclass can override it. Click here to view code image public class Employee { ... public final String getName() { return name; } }

WOW! eBook www.wowebook.org

A good example of a final method in the Java API is the getClass method of the Object class that you will see in Section 4.4.1, “The Class Class” (page 159). It does not seem wise to allow objects to lie about the class to which they belong, so this method can never be changed. Some programmers believe that the final keyword is good for efficiency. This may have been true in the early days of Java, but it no longer is. Modern virtual machines will speculatively “inline” simple methods, such as the getName method above, even if they are not declared final. In the rare case when a subclass is loaded that overrides such a method, the inlining is undone. Some programmers believe that most methods of a class should be declared final, and only methods specifically designed to be overridden should not be. Others find this too draconian since it prevents even harmless overriding, for example for logging or debugging purposes. Occasionally, you may want to prevent someone from forming a subclass from one of your classes. Use the final modifier in the class definition to indicate this. For example, here is how to prevent others from subclassing the Executive class: Click here to view code image public final class Executive extends Manager { ... }

There is a good number of final classes in the Java API, such as String, LocalTime, and URL.

4.1.8 Abstract Methods and Classes A class can define a method without an implementation, forcing subclasses to implement it. Such a method, and the class containing it, are called abstract and must be tagged with the abstract modifier. This is commonly done for very general classes, for example: Click here to view code image public abstract class Person { private String name; public Person(String name) { this.name = name; } public final String getName() { return name; } public abstract int getId(); }

WOW! eBook www.wowebook.org

Any class extending Person must either supply an implementation of the getId method or be itself declared as abstract. Note that an abstract class can have nonabstract methods, such as the getName method in the preceding example. Note Unlike an interface, an abstract class can have instance variables and constructors. It is not possible to construct an instance of an abstract class. For example, the call Click here to view code image Person p = new Person("Fred"); // Error

would be a compile-time error. However, you can have a variable whose type is an abstract class, provided it contains a reference to an object of a concrete subclass. Suppose the class Student is declared as Click here to view code image public class Student extends Person { private int id; public Student(String name, int id) { super(name); this.id = id; } public int getId() { return id; } }

Then you can construct a Student and assign it to a Person variable. Click here to view code image Person p = new Student("Fred", 1729); // OK, a concrete subclass

4.1.9 Protected Access There are times when you want to restrict a method to subclasses only or, less commonly, to allow subclass methods to access an instance variable of a superclass. For that, declare a class feature as protected. For example, suppose the superclass Employee declares the instance variable salary as protected instead of private.

WOW! eBook www.wowebook.org

Click here to view code image package com.horstmann.employees; public class Employee { protected double salary; ... }

All classes in the same package as Employee can access this field. Now consider a subclass from a different package: Click here to view code image package com.horstmann.managers; import com.horstmann.employees.Employee; public class Manager extends Employee { ... public double getSalary() { return salary + bonus; // OK to access protected salary variable } }

The Manager class methods can peek inside the salary variable of Manager objects only, not of other Employee objects. This restriction is made so that you can’t abuse the protected mechanism by forming subclasses just to gain access to protected features. Of course, protected fields should be used with caution. Once provided, you cannot take them away without breaking classes that are using them. Protected methods and constructors are more common. For example, the clone method of the Object class is protected since it is somewhat tricky to use (see Section 4.2.4, “Cloning Objects,” page 151). Caution In Java, protected grants package-level access, and it only protects access from other packages.

4.1.10 Anonymous Subclasses Just as you can have an anonymous class that implements an interface, you can have an anonymous class that extends a superclass. This can be handy for debugging: WOW! eBook www.wowebook.org

Click here to view code image ArrayList names = new ArrayList(100) { public void add(int index, String element) { super.add(index, element); System.out.printf("Adding %s at %d\n", element, index); } };

The arguments in the parentheses following the superclass name are passed to the superclass constructor. Here, we construct an anonymous subclass of ArrayList that overrides the add method. The instance is constructed with an initial capacity of 100. A trick called double brace initialization uses the inner class syntax in a rather bizarre way. Suppose you want to construct an array list and pass it to a method: Click here to view code image ArrayList friends = new ArrayList(); friends.add("Harry"); friends.add("Sally"); invite(friends);

If you won’t ever need the array list again, it would be nice to make it anonymous. But then, how can you add the elements? Here is how: Click here to view code image invite(new ArrayList() {{ add("Harry"); add("Sally"); }});

Note the double braces. The outer braces make an anonymous subclass of ArrayList. The inner braces are an initialization block (see Chapter 2). I am not recommending that you use this trick outside of Java trivia contests. There are several drawbacks beyond the confusing syntax. It is inefficient, and the constructed object can behave strangely in equality tests, depending on how the equals method is implemented.

4.1.11 Inheritance and Default Methods Suppose a class extends a class and implements an interface, both of which happen to have a method of the same name. Click here to view code image public interface Named {

WOW! eBook www.wowebook.org

default String getName() { return ""; } } public class Person { ... public String getName() { return name; } } public class Student extends Person implements Named { ... }

In this situation, the superclass implementation always wins over the interface implementation. There is no need for the subclass to resolve the conflict. In contrast, as you saw in Chapter 3, you must resolve a conflict when the same default method is inherited from two interfaces. The “classes win” rule ensures compatibility with Java 7. If you add default methods to an interface, it has no effect on code that worked before there were default methods.

4.1.12 Method Expressions with super Recall from Chapter 3 that a method expression can have the form object::instanceMethod. It is also valid to use super instead of an object reference. The method expression super::instanceMethod

uses this as the target and invokes the superclass version of the given method. Here is an artificial example that shows the mechanics: Click here to view code image public class Worker { public void work() { for (int i = 0; i < 100; i++) System.out.println("Working"); } } public class ConcurrentWorker extends Worker { public void work() { Thread t = new Thread(super::work); t.start(); } }

WOW! eBook www.wowebook.org

The thread is constructed with a Runnable whose run method calls the work method of the superclass.

4.2 Object: The Cosmic Superclass Every class in Java directly or indirectly extends the class Object. When a class has no explicit superclass, it implicitly extends Object. For example, public class Employee { ... }

is equivalent to Click here to view code image public class Employee extends Object { ... }

The Object class defines methods that are applicable to any Java object (see Table 4-1). We will examine several of these methods in detail in the following sections. Table 4-1 The Methods of the java.lang.Object Class Method String toString()

Description Yields a string representation of this object, by default the name of the class and the hash code.

Returns true if this object should be considered equal to boolean other, false if other is null or different from other. By equals(Object default, two objects are equal if they are identical. Instead of other) obj.equals(other), consider the null-safe alternative Objects.equals(obj, other). int hashCode()

Yields a hash code for this object. Equal objects must have the same hash code. Unless overridden, the hash code is assigned in some way by the virtual machine.

Class getClass()

Yields the Class object describing the class to which this object belongs.

protected Object clone()

Makes a copy of this object. By default, the copy is shallow.

protected void finalize()

This method is called when this object is reclaimed by the garbage collector. Don't override it.

wait, notify,

See Chapter 10. WOW! eBook www.wowebook.org

notifyAll

Note Arrays are classes. Therefore, it is legal to convert an array, even a primitive type array, to a reference of type Object.

4.2.1 The toString Method An important method in the Object class is the toString method that returns a string description of an object. For example, the toString method of the Point class returns a string like this: java.awt.Point[x=10,y=20]

Many toString methods follow this format: the name of the class, followed by the instance variables enclosed in square brackets. Here is such an implementation of the toString method of the Employee class: Click here to view code image public String toString() { return getClass().getName() + "[name=" + name + ",salary=" + salary + "]"; }

By calling getClass().getName() instead of hardwiring the string "Employee", this method does the right thing for subclasses as well. In a subclass, call super.toString() and add the instance variables of the subclass, in a separate pair of brackets: Click here to view code image public class Manager extends Employee { ... public String toString() { return super.toString() + "[bonus=" + bonus + "]"; } }

Whenever an object is concatenated with a string, the Java compiler automatically invokes the toString method on the object. For example: Click here to view code image Point p = new Point(10, 20); WOW! eBook www.wowebook.org

String message = "The current position is " + p; // Concatenates with p.toString()

Tip Instead of writing x.toString(), you can write "" + x. This expression even works if x is null or a primitive type value. The Object class defines the toString method to print the class name and the hash code (see Section 4.2.3, “The hashCode Method,” page 150). For example, the call Click here to view code image System.out.println(System.out)

produces an output that looks like java.io.PrintStream@2f6684 since the implementor of the PrintStream class didn’t bother to override the toString method. Caution Arrays inherit the toString method from Object, with the added twist that the array type is printed in an archaic format. For example, if you have the array Click here to view code image int[] primes = { 2, 3, 5, 7, 11, 13 };

then primes.toString() yields a string such as "[I@1a46e30". The prefix [I denotes an array of integers. The remedy is to call Arrays.toString(primes) instead, which yields the string "[2, 3, 5, 7, 11, 13]". To correctly print multidimensional arrays (that is, arrays of arrays), use Arrays.deepToString.

4.2.2 The equals Method The equals method tests whether one object is considered equal to another. The equals method, as implemented in the Object class, determines whether two object references are identical. This is a pretty reasonable default—if two objects are WOW! eBook www.wowebook.org

identical, they should certainly be equal. For quite a few classes, nothing else is required. For example, it makes little sense to compare two Scanner objects for equality. Override the equals method only for state-based equality testing, in which two objects are considered equal when they have the same contents. For example, the String class overrides equals to check whether two strings consist of the same characters. Caution Whenever you override the equals method, you must provide a compatible hashCode method as well—see Section 4.2.3, “The hashCode Method” (page 150). Suppose we want to consider two objects of a class Item equal if their descriptions and prices match. Here is how you can implement the equals method: Click here to view code image public class Item { private String description; private double price; ... public boolean equals(Object otherObject) { // A quick test to see if the objects are identical if (this == otherObject) return true; // Must return false if the parameter is null if (otherObject == null) return false; // Check that otherObject is an Item if (getClass() != otherObject.getClass()) return false; // Test whether the instance variables have identical values Item other = (Item) otherObject; return Objects.equals(description, other.description) && price == other.price; } public int hashCode() { ... } // See Section 4.2.3 }

There are a number of routine steps that you need to go through in an equals method: 1. It is common for equal objects to be identical, and that test is very inexpensive. WOW! eBook www.wowebook.org

2. Every equals method is required to return false when comparing against null. 3. Since the equals method overrides Object.equals, its parameter is of type Object, and you need to cast it to the actual type so you can look at its instance variables. Before doing that, make a type check, either with the getClass method or with the instanceof operator. 4. Finally, compare the instance variables. Use == for primitive types. However, for double values, if you are concerned about ±∞ or NaN, use Double.equals. For objects, use Objects.equals, a null-safe version of the equals method. The call Objects.equals(x, y) returns false if x is null, whereas x.equals(y) would throw an exception. Tip If you have instance variables that are arrays, use the static Arrays.equals method to check that the arrays have equal length and the corresponding array elements are equal. When you define the equals method for a subclass, first call equals on the superclass. If that test doesn’t pass, the objects can’t be equal. If the instance variables of the superclass are equal, then you are ready to compare the instance variables of the subclass. Click here to view code image public class DiscountedItem extends Item { private double discount; ... public boolean equals(Object otherObject) { if (!super.equals(otherObject)) return false; DiscountedItem other = (DiscountedItem) otherObject; return discount == other.discount; } public int hashCode() { ... } }

Note that the getClass test in the superclass fails if otherObject is not a DiscountedItem. How should the equals method behave when comparing values that belong to different classes? This has been an area of some controversy. In the preceding example, the equals method returns false if the classes don’t match exactly. But WOW! eBook www.wowebook.org

many programmers use an instanceof test instead: Click here to view code image if (!(otherObject instanceof Item)) return false;

This leaves open the possibility that otherObject can belong to a subclass. For example, you can compare an Item with a DiscountedItem. However, that kind of comparison doesn't usually work. One of the requirements of the equals method is that it is symmetric: For non-null x and y, the calls x.equals(y) and y.equals(x) need to return the same value. Now suppose x is an Item and y a DiscountedItem. Since x.equals(y) doesn't consider discounts, neither can y.equals(x). Note The Java API contains over 150 implementations of equals methods, with a mixture of instanceof tests, calling getClass, catching a ClassCastException, or doing nothing at all. Check out the documentation of the java.sql.Timestamp class, where the implementors note with some embarrassment that the Timestamp class inherits from java.util.Date, whose equals method uses an instanceof test, and it is therefore impossible to override equals to be both symmetric and accurate. There is one situation where the instanceof test makes sense: if the notion of equality is fixed in the superclass and never varies in a subclass. For example, this is the case if we compare employees by ID. In that case, make an instanceof test and declare the equals method as final. Click here to view code image public class Employee { private int id; ... public final boolean equals(Object otherObject) { if (this == otherObject) return true; if (!(otherObject instanceof Employee)) return false; Employee other = (Employee) otherObject; return id == other.id; } public int hashCode() { ... } WOW! eBook www.wowebook.org

}

4.2.3 The hashCode Method A hash code is an integer that is derived from an object. Hash codes should be scrambled—if x and y are two unequal objects, there should be a high probability that x.hashCode() and y.hashCode() are different. For example, "Mary".hashCode() is 2390779, and "Myra".hashCode() is 2413819. The String class uses the following algorithm to compute the hash code: Click here to view code image int hash = 0; for (int i = 0; i < length(); i++) hash = 31 * hash + charAt(i);

The hashCode and equals methods must be compatible: If x.equals(y), then it must be the case that x.hashCode() == y.hashCode(). As you can see, this is the case for the String class since strings with equal characters produce the same hash code. The Object.hashCode method derives the hash code in some implementationdependent way. It can be derived from the object's memory location, or a number (sequential or pseudorandom) that is cached with the object, or a combination of both. Since Object.equals tests for identical objects, the only thing that matters is that identical objects have the same hash code. If you redefine the equals method, you will also need to redefine the hashCode method to be compatible with equals. If you don't, and users of your class insert objects into a hash set or hash map, they might get lost! In your hashCode method, simply combine the hash codes of the instance variables. For example, here is a hashCode method for the Item class: Click here to view code image class Item { ... public int hashCode() { return Objects.hash(description, price); } }

The Objects.hash varargs method computes the hash codes of its arguments and combines them. The method is null-safe. If your class has instance variables that are arrays, compute their hash codes first WOW! eBook www.wowebook.org

with the static Arrays.hashCode method, which computes a hash code composed of the hash codes of the array elements. Pass the result to Objects.hash. Caution In an interface, you can never make a default method that redefines one of the methods in the Object class. In particular, an interface can’t define a default method for toString, equals, or hashCode. As a consequence of the “classes win” rule (see Section 4.1.11, “Inheritance and Default Methods,” page 144), such a method could never win against Object.toString, Object.equals, or Object.hashCode.

4.2.4 Cloning Objects You have just seen the “big three” methods of the Object class that are commonly overridden: toString, equals, and hashCode. In this section, you will learn how to override the clone method. As you will see, this is complex, and it is also rarely necessary. Don't override clone unless you have a good reason to do so. Less than five percent of the classes in the standard Java library implement clone. The purpose of the clone method is to make a “clone” of an object—a distinct object with the same state of the original. If you mutate one of the objects, the other stays unchanged. Click here to view code image Employee cloneOfFred = fred.clone(); cloneOfFred.raiseSalary(10); // fred unchanged

The clone method is declared as protected in the Object class, so you must override it if you want users of your class to clone instances. The Object.clone method makes a shallow copy. It simply copies all instance variables from the original to the cloned object. That is fine if the variables are primitive or immutable. But if they aren't, then the original and the clone share mutable state, which can be a problem. Consider a class for email messages that has a list of recipients. Click here to view code image public final class Message { private String sender; private ArrayList recipients; WOW! eBook www.wowebook.org

private String text; ... public void addRecipient(String recipient) { ... }; }

If you make a shallow copy of a Message object, both the original and the clone share the recipients list (see Figure 4-1): Click here to view code image Message specialOffer = ...; Message cloneOfSpecialOffer = specialOffer.clone();

Figure 4-1 A shallow copy of an object If either object changes the recipient list, the change is reflected in the other. Therefore, the Message class needs to override the clone method to make a deep copy. It may also be that cloning is impossible or not worth the trouble. For example, it would be very challenging to clone a Scanner object. In general, when you implement a class, you need to decide whether 1. You do not want to provide a clone method, or 2. The inherited clone method is acceptable, or 3. The clone method should make a deep copy. For the first option, simply do nothing. Your class will inherit the clone method, but no user of your class will be able to call it since it is protected. To choose the second option, your class must implement the Cloneable interface. This is an interface without any methods, called a tagging or marker interface. (Recall that the clone method is defined in the Object class.) The Object.clone method checks that this interface is implemented before making a WOW! eBook www.wowebook.org

shallow copy, and throws a CloneNotSupportedException otherwise. You will also want to raise the scope of clone from protected to public, and change the return type. Finally, you need to deal with the CloneNotSupportedException. This is a checked exception, and as you will see in Chapter 5, you must either declare or catch it. If your class is final, you can catch it. Otherwise, declare the exception since it is possible that a subclass might again want to throw it. Click here to view code image public class Employee implements Cloneable { ... public Employee clone() throws CloneNotSupportedException { return (Employee) super.clone(); } }

The cast (Employee) is necessary since the return type of Object.clone is Object. The third option for implementing the clone method, in which a class needs to make a deep copy, is the most complex case. You don't need to use the Object.clone method at all. Here is a simple implementation of Message.clone: Click here to view code image public Message clone() { Message cloned = new Message(sender, text); cloned.recipients = new ArrayList(recipients); return cloned; }

Alternatively, you can call clone on the superclass and the mutable instance variables. The ArrayList class implements the clone method, yielding a shallow copy. That is, the original and cloned list share the element references. That is fine in our case since the elements are strings. If not, we would have had to clone each element as well. However, for historical reasons, the ArrayList.clone method has return type Object. You need to use a cast. Click here to view code image cloned.recipients = (ArrayList) recipients.clone(); // Warning WOW! eBook www.wowebook.org

Unhappily, as you will see in Chapter 6, that cast cannot be fully checked at runtime, and you will get a warning. You can suppress the warning with an annotation, but that annotation can only be attached to a declaration (see Chapter 12). Here is the complete method implementation: Click here to view code image public Message clone() { try { Message cloned = (Message) super.clone(); @SuppressWarnings("unchecked") ArrayList clonedRecipients = (ArrayList) recipients.clone(); cloned.recipients = clonedRecipients; return cloned; } catch (CloneNotSupportedException ex) { return null; // Can't happen } }

In this case, the CloneNotSupportedException cannot happen since the Message class is Cloneable and final, and ArrayList.clone does not throw the exception. Note Arrays have a public clone method whose return type is the same as the type of the array. For example, if recipients had been an array, not an array list, you could have cloned it as Click here to view code image cloned.recipients = recipients.clone(); // No cast required

4.3 Enumerations You saw in Chapter 1 how to define enumerated types. Here is a typical example, defining a type with exactly four instances: Click here to view code image public enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE };

In the following sections, you will see how to work with enumerations.

4.3.1 Methods of Enumerations WOW! eBook www.wowebook.org

Since each instance of an enumerated type is unique, you never need to use the equals method for values of enumerated types. Simply use == to compare them. (You can, if you like, call equals which makes the == test.) You also don't need to provide a toString method. It is automatically provided to yield the name of the enumerated object—in our example, "SMALL", "MEDIUM", and so on. The converse of toString is the static valueOf method that is synthesized for each enumerated type. For example, the statement Click here to view code image Size notMySize = Size.valueOf("SMALL");

sets notMySize to Size.SMALL. The valueOf method throws an exception if there is no instance with the given name. Each enumerated type has a static values method that returns an array of all instances of the enumeration, in the order in which they were declared. The call Click here to view code image Size[] allValues = Size.values();

returns the array with elements Size.SMALL, Size.MEDIUM, and so on. Tip Use this method to traverse all instances of an enumerated type in an enhanced for loop: Click here to view code image for (Size s : Size.values()) { System.out.println(s); }

The ordinal method yields the position of an instance in the enum declaration, counting from zero. For example, Size.MEDIUM.ordinal() returns 1. Of course, you need to be careful with this method. The values shift if new constants are inserted. Every enumerated type E automatically implements Comparable, allowing comparisons only against its own objects. The comparison is by ordinal values. Note Technically, an enumerated type E extends the class Enum from which WOW! eBook www.wowebook.org

it inherits the compareTo method as well as the other methods described in this section. Table 4-2 shows the methods of the Enum class. Table 4-2 Methods of the java.lang.Enum Class Method

Description

String toString() The name of this instance, as provided in the enum String name() declaration. The name method is final. int ordinal()

The position of this instance in the enum declaration.

int compareTo(Enum other)

Compares this instance against other by ordinal value.

static T valueOf(Class type, String name)

Returns the instance for a given name. Consider using the synthesized valueOf or values method of the enumeration type instead.

Class Gets the class in which this instance was defined. (This getDeclaringClass() differs from getClass() if the instance has a body.)

int hashCode() protected void finalize()

These methods call the corresponding Object methods and are final.

protected Object Throws a CloneNotSupportedException. clone()

4.3.2 Constructors, Methods, and Fields You can, if you like, add constructors, methods, and fields to an enumerated type. Here is an example: Click here to view code image public enum Size { SMALL("S"), MEDIUM("M"), LARGE("L"), EXTRA_LARGE("XL"); private String abbreviation; Size(String abbreviation) { this.abbreviation = abbreviation; } WOW! eBook www.wowebook.org

public String getAbbreviation() { return abbreviation; } }

Each instance of the enumeration is guaranteed to be constructed exactly once. Note The constructor of an enumeration is always private. You can omit the private modifier, as in the preceding example. It is a syntax error to declare an enum constructor as public or protected.

4.3.3 Bodies of Instances You can add methods to each individual enum instance, but they have to override methods defined in the enumeration. For example, to implement a calculator, you might do this: Click here to view code image public enum Operation { ADD { public int eval(int } }, SUBTRACT { public int eval(int } }, MULTIPLY { public int eval(int } }, DIVIDE { public int eval(int } };

arg1, int arg2) { return arg1 + arg2;

arg1, int arg2) { return arg1 - arg2;

arg1, int arg2) { return arg1 * arg2;

arg1, int arg2) { return arg1 / arg2;

public abstract int eval(int arg1, int arg2); }

In the loop of a calculator program, one would set a variable to one of these values, depending on user input, and then invoke eval: Click here to view code image Operation op = ...; WOW! eBook www.wowebook.org

int result = op.eval(first, second);

Note Technically, each of these constants belongs to an anonymous subclass of Operation. Anything that you could place into an anonymous subclass body you can also add into the body of a member.

4.3.4 Static Members It is legal for an enumeration to have static members. However, you have to be careful with construction order. The enumerated constants are constructed before the static members, so you cannot refer to any static members in an enumeration constructor. For example, the following would be illegal: Click here to view code image public enum Modifier { PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, ABSTRACT; private static int maskBit = 1; private int mask; Modifier() { mask = maskBit; // Error—cannot access static variable in constructor maskBit *= 2; } ... }

The remedy is to do the initialization in a static initializer: Click here to view code image public enum Modifier { PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, ABSTRACT; private int mask; static { int maskBit = 1; for (Modifier m : Modifier.values()) { m.mask = maskBit; maskBit *= 2; } } ... }

Once the constants have been constructed, static variable initializations and static WOW! eBook www.wowebook.org

initializers run in the usual top-to-bottom fashion. Note Enumerated types can be nested inside classes. Such nested enumerations are implicitly static nested classes—that is, their methods cannot reference instance variables of the enclosing class.

4.3.5 Switching on an Enumeration You can use enumeration constants in a switch statement. Click here to view code image enum Operation { ADD, SUBTRACT, MULTIPLY, DIVIDE }; public static int eval(Operation op, int arg1, int arg2) { int result = 0; switch (op) { case ADD: result = arg1 + arg2; break; case SUBTRACT: result = arg1 - arg2; break; case MULTIPLY: result = arg1 * arg2; break; case DIVIDE: result = arg1 / arg2; break; } return result; }

You use ADD, not Operation.ADD, inside the switch statement—the type is inferred from the type of the expression on which the switch is computed. Note According to the language specification, compilers are encouraged to give a warning if a switch on an enumeration is not exhaustive—that is, if there aren't cases for all constants and no default clause. The Oracle compiler does not produce such a warning.

Tip If you want to refer to the instances of an enumeration by their simple name outside a switch, use a static import declaration. For example, with the declaration WOW! eBook www.wowebook.org

Click here to view code image import static com.horstmann.corejava.Size.*;

you can use SMALL instead of Size.SMALL.

4.4 Runtime Type Information and Resources In Java, you can find out at runtime to which class a given object belongs. This is sometimes useful, for example in the implementation of the equals and toString methods. Moreover, you can find out how the class was loaded and load its associated data, called resources.

4.4.1 The Class Class Suppose you have a variable of type Object, filled with some object reference, and you want to know more about the object, such as to which class it belongs. The getClass method yields an object of a class called, not surprisingly, Class. Object obj = ...; Class cl = obj.getClass();

Note See Chapter 6 for an explanation of the suffix. For now, just ignore it. But don't omit it. If you do, not only does your IDE give you an unsightly warning, but you also turn off useful type checks in expressions involving the variable. Once you have a Class object, you can find out the class name: Click here to view code image System.out.println("This object is an instance of " + cl.getName());

Alternatively, you can get a Class object by using the static Class.forName method: Click here to view code image String className = "java.util.Scanner"; Class cl = Class.forName(className); // An object describing the java.util.Scanner class

WOW! eBook www.wowebook.org

Caution The Class.forName method, as well as many other methods used with reflection, throws checked exceptions when something goes wrong (for example, when there is no class with the given name). For now, tag the calling method with throws ReflectiveOperationException. You will see in Chapter 5 how to handle the exception. The Class.forName method is intended for constructing Class objects for classes that may not be known at compile time. If you know in advance which class you want, use a class literal instead: Click here to view code image Class cl = java.util.Scanner.class;

The .class suffix can be used to get information about other types as well: Click here to view code image Class Class Class Class

cl2 cl3 cl4 cl5

= = = =

String[].class; // Describes the array type String[] Runnable.class; // Describes the Runnable interface int.class; // Describes the int type void.class; // Describes the void type

Arrays are classes in Java, but interfaces, primitive types, and void are not. The name Class is a bit unfortunate—Type would have been more accurate. Caution The getName method returns strange names for array types: • String[].class.getName() returns "[Ljava.lang.String;" • int[].class.getName() returns "[I" This notation has been used since archaic times in the virtual machine. Use getCanonicalName instead to get names such as "java.lang.String[]" and "int[]". You need to use the archaic notation with the Class.forName method if you want to generate Class objects for arrays. The virtual machine manages a unique Class object for each type. Therefore, you can use the == operator to compare class objects. For example:

WOW! eBook www.wowebook.org

Click here to view code image if (other.getClass() == Employee.class) ...

You have already seen this use of class objects in Section 4.2.2, “The equals Method” (page 148). In the following sections, you will see what you can do with Class objects. See Table 4-3 for a summary of useful methods. Table 4-3 Useful Methods of the java.lang.Class Class Method

Description

static Class forName(String className)

Gets the Class object describing className.

String String String String String String

Gets the name of this class, with various idiosyncrasies for arrays, inner classes, generic classes, and modifiers (see Exercise 8).

getCanonicalName() getSimpleName() getTypeName() getName() toString() toGenericString()

Class[] getInterfaces() Package getPackage() int getModifiers()

Gets the superclass, the implemented interfaces, package, and modifiers of this class. Table 4-4 shows how to analyze the value returned by getModifiers.

boolean boolean boolean boolean boolean boolean boolean boolean

Tests whether the represented type is primitive or void, an array, an enumeration, an annotation (see Chapter 12), nested in another class, local to a method or constructor, anonymous, or synthetic (see Section 4.5.7).

isPrimitive() isArray() isEnum() isAnnotation() isMemberClass() isLocalClass() isAnonymousClass() isSynthetic()

Class getComponentType() Class getDeclaringClass() Class getEnclosingClass()

Gets the component type of an array, the class declaring a nested class, the class and constructor or method in which a local class WOW! eBook www.wowebook.org

Constructor getEnclosingConstructor() Method getEnclosingMethod()

is declared.

boolean isAssignableFrom(Class cls) boolean isInstance(Object obj)

Tests whether the type cls or the class of obj is a subtype of this type.

String getPackageName()

Gets the fully qualified package name of this class or, if it is not a top-level class, its enclosing class.

ClassLoader getClassLoader()

Gets the class loader that loaded this class (see Section 4.4.3).

InputStream getResourceAsStream(String Loads the requested resource from the same path) location from which this class was loaded. URL getResource(String path) Field[] getFields() Method[] getMethods() Gets all public fields or methods, or the Field getField(String name) Method getMethod(String name, specified field or method, from this class or a superclass. Class... parameterTypes) Field[] getDeclaredFields() Method[] getDeclaredMethods() Field getDeclaredField(String name) Gets all fields or methods, or the specified Method getDeclaredMethod(String name, field or method, from this class. Class... parameterTypes)

Constructor[] getConstructors() Constructor[] getDeclaredConstructors()

Gets all public constructors, or all WOW! eBook www.wowebook.org

Constructor constructors, or the specified public getConstructor(Class... constructor, or the specified constructor, for parameterTypes) this class. Constructor getDeclaredConstructor(Class