847 155 166MB
English Pages 1717 Year 2020
INTRODUCTION TO
JAVA ™
PROGRAMMING AND DATA STRUCTURES COMPREHENSIVE VERSION Twelfth Edition
Y. Daniel Liang Georgia Southern University
A01_LIAN9966_12_SE_FM.indd 1
28/09/19 3:26 PM
To Samantha, Michael, and Michelle Microsoft and/or its respective suppliers make no representations about the suitability of the information contained in the documents and related graphics published as part of the services for any purpose. All such documents and related graphics are provided “as is” without warranty of any kind. Microsoft and/or its respective suppliers hereby disclaim all warranties and conditions with regard to this information, including all warranties and conditions of merchantability, whether express, implied or statutory, fitness for a particular purpose, title and non-infringement. In no event shall Microsoft and/or its respective suppliers be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of information available from the services. The documents and related graphics contained herein could include technical inaccuracies or typographical errors. Changes are periodically added to the information herein. Microsoft and/or its respective suppliers may make improvements and/or changes in the product(s) and/or the program(s) described herein at any time. Partial screen shots may be viewed in full within the software version specified.
Microsoft® and Windows® are registered trademarks of the Microsoft Corporation in the U.S.A. and other countries. This book is not sponsored or endorsed by or affiliated with the Microsoft Corporation. Copyright © 2020, 2018, 2015 by Pearson Education, Inc. or its affiliates, 221 River Street, Hoboken, NJ 07030. All Rights Reserved. Manufactured in the United States of America. This publication is protected by copyright, and permission should 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 otherwise. For information regarding permissions, request forms, and the appropriate contacts within the Pearson Education Global Rights and Permissions department, please visit www.pearsoned.com/permissions/. Acknowledgments of third-party content appear on the appropriate page within the text PEARSON, ALWAYS LEARNING, and MYLAB are exclusive trademarks owned by Pearson Education, Inc. or its affiliates in the U.S. and/or other countries. Unless otherwise indicated herein, any third-party trademarks, logos, or icons that may appear in this work are the property of their respective owners, and any references to third-party trademarks, logos, icons, or other trade dress are for demonstrative or descriptive purposes only. Such references are not intended to imply any sponsorship, endorsement, authorization, or promotion of Pearson’s products by the owners of such marks, or any relationship between the owner and Pearson Education, Inc., or its affiliates, authors, licensees, or distributors. Library of Congress Cataloging-in-Publication Data Names: Liang, Y. Daniel, author. Title: Java programming and data structures / Y. Daniel Liang, Georgia Southern University. Other titles: Introduction to Java programming and data structures Description: Twelfth edition. Comprehensive version | Hoboken, NJ : Pearson, 2019. | Revised edition of: Introduction to Java programming and data structures / Y. Daniel Liang, Georgia Southern University. Eleventh edition. Comprehensive version. 2018. | Includes bibliographical references and index. Identifiers: LCCN 2019038073 | ISBN 9780136520238 (paperback) Subjects: LCSH: Java (Computer program language) Classification: LCC QA76.73.J38 L52 2019 | DDC 005.13/3–dc23 LC record available at https://lccn.loc.gov/2019038073
ScoutAutomatedPrintCode LLE ISBN ISBN-10: 0-13-651996-2 ISBN-13: 978-0-13-651996-6
SE ISBN-10: 0-13-652023-5 ISBN-13: 978-0-13-652023-8
A01_LIAN9966_12_SE_FM.indd 2
28/09/19 3:26 PM
PREFACE Dear Reader, Many of you have provided feedback on earlier editions of this book, and your comments and suggestions have greatly improved the book. This edition has been substantially enhanced in presentation, organization, examples, exercises, and supplements. The book is fundamentals first by introducing basic programming concepts and techniques before designing custom classes. The fundamental concepts and techniques of selection statements, loops, methods, and arrays are the foundation for programming. Building this strong foundation prepares students to learn object-oriented programming and advanced Java programming. This book teaches programming in a problem-driven way that focuses on problem solving rather than syntax. We make introductory programming interesting by using thought- provoking problems in a broad context. The central thread of early chapters is on problem solving. Appropriate syntax and library are introduced to enable readers to write programs for solving the problems. To support the teaching of programming in a problem-driven way, the book provides a wide variety of problems at various levels of difficulty to motivate students. To appeal to students in all majors, the problems cover many application areas, including math, science, business, financial, gaming, animation, and multimedia. The book seamlessly integrates programming, data structures, and algorithms into one text. It employs a practical approach to teach data structures. We first introduce how to use various data structures to develop efficient algorithms, and then show how to implement these data structures. Through implementation, students gain a deep understanding on the efficiency of data structures and on how and when to use certain data structures. Finally, we design and implement custom data structures for trees and graphs. The book is widely used in the introductory programming, data structures, and algorithms courses in the universities around the world. This comprehensive version covers fundamentals of programming, object-oriented programming, GUI programming, data structures, algorithms, concurrency, networking, database, and Web programming. It is designed to prepare students to become proficient Java programmers. A brief version (Introduction to Java Programming, Brief Version, Twelfth Edition) is available for a first course on programming, commonly known as CS1. The brief version contains the first 18 chapters of the comprehensive version. An AP version of the book is also available for high school students taking an AP Computer Science course. The best way to teach programming is by example, and the only way to learn p rogramming is by doing. Basic concepts are explained by example and a large number of exercises with various levels of difficulty are provided for students to practice. For our programming courses, we assign programming exercises after each lecture. Our goal is to produce a text that teaches problem solving and programming in a broad context using a wide variety of interesting examples. If you have any comments on and suggestions for improving the book, please email me.
fundamentals-first
problem-driven
data structures
comprehensive version
brief version
AP Computer Science examples and exercises
Sincerely, Y. Daniel Liang [email protected] www.pearsonhighered.com/liang
iii
A01_LIAN9966_12_SE_FM.indd 3
28/09/19 3:26 PM
iv Preface
ACM/IEEE Curricular 2013 and ABET Course Assessment The new ACM/IEEE Computer Science Curricular 2013 defines the Body of Knowledge organized into 18 Knowledge Areas. To help instructors design the courses based on this book, we provide sample syllabi to identify the Knowledge Areas and Knowledge Units. The sample syllabi are for a three semester course sequence and serve as an example for institutional customization. The sample syllabi are accessible from the Instructor Resource Website. Many of our users are from the ABET-accredited programs. A key component of the ABET accreditation is to identify the weakness through continuous course assessment against the course outcomes. We provide sample course outcomes for the courses and sample exams for measuring course outcomes on the Instructor Resource Website.
What’s New in This Edition? This edition is completely revised in every detail to enhance clarity, presentation, content, examples, and exercises. The major improvements are as follows: ■■
Updated to Java 9, 10, and 11. Examples are improved and simplified by using the new features in Java 9, 10, 11.
■■
The GUI chapters are updated to JavaFX 11. The examples are revised. The user interfaces in the examples and exercises are now resizable and displayed in the center of the window.
■■
More examples and exercises in the data structures chapters use Lambda expressions to simplify coding.
■■
Both Comparable and Comparator are used to compare elements in Heap, PriorityQueue, BST, and AVLTree. This is consistent with the Java API and is more useful and flexible.
■■
String matching algorithms are introduced in Chapter 22.
■■
VideoNotes are updated.
■■
Provided additional exercises not printed in the book. These exercises are available for instructors only.
Please visit www.pearsonhighered.com/liang for a complete list of new features as well as correlations to the previous edition.
Pedagogical Features The book uses the following elements to help students get the most from the material:
A01_LIAN9966_12_SE_FM.indd 4
■■
The Objectives at the beginning of each chapter list what students should learn from the chapter. This will help them determine whether they have met the objectives after completing the chapter.
■■
The Introduction opens the discussion with a thought-provoking question to motivate the reader to delve into the chapter.
■■
Key Points highlight the important concepts covered in each section.
■■
Check Points provide review questions to help students track their progress as they read through the chapter and evaluate their learning.
28/09/19 3:26 PM
Preface v ■■
Problems and Case Studies, carefully chosen and presented in an easy-to-follow style, teach problem solving and programming concepts. The book uses many small, simple, and stimulating examples to demonstrate important ideas.
■■
The Chapter Summary reviews the important subjects that students should understand and remember. It helps them reinforce the key concepts they have learned in the chapter.
■■
Quizzes are accessible online, grouped by sections, for students to do self-test on programming concepts and techniques.
■■
Programming Exercises are grouped by sections to provide students with opportunities to apply the new skills they have learned on their own. The level of difficulty is rated as easy (no asterisk), moderate (*), hard (**), or challenging (***). The trick of learning programming is practice, practice, and practice. To that end, the book provides a great many exercises. Additionally, more than 200 programming exercises with solutions are provided to the instructors on the Instructor Resource Website. These exercises are not printed in the text.
■■
Notes, Tips, Cautions, and Design Guides are inserted throughout the text to offer valuable advice and insight on important aspects of program development.
Note Provides additional information on the subject and reinforces important concepts.
Tip Teaches good programming style and practice.
Caution Helps students steer away from the pitfalls of programming errors.
Design Guide Provides guidelines for designing programs.
Flexible Chapter Orderings The book is designed to provide flexible chapter orderings to enable GUI, exception handling, recursion, generics, and the Java Collections Framework to be covered earlier or later. The diagram on the next page shows the chapter dependencies.
Organization of the Book The chapters can be grouped into five parts that, taken together, form a comprehensive introduction to Java programming, data structures and algorithms, and database and Web programming. Because knowledge is cumulative, the early chapters provide the conceptual basis for understanding programming and guide students through simple examples and exercises; subsequent chapters progressively present Java programming in detail, culminating with the development of comprehensive Java applications. The appendixes contain a mixed bag of topics, including an introduction to number systems, bitwise operations, regular expressions, and enumerated types.
A01_LIAN9966_12_SE_FM.indd 5
28/09/19 3:26 PM
A01_LIAN9966_12_SE_FM.indd 6
Chapter 8 Multidimensional Arrays
Chapter 28 Graphs and Applications
Note: Chapters 31–44 are bonus chapters available from the Companion Website.
Chapter 43 Red-Black Trees
Chapter 42 2-4 Trees and BTrees
Chapter 30 Aggregate Operations and Collection Streams
Chapter 29 Weighted Graphs and Applications
Chapter 27 Hashing
Note: Chapters 1–30 are in the comprehensive version.
Chapter 26 AVL Trees
Chapter 25 Binary Search Trees
Chapter 23 Sorting
Chapter 22 Developping Efficient Algorithms
Chapter 21 Sets and Maps
Chapter 20 Lists, Stacks, Queues, and Priority Queues
Chapter 19 Generics
Chapter 18 Recursion
Chapter 7 Single-Dimensional Arrays Note: Chapters 1–18 are in the brief version of this book.
Chapter 31 Advanced JavaFX and FXML
Ch 13
Ch 7
Part IV: Data Structures and Algorithms
Chapter 6 Methods
Chapter 17 Binary I/O
Chapter 13 Abstract Classes and Interfaces
Chapter 12 Exception Handling and Text I/O
Chapter 16 JavaFX Controls and Multimedia
Chapter 15 Event-Driven Programming and Animations
Chapter 10 Thinking in Objects Chapter 11 Inheritance and Polymorphism
Chapter 14 JavaFX Basics
Part III: GUI Programming
Chapter 9 Objects and Classes
Part II: Object-Oriented Programming
Chapter 24 Implementing Lists, Stacks, Queues, and Priority Queues
Chapter 5 Loops
Chapter 4 Mathematical Functions, Characters, and Strings
Chapter 3 Selections
Chapter 2 Elementary Programming
Chapter 1 Introduction to Computers, Programs, and Java
Part I: Fundamentals of Programming
Ch 9
Ch 16
Chapter 44 Testing Using JUnit
Chapter 41 Web Services
Chapter 40 RMI
Chapter 39 JavaServer Faces
Chapter 38 JavaServer Pages
Chapter 37 Servlets
Chapter 36 Internationalization
Chapter 35 Advanced Java Database Programming
Chapter 34 Java Database Programming
Chapter 33 Networking
Chapter 32 Multithreading and Parallel Programming
Part V: Advanced Java Programming
vi Preface
28/09/19 3:27 PM
Preface vii Part I: Fundamentals of Programming (Chapters 1–8) The first part of the book is a stepping stone, preparing you to embark on the journey of learning Java. You will begin to learn about Java (Chapter 1) and fundamental programming techniques with primitive data types, variables, constants, assignments, expressions, and operators (Chapter 2), selection statements (Chapter 3), mathematical functions, characters, and strings (Chapter 4), loops (Chapter 5), methods (Chapter 6), and arrays (Chapters 7–8). After Chapter 7, you can jump to Chapter 18 to learn how to write recursive methods for solving inherently recursive problems. Part II: Object-Oriented Programming (Chapters 9–13, and 17) This part introduces object-oriented programming. Java is an object-oriented programming language that uses abstraction, encapsulation, inheritance, and polymorphism to provide great flexibility, modularity, and reusability in developing software. You will learn programming with objects and classes (Chapters 9–10), class inheritance (Chapter 11), polymorphism (Chapter 11), exception handling (Chapter 12), abstract classes (Chapter 13), and interfaces (Chapter 13). Text I/O is introduced in Chapter 12 and binary I/O is discussed in Chapter 17. Part III: GUI Programming (Chapters 14–16 and Bonus Chapter 31) JavaFX is a new framework for developing Java GUI programs. It is not only useful for developing GUI programs, but also an excellent pedagogical tool for learning object-oriented programming. This part introduces Java GUI programming using JavaFX in Chapters 14–16. Major topics include GUI basics (Chapter 14), container panes (Chapter 14), drawing shapes (Chapter 14), event-driven programming (Chapter 15), animations (Chapter 15), and GUI controls (Chapter 16), and playing audio and video (Chapter 16). You will learn the a rchitecture of JavaFX GUI programming and use the controls, shapes, panes, image, and video to develop useful applications. Chapter 31 covers advanced features in JavaFX. Part IV: Data Structures and Algorithms (Chapters 18–30 and Bonus Chapters 42–43) This part covers the main subjects in a typical data structures and algorithms course. Chapter 18 introduces recursion to write methods for solving inherently recursive problems. Chapter 19 presents how generics can improve software reliability. Chapters 20 and 21 introduce the Java Collection Framework, which defines a set of useful API for data structures. Chapter 22 discusses measuring algorithm efficiency in order to choose an appropriate algorithm for applications. Chapter 23 describes classic sorting algorithms. You will learn how to implement several classic data structures lists, queues, and priority queues in Chapter 24. Chapters 25 and 26 introduce binary search trees and AVL trees. Chapter 27 presents hashing and implementing maps and sets using hashing. Chapters 28 and 29 introduce graph applications. Chapter 30 introduces aggregate operations for collection streams. The 2-4 trees, B-trees, and red-black trees are covered in Bonus Chapters 42–43. Part V: Advanced Java Programming (Chapters 32-41, 44) This part of the book is devoted to advanced Java programming. Chapter 32 treats the use of multithreading to make programs more responsive and interactive and introduces parallel programming. Chapter 33 discusses how to write programs that talk with each other from different hosts over the Internet. Chapter 34 introduces the use of Java to develop database projects. Chapter 35 delves into advanced Java database programming. Chapter 36 covers the use of internationalization support to develop projects for international audiences. Chapters 37 and 38 introduce how to use Java servlets and JavaServer Pages to generate dynamic content from Web servers. Chapter 39 introduces modern Web application development using JavaServer Faces. Chapter 40 introduces remote method invocation and Chapter 41 discusses Web services. Chapter 44 introduces testing Java programs using JUnit.
A01_LIAN9966_12_SE_FM.indd 7
28/09/19 3:27 PM
viii Preface Appendixes This part of the book covers a mixed bag of topics. Appendix A lists Java keywords. Appendix B gives tables of ASCII characters and their associated codes in decimal and in hex. Appendix C shows the operator precedence. Appendix D summarizes Java modifiers and their usage. Appendix E discusses special floating-point values. Appendix F introduces number systems and conversions among binary, decimal, and hex numbers. Finally, Appendix G introduces bitwise operations. Appendix H introduces regular expressions. Appendix I covers enumerated types.
Java Development Tools
IDE tutorials
You can use a text editor, such as the Windows Notepad or WordPad, to create Java programs and to compile and run the programs from the command window. You can also use a Java development tool, such as NetBeans or Eclipse. These tools support an integrated development environment (IDE) for developing Java programs quickly. Editing, compiling, building, executing, and debugging programs are integrated in one graphical user interface. Using these tools effectively can greatly increase your programming productivity. NetBeans and Eclipse are easy to use if you follow the tutorials. Tutorials on NetBeans and Eclipse can be found in the supplements on the Companion Website www.pearsonhighered.com/liang.
Student Resource Website The Student Resource Website (www.pearsonhighered.com/liang) contains the following resources: ■■
Answers to CheckPoint questions
■■
Solutions to majority of even-numbered programming exercises
■■
Source code for the examples in the book
■■
Interactive quiz (organized by sections for each chapter)
■■
Supplements
■■
Debugging tips
■■
Video notes
■■
Algorithm animations
■■
Errata
Supplements The text covers the essential subjects. The supplements extend the text to introduce additional topics that might be of interest to readers. The supplements are available from the Companion Website.
Instructor Resource Website The Instructor Resource Website, accessible from www.pearsonhighered.com/liang, contains the following resources:
A01_LIAN9966_12_SE_FM.indd 8
■■
Microsoft PowerPoint slides with interactive buttons to view full-color, syntax-highlighted source code and to run programs without leaving the slides.
■■
Solutions to majority of odd-numbered programming exercises.
28/09/19 3:27 PM
Preface ix ■■
More than 200 additional programming exercises and 300 quizzes organized by chapters. These exercises and quizzes are available only to the instructors. Solutions to these exercises and quizzes are provided.
■■
Web-based quiz generator. (Instructors can choose chapters to generate quizzes from a large database of more than two thousand questions.)
■■
Sample exams. Most exams have four parts: ■■
Multiple-choice questions or short-answer questions
■■
Correct programming errors
■■
Trace programs
■■
Write programs
■■
Sample exams with ABET course assessment.
■■
Projects. In general, each project gives a description and asks students to analyze, design, and implement the project.
Some readers have requested the materials from the Instructor Resource Website. Please understand that these are for instructors only. Such requests will not be answered.
Online Practice and Assessment with MyProgrammingLab MyProgrammingLab helps students fully grasp the logic, semantics, and syntax of programming. Through practice exercises and immediate, personalized feedback, MyProgrammingLab improves the programming competence of beginning students who often struggle with the basic concepts and paradigms of popular high-level programming languages. A self-study and homework tool, a MyProgrammingLab course consists of hundreds of small practice problems organized around the structure of this textbook. For students, the system automatically detects errors in the logic and syntax of their code submissions and offers targeted hints that enable students to figure out what went wrong—and why. For instructors, a comprehensive gradebook tracks correct and incorrect answers and stores the code inputted by students for review. MyProgrammingLab is offered to users of this book in partnership with Turing’s Craft, the makers of the CodeLab interactive programming exercise system. For a full demonstration, to see feedback from instructors and students, or to get started using MyProgrammingLab in your course, visit www.myprogramminglab.com.
Video Notes We are excited about the new Video Notes feature that is found in this new edition. These videos provide additional help by presenting examples of key topics and showing how to solve problems completely from design through coding. Video Notes are available from www.pearsonhighered.com/liang.
VideoNote
Algorithm Animations We have provided numerous animations for algorithms. These are valuable pedagogical tools to demonstrate how algorithms work. Algorithm animations can be accessed from the Companion Website.
A01_LIAN9966_12_SE_FM.indd 9
Animation
28/09/19 3:27 PM
x Preface
Acknowledgments I would like to thank Georgia Southern University for enabling me to teach what I write and for supporting me in writing what I teach. Teaching is the source of inspiration for continuing to improve the book. I am grateful to the instructors and students who have offered comments, suggestions, corrections, and praise. My special thanks go to Stefan Andrei of Lamar University and William Bahn of University of Colorado Colorado Springs for their help to improve the data structures part of this book. This book has been greatly enhanced thanks to outstanding reviews for this and previous editions. The reviewers are: Elizabeth Adams (James Madison University), Syed Ahmed (North G eorgia College and State University), Omar Aldawud (Illinois Institute of Technology), Stefan Andrei (Lamar University), Yang Ang (University of Wollongong, Australia), Kevin Bierre (Rochester Institute of Technology), Aaron Braskin (Mira Costa High School), David Champion (DeVry Institute), James Chegwidden (Tarrant County College), Anup Dargar (University of North Dakota), Daryl Detrick (Warren Hills Regional High School), Charles Dierbach (Towson University), Frank Ducrest (University of Louisiana at Lafayette), Erica Eddy (University of Wisconsin at Parkside), Summer Ehresman (Center Grove High School), Deena Engel (New York University), Henry A. Etlinger (Rochester Institute of Technology), James Ten Eyck (Marist College), Myers Foreman (Lamar University), Olac Fuentes (University of Texas at El Paso), Edward F. Gehringer (North Carolina State University), Harold Grossman (Clemson University), Barbara Guillot (Louisiana State University), Stuart Hansen (University of Wisconsin, Parkside), Dan Harvey (Southern Oregon University), Ron Hofman (Red River College, Canada), Stephen Hughes (Roanoke College), Vladan Jovanovic (Georgia Southern University), Deborah Kabura Kariuki (Stony Point High School), Edwin Kay (Lehigh University), Larry King (University of Texas at Dallas), Nana Kofi (Langara College, Canada), George Koutsogiannakis (Illinois Institute of Technology), Roger Kraft (Purdue University at Calumet), Norman Krumpe (Miami University), Hong Lin (DeVry Institute), Dan Lipsa (Armstrong State University), James Madison (Rensselaer Polytechnic Institute), Frank Malinowski (Darton College), Tim Margush (University of Akron), Debbie Masada (Sun Microsystems), Blayne Mayfield (Oklahoma State University), John McGrath (J.P. McGrath Consulting), Hugh McGuire (Grand Valley State), Shyamal Mitra (University of Texas at Austin), Michel Mitri (James Madison University), Kenrick Mock (University of Alaska Anchorage), Frank Murgolo (California State University, Long Beach), Jun Ni (University of Iowa), Benjamin N ystuen (University of Colorado at Colorado Springs), Maureen Opkins (CA State University, Long Beach), Gavin Osborne (University of Saskatchewan), Kevin Parker (Idaho State University), Dale Parson (Kutztown University), Mark Pendergast (Florida Gulf Coast University), Richard Povinelli (Marquette University), Roger Priebe (University of Texas at Austin), Mary Ann Pumphrey (De Anza Junior College), Pat Roth (Southern Polytechnic State University), Amr Sabry (Indiana University), Ben Setzer (Kennesaw State University), Carolyn Schauble (Colorado State University), David Scuse (University of Manitoba), Ashraf Shirani (San Jose State University), Daniel Spiegel (Kutztown University), Joslyn A. Smith (Florida Atlantic University), Lixin Tao (Pace University), Ronald F. Taylor (Wright State University), Russ Tront (Simon Fraser University), Deborah T rytten (University of Oklahoma), Michael Verdicchio (Citadel), Kent Vidrine (George Washington University), and Bahram Zartoshty (California State University at Northridge). It is a great pleasure, honor, and privilege to work with Pearson. I would like to thank Tracy Johnson and her colleagues Marcia Horton, Demetrius Hall, Yvonne Vannatta, Kristy Alaura, Carole Snyder, Scott Disanno, Bob Engelhardt, Shylaja Gattupalli, and their colleagues for organizing, producing, and promoting this project. As always, I am indebted to my wife, Samantha, for her love, support, and encouragement.
A01_LIAN9966_12_SE_FM.indd 10
28/09/19 3:27 PM
BRIEF CONTENTS 1 Introduction to Computers, 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Programs, and Java™ 1 Elementary Programming 33 Selections 77 Mathematical Functions, Characters, and Strings 121 Loops 159 Methods 205 Single-Dimensional Arrays 249 Multidimensional Arrays 289 Objects and Classes 323 Object-Oriented Thinking 367 Inheritance and Polymorphism 411 Exception Handling and Text I/O 453 Abstract Classes and Interfaces 499 JavaFX Basics 541 Event-Driven Programming and Animations 593 JavaFX UI Controls and Multimedia 643 Binary I/O 691 Recursion 719 Generics 751 Lists, Stacks, Queues, and Priority Queues 775 Sets and Maps 815 Developing Efficient Algorithms 839 Sorting 887 Implementing Lists, Stacks, Queues, and Priority Queues 923 Binary Search Trees 959 AVL Trees 995 Hashing 1015 Graphs and Applications 1045 Weighted Graphs and Applications 1091
30 Aggregate Operations for
Collection Streams 1129
CHAPTER 31–44 are available from the Companion Website at www.pearsonhighered .com/liang 31 Advanced JavaFX and FXML 32 Multithreading and Parallel Programming 33 Networking 34 Java Database Programming 35 Advanced Java Database Programming 36 Internationalization 37 Servlets 38 JavaServer Pages 39 JavaServer Faces 40 RMI 41 Web Services 42 2-4 Trees and B-Trees 43 Red-Black Trees 44 Testing Using JUnit
Appendixes 1161 A Java Keywords and Reserved Words 1163 B The ASCII Character Set 1164 C Operator Precedence Chart 1166 D Java Modifiers 1168 E Special Floating-Point Values 1170 F Number Systems 1171 G Bitwise Operations 1175 H Regular Expressions 1176 I Enumerated Types 1182 J The Big-O, Big-Omega, and Big-Theta Notations 1187
Quick Reference 1189 Index 1191 xi
A01_LIAN9966_12_SE_FM.indd 11
28/09/19 3:27 PM
CONTENTS Chapter 1 I ntroduction to Computers, Programs, and Java™
1.1 Introduction 1.2 What Is a Computer? 1.3 Programming Languages 1.4 Operating Systems 1.5 Java, the World Wide Web, and Beyond 1.6 The Java Language Specification, API, JDK, JRE, and IDE 1.7 A Simple Java Program 1.8 Creating, Compiling, and Executing a Java Program 1.9 Programming Style and Documentation 1.10 Programming Errors 1.11 Developing Java Programs Using NetBeans 1.12 Developing Java Programs Using Eclipse
Chapter 2 Elementary Programming
2.1 Introduction 2.2 Writing a Simple Program 2.3 Reading Input from the Console 2.4 Identifiers 2.5 Variables 2.6 Assignment Statements and Assignment Expressions 2.7 Named Constants 2.8 Naming Conventions 2.9 Numeric Data Types and Operations 2.10 Numeric Literals 2.11 JShell 2.12 Evaluating Expressions and Operator Precedence 2.13 Case Study: Displaying the Current Time 2.14 Augmented Assignment Operators 2.15 Increment and Decrement Operators 2.16 Numeric Type Conversions 2.17 Software Development Process 2.18 Case Study: Counting Monetary Units 2.19 Common Errors and Pitfalls
1
2 2 7 9 10 11 12 15 18 19 23 26
33
34 34 37 40 40 42 43 44 45 48 50 52 54 56 57 58 61 64 67
Chapter 3 Selections 77
xii
A01_LIAN9966_12_SE_FM.indd 12
3.1 Introduction 3.2 boolean Data Type, Values, and Expressions 3.3 if Statements 3.4 Two-Way if-else Statements 3.5 Nested if and Multi-Way if-else Statements 3.6 Common Errors and Pitfalls 3.7 Generating Random Numbers 3.8 Case Study: Computing Body Mass Index 3.9 Case Study: Computing Taxes 3.10 Logical Operators 3.11 Case Study: Determining Leap Year 3.12 Case Study: Lottery
78 78 80 82 83 85 89 91 92 95 99 100
28/09/19 3:27 PM
Contents xiii
3.13 switch Statements 3.14 Conditional Operators 3.15 Operator Precedence and Associativity 3.16 Debugging
Chapter 4 M athematical Functions, Characters, and Strings
4.1 Introduction 4.2 Common Mathematical Functions 4.3 Character Data Type and Operations 4.4 The String Type 4.5 Case Studies 4.6 Formatting Console Output
102 105 106 108
121
122 122 126 131 140 146
Chapter 5 Loops 159
5.1 Introduction 160 5.2 The while Loop 160 5.3 Case Study: Guessing Numbers 163 5.4 Loop Design Strategies 166 5.5 Controlling a Loop with User Confirmation or a Sentinel Value 168 5.6 The do-while Loop 171 5.7 The for Loop 173 5.8 Which Loop to Use? 176 5.9 Nested Loops 178 5.10 Minimizing Numeric Errors 180 5.11 Case Studies 182 5.12 Keywords break and continue 186 5.13 Case Study: Checking Palindromes 189 5.14 Case Study: Displaying Prime Numbers 191
Chapter 6 Methods 205 6.1 Introduction 6.2 Defining a Method 6.3 Calling a Method 6.4 void vs. Value-Returning Methods 6.5 Passing Arguments by Values 6.6 Modularizing Code 6.7 Case Study: Converting Hexadecimals to Decimals 6.8 Overloading Methods 6.9 The Scope of Variables 6.10 Case Study: Generating Random Characters 6.11 Method Abstraction and Stepwise Refinement
206 206 208 211 213 217 219 221 224 225 227
Chapter 7 Single-Dimensional Arrays
249
A01_LIAN9966_12_SE_FM.indd 13
7.1 Introduction 7.2 Array Basics 7.3 Case Study: Analyzing Numbers 7.4 Case Study: Deck of Cards 7.5 Copying Arrays 7.6 Passing Arrays to Methods 7.7 Returning an Array from a Method 7.8 Case Study: Counting the Occurrences of Each Letter 7.9 Variable-Length Argument Lists 7.10 Searching Arrays
250 250 257 258 260 261 264 265 268 269
28/09/19 3:27 PM
xiv Contents
7.11 Sorting Arrays 7.12 The Arrays Class 7.13 Command-Line Arguments
273 274 276
Chapter 8 Multidimensional Arrays
289
Chapter 9 Objects and Classes
323
Chapter 10 Object-Oriented Thinking
367
8.1 Introduction 8.2 Two-Dimensional Array Basics 8.3 Processing Two-Dimensional Arrays 8.4 Passing Two-Dimensional Arrays to Methods 8.5 Case Study: Grading a Multiple-Choice Test 8.6 Case Study: Finding the Closest Pair 8.7 Case Study: Sudoku 8.8 Multidimensional Arrays
9.1 Introduction 9.2 Defining Classes for Objects 9.3 Example: Defining Classes and Creating Objects 9.4 Constructing Objects Using Constructors 9.5 Accessing Objects via Reference Variables 9.6 Using Classes from the Java Library 9.7 Static Variables, Constants, and Methods 9.8 Visibility Modifiers 9.9 Data Field Encapsulation 9.10 Passing Objects to Methods 9.11 Array of Objects 9.12 Immutable Objects and Classes 9.13 The Scope of Variables 9.14 The this Reference
10.1 Introduction 10.2 Class Abstraction and Encapsulation 10.3 Thinking in Objects 10.4 Class Relationships 10.5 Case Study: Designing the Course Class 10.6 Case Study: Designing a Class for Stacks 10.7 Processing Primitive Data Type Values as Objects 10.8 Automatic Conversion between Primitive Types and Wrapper Class Types 10.9 The BigInteger and BigDecimal Classes 10.10 The String Class 10.11 The StringBuilder and StringBuffer Classes
290 290 293 295 296 298 300 303
324 324 326 331 332 336 339 344 346 349 353 355 357 358
368 368 372 375 378 380 382 386 387 388 395
Chapter 11 Inheritance and Polymorphism 411
A01_LIAN9966_12_SE_FM.indd 14
11.1 Introduction 11.2 Superclasses and Subclasses 11.3 Using the super Keyword 11.4 Overriding Methods 11.5 Overriding vs. Overloading 11.6 The Object Class and Its toString() Method 11.7 Polymorphism 11.8 Dynamic Binding 11.9 Casting Objects and the instanceof Operator
412 412 418 421 422 424 425 425 429
28/09/19 3:27 PM
Contents xv
11.10 The Object’s equals Method 11.11 The ArrayList Class 11.12 Useful Methods for Lists 11.13 Case Study: A Custom Stack Class 11.14 The protected Data and Methods 11.15 Preventing Extending and Overriding
Chapter 12 Exception Handling and Text I/O
12.1 Introduction 12.2 Exception-Handling Overview 12.3 Exception Types 12.4 Declaring, Throwing, and Catching Exceptions 12.5 The finally Clause 12.6 When to Use Exceptions 12.7 Rethrowing Exceptions 12.8 Chained Exceptions 12.9 Defining Custom Exception Classes 12.10 The File Class 12.11 File Input and Output 12.12 Reading Data from the Web 12.13 Case Study: Web Crawler
433 434 440 441 442 445
453
454 454 459 462 470 472 472 473 474 477 480 487 488
Chapter 13 Abstract Classes and Interfaces 499
13.1 Introduction 13.2 Abstract Classes 13.3 Case Study: The Abstract Number Class 13.4 Case Study: Calendar and GregorianCalendar 13.5 Interfaces 13.6 The Comparable Interface 13.7 The Cloneable Interface 13.8 Interfaces vs. Abstract Classes 13.9 Case Study: The Rational Class 13.10 Class-Design Guidelines
500 500 505 507 510 514 518 523 526 531
Chapter 14 JavaFX Basics
541
Chapter 15 Event-Driven Programming and Animations
593
A01_LIAN9966_12_SE_FM.indd 15
14.1 Introduction 14.2 JavaFX vs Swing and AWT 14.3 The Basic Structure of a JavaFX Program 14.4 Panes, Groups, UI Controls, and Shapes 14.5 Property Binding 14.6 Common Properties and Methods for Nodes 14.7 The Color Class 14.8 The Font Class 14.9 The Image and ImageView Classes 14.10 Layout Panes and Groups 14.11 Shapes 14.12 Case Study: The ClockPane Class
15.1 Introduction 15.2 Events and Event Sources 15.3 Registering Handlers and Handling Events 15.4 Inner Classes
542 542 542 545 548 551 553 554 556 558 567 580
594 596 597 601
28/09/19 3:27 PM
xvi Contents
15.5 Anonymous Inner Class Handlers 15.6 Simplifying Event Handling Using Lambda Expressions 15.7 Case Study: Loan Calculator 15.8 Mouse Events 15.9 Key Events 15.10 Listeners for Observable Objects 15.11 Animation 15.12 Case Study: Bouncing Ball 15.13 Case Study: US Map
602 605 609 611 613 616 618 626 630
Chapter 16 JavaFX UI Controls and Multimedia
643
Chapter 17 Binary I/O
691
16.1 Introduction 16.2 Labeled and Label 16.3 Button 16.4 CheckBox 16.5 RadioButton 16.6 TextField 16.7 TextArea 16.8 ComboBox 16.9 ListView 16.10 ScrollBar 16.11 Slider 16.12 Case Study: Developing a Tic-Tac-Toe Game 16.13 Video and Audio 16.14 Case Study: National Flags and Anthems
17.1 Introduction 17.2 How Is Text I/O Handled in Java? 17.3 Text I/O vs. Binary I/O 17.4 Binary I/O Classes 17.5 Case Study: Copying Files 17.6 Object I/O 17.7 Random-Access Files
644 644 646 648 651 654 655 659 662 665 668 671 676 679
692 692 693 694 704 706 711
Chapter 18 Recursion 719
18.1 Introduction 18.2 Case Study: Computing Factorials 18.3 Case Study: Computing Fibonacci Numbers 18.4 Problem Solving Using Recursion 18.5 Recursive Helper Methods 18.6 Case Study: Finding the Directory Size 18.7 Case Study: Tower of Hanoi 18.8 Case Study: Fractals 18.9 Recursion vs. Iteration 18.10 Tail Recursion
720 720 723 726 728 731 733 736 740 740
Chapter 19 Generics 751
A01_LIAN9966_12_SE_FM.indd 16
19.1 Introduction 19.2 Motivations and Benefits 19.3 Defining Generic Classes and Interfaces 19.4 Generic Methods 19.5 Case Study: Sorting an Array of Objects
752 752 754 756 758
28/09/19 3:27 PM
Contents xvii
19.6 19.7 19.8 19.9
Raw Types and Backward Compatibility Wildcard Generic Types Erasure and Restrictions on Generics Case Study: Generic Matrix Class
760 761 764 766
Chapter 20 L ists, Stacks, Queues, and Priority Queues
775
Chapter 21 Sets and Maps
815
20.1 Introduction 20.2 Collections 20.3 Iterators 20.4 Using the forEach Method 20.5 Lists 20.6 The Comparator Interface 20.7 Static Methods for Lists and Collections 20.8 Case Study: Bouncing Balls 20.9 Vector and Stack Classes 20.10 Queues and Priority Queues 20.11 Case Study: Evaluating Expressions
21.1 Introduction 21.2 Sets 21.3 Comparing the Performance of Sets and Lists 21.4 Case Study: Counting Keywords 21.5 Maps 21.6 Case Study: Occurrences of Words 21.7 Singleton and Unmodifiable Collections and Maps
776 776 780 782 783 787 792 795 798 800 803
816 816 824 827 828 833 835
Chapter 22 Developing Efficient Algorithms 839
22.1 Introduction 22.2 Measuring Algorithm Efficiency Using Big O Notation 22.3 Examples: Determining Big O 22.4 Analyzing Algorithm Time Complexity 22.5 Finding Fibonacci Numbers Using Dynamic Programming 22.6 Finding Greatest Common Divisors Using Euclid’s Algorithm 22.7 Efficient Algorithms for Finding Prime Numbers 22.8 Finding the Closest Pair of Points Using Divide-and-Conquer 22.9 Solving the Eight Queens Problem Using Backtracking 22.10 Computational Geometry: Finding a Convex Hull 22.11 String Matching
840 840 842 846 849 851 855 861 864 867 869
Chapter 23 Sorting 887
A01_LIAN9966_12_SE_FM.indd 17
23.1 Introduction 23.2 Insertion Sort 23.3 Bubble Sort 23.4 Merge Sort 23.5 Quick Sort 23.6 Heap Sort 23.7 Bucket and Radix Sorts 23.8 External Sort
888 888 890 892 896 900 907 909
28/09/19 3:27 PM
xviii Contents
Chapter 24 I mplementing Lists, Stacks, Queues, and Priority Queues
923
Chapter 25 Binary Search Trees
959
Chapter 26 AVL Trees
995
24.1 Introduction 24.2 Common Operations for Lists 24.3 Array Lists 24.4 Linked Lists 24.5 Stacks and Queues 24.6 Priority Queues
25.1 Introduction 25.2 Binary Search Trees Basics 25.3 Representing Binary Search Trees 25.4 Searching for an Element 25.5 Inserting an Element into a BST 25.6 Tree Traversal 25.7 The BST Class 25.8 Deleting Elements from a BST 25.9 Tree Visualization and MVC 25.10 Iterators 25.11 Case Study: Data Compression
26.1 Introduction 26.2 Rebalancing Trees 26.3 Designing Classes for AVL Trees 26.4 Overriding the insert Method 26.5 Implementing Rotations 26.6 Implementing the delete Method 26.7 The AVLTree Class 26.8 Testing the AVLTree Class 26.9 AVL Tree Time Complexity Analysis
924 924 928 935 949 953
960 960 961 962 962 963 965 974 980 983 985
996 996 999 1000 1001 1002 1002 1008 1011
Chapter 27 Hashing 1015
27.1 Introduction 27.2 What Is Hashing? 27.3 Hash Functions and Hash Codes 27.4 Handling Collisions Using Open Addressing 27.5 Handling Collisions Using Separate Chaining 27.6 Load Factor and Rehashing 27.7 Implementing a Map Using Hashing 27.8 Implementing Set Using Hashing
Chapter 28 Graphs and Applications
A01_LIAN9966_12_SE_FM.indd 18
28.1 Introduction 28.2 Basic Graph Terminologies 28.3 Representing Graphs 28.4 Modeling Graphs 28.5 Graph Visualization 28.6 Graph Traversals
1016 1016 1017 1019 1023 1025 1025 1034
1045
1046 1047 1048 1054 1064 1067
28/09/19 3:27 PM
Contents xix
28.7 28.8 28.9 28.10
Depth-First Search (DFS) Case Study: The Connected Circles Problem Breadth-First Search (BFS) Case Study: The Nine Tails Problem
1068 1072 1074 1077
Chapter 29 W eighted Graphs and Applications 1091
29.1 Introduction 29.2 Representing Weighted Graphs 29.3 The WeightedGraph Class 29.4 Minimum Spanning Trees 29.5 Finding Shortest Paths 29.6 Case Study: The Weighted Nine Tails Problem
Chapter 30 Aggregate Operations for Collection Streams
30.1 Introduction 30.2 Stream Pipelines 30.3 IntStream, LongStream, and DoubleStream 30.4 Parallel Streams 30.5 Stream Reduction Using the reduce Method 30.6 Stream Reduction Using the collect Method 30.7 Grouping Elements Using the groupingby Collector 30.8 Case Studies
1092 1093 1095 1103 1109 1118
1129
1130 1130 1136 1139 1141 1144 1147 1150
Chapter 31–44 are available from the Companion Website at www.pearsonhighered.com/liang
Chapter 31 Chapter 32
Advanced JavaFX and FXML
Chapter 33 Chapter 34 Chapter 35 Chapter 36 Chapter 37 Chapter 38 Chapter 39 Chapter 40 Chapter 41
Networking
A01_LIAN9966_12_SE_FM.indd 19
Multithreading and Parallel Programming Java Database Programming Advanced Database Programming Internationalization Servlets JavaServer Pages JavaServer Faces RMI Web Services
28/09/19 3:27 PM
xx Contents
Chapter 42 Chapter 43 Chapter 44 Appendixes Appendix A Appendix B Appendix C Appendix D Appendix E Appendix F Appendix G Appendix H Appendix I Appendix J
2-4 Trees and B-Trees Red-Black Trees Testing Using JUnit
1161
Java Keywords and Reserved Words
1163
The ASCII Character Set
1164
Operator Precedence Chart
1166
Java Modifiers
1168
Special Floating-Point Values
1170
Number Systems
1171
Bitwise Operations
1175
Regular Expressions
1176
Enumerated Types
1182
The Big-O, Big-Omega, and Big-Theta Notations
1187
Quick Reference Index
A01_LIAN9966_12_SE_FM.indd 20
1189 1191
28/09/19 3:27 PM
VideoNotes Locations of VideoNotes
VideoNote
http://www.pearsonhighered.com/liang
Chapter 1
Chapter 2
Chapter 3
Chapter 4
Chapter 5
Chapter 6
Chapter 7
Introduction to Computers, Programs, and Java™ Your first Java program Compile and Run a Java Program NetBeans brief tutorial Eclipse brief tutorial
1 12 17 23 26
Elementary Programming Obtain Input Use operators / and % Software development process Compute loan payments Compute BMI
33 37 54
Selections Program addition quiz Program subtraction quiz Use multi-way if-else statements Sort three integers Check point location
77 79 89 92 112 114
Mathematical Functions, Characters, and Strings Introduce Math functions Introduce strings and objects Convert hex to decimal Compute great circle distance Convert hex to binary
121 122 131 143 152 154
Loops Use while loop Guess a number Multiple subtraction quiz Use do-while loop Minimize numeric errors Display loan schedule Sum a series
159 160 163 166 171 180 197 198
Methods Define/invoke max method Use void method Modularize code Stepwise refinement Reverse an integer Estimate p
205 208 211 217 227 236 240
Single-Dimensional Arrays Random shuffling Deck of cards Selection sort Command-line arguments
249 254 258 273 277
61 62 73
Coupon collector’s problem Consecutive four
284 286
Chapter 8
Multidimensional Arrays Find the row with the largest sum Grade multiple-choice test Sudoku Multiply two matrices Even number of 1s
289 294 296 300 309 316
Chapter 9
Objects and Classes Define classes and create objects Static vs. instance Data field encapsulation Immutable objects and this keyword The this keyword The Fan class
323 324 339 346 355 358 364
Chapter 10 Object-Oriented Thinking the Loan class The BMI class The StackOfIntegers class Process large numbers The String class The MyPoint class
367 369 372 380 387 388 403
Chapter 11 Inheritance and Polymorphism Geometric class hierarchy Polymorphism and dynamic binding demo New Account class
411 412
Chapter 12 Exception Handling and Text I/O Exception-handling advantages Create custom exception classes Write and read data HexFormatException
453 454 474 480 493
Chapter 13 Abstract Classes and Interfaces Abstract GeometricObject class Calendar and GregorianCalendar classes The concept of interface
499 500
Chapter 14 JavaFX Basics Getting started with JavaFX Understand property binding Use Image and ImageView Use layout panes Use shapes Display a tic-tac-toe board Display a bar chart
541 542 548 556 558 567 586 588
426 448
507 510
xxi
A01_LIAN9966_12_SE_FM.indd 21
28/09/19 3:27 PM
xxii VideoNotes Chapter 15 Event-Driven Programming and Animations Handler and its registration Anonymous handler Move message using the mouse Animate a rising flag Flashing text Simple calculator Check mouse-point location Display a running fan Chapter 16 JavaFX UI Controls and Multimedia Use ListView Use Slider Tic-Tac-Toe
593 600 603 612 618 624 634 636 639 643 662 668 671
Use Media, MediaPlayer, and MediaView Use radio buttons and text fields Set fonts
676 683 685
Chapter 17 Binary I/O Copy file Object I/O Split a large file
691 704 706 716
Chapter 18 Recursion Binary search Directory size Search a string in a directory Recursive tree
719 730 731 747 750
Animations Chapter 7
Chapter 8
Single-Dimensional Arrays linear search animation on Companion Website binary search animation on Companion Website selection sort animation on Companion Website
249
Multidimensional Arrays closest-pair animation on the Companion Website
289
270 270 273
298
Chapter 22 Developing Efficient Algorithms binary search animation on the Companion Website selection sort animation on the Companion Website closest-pair animation on Companion Website Eight Queens animation on the Companion Website convex hull animation on the Companion Website
839
Chapter 23 Sorting insertion-sort animation on Companion Website bubble sort animation on the Companion Website merge animation on Companion Website partition animation on Companion Website radix sort on Companion Website
887
A01_LIAN9966_12_SE_FM.indd 22
846 846 861 864 867
888 890 894 898 908
Chapter 24 Implementing Lists, Stacks, Queues, and Priority Queues list animation on Companion Website stack and queue animation on Companion Website
923 924 950
Chapter 25 Binary Search Trees BST animation on Companion Website
959
Chapter 26 AVL Trees AVL tree animation on Companion Website
995
Chapter 27 Hashing linear probing animation on Companion Website quadratic probing animation on Companion Website double hashing animation on Companion Website separate chaining animation on Companion Website
1015
Chapter 28 Graphs and Applications graph learning tool on Companion Website U.S. Map Search
1045
Chapter 29 Weighted Graphs and Applications weighted graph learning tool on Companion Website
960
996
1020 1021 1022 1025
1048 1070 1091 1092
28/09/19 3:27 PM
CHAPTER
1 Introduction to Computers, Programs, and Java™ Objectives ■■
To understand computer basics, programs, and operating systems (§§1.2–1.4).
■■
To describe the relationship between Java and the World Wide Web (§1.5).
■■
To understand the meaning of Java language specification, API, JDK™, JRE™, and IDE (§1.6).
■■
To write a simple Java program (§1.7).
■■
To display output on the console (§1.7).
■■
To explain the basic syntax of a Java program (§1.7).
■■
To create, compile, and run Java programs (§1.8).
■■
To use sound Java programming style and document programs properly (§1.9).
■■
To explain the differences between syntax errors, runtime errors, and logic errors (§1.10).
■■
To develop Java programs using NetBeans™ (§1.11).
■■
To develop Java programs using Eclipse™ (§1.12).
M01_LIAN9966_12_SE_C01.indd 1
12/09/19 8:26 PM
2 Chapter 1 Introduction to Computers, Programs, and Java™
1.1 Introduction Key Point what is programming? programming program
The central theme of this book is to learn how to solve problems by writing a program. This book is about programming. So, what is programming? The term programming means to create (or develop) software, which is also called a program. In basic terms, software contains instructions that tell a computer—or a computerized device—what to do. Software is all around you, even in devices you might not think would need it. Of course, you expect to find and use software on a personal computer, but software also plays a role in running airplanes, cars, cell phones, and even toasters. On a personal computer, you use word processors to write documents, web browsers to explore the Internet, and e-mail programs to send and receive messages. These programs are all examples of software. Software developers create software with the help of powerful tools called programming languages. This book teaches you how to create programs by using the Java programming language. There are many programming languages, some of which are decades old. Each language was invented for a specific purpose—to build on the strengths of a previous language, for example, or to give the programmer a new and unique set of tools. Knowing there are so many programming languages available, it would be natural for you to wonder which one is best. However, in truth, there is no “best” language. Each one has its own strengths and weaknesses. Experienced programmers know one language might work well in some situations, whereas a different language may be more appropriate in other situations. For this reason, seasoned programmers try to master as many different programming languages as they can, giving them access to a vast arsenal of software-development tools. If you learn to program using one language, you should find it easy to pick up other languages. The key is to learn how to solve problems using a programming approach. That is the main theme of this book. You are about to begin an exciting journey: learning how to program. At the outset, it is helpful to review computer basics, programs, and operating systems (OSs). If you are already familiar with such terms as central processing unit (CPU), memory, disks, operating systems, and programming languages, you may skip Sections 1.2–1.4.
1.2 What Is a Computer? A computer is an electronic device that stores and processes data. Key Point hardware software
bus
M01_LIAN9966_12_SE_C01.indd 2
A computer includes both hardware and software. In general, hardware comprises the visible, physical elements of the computer, and software provides the invisible instructions that control the hardware and make it perform specific tasks. Knowing computer hardware isn’t essential to learning a programming language, but it can help you better understand the effects that a program’s instructions have on the computer and its components. This section introduces computer hardware components and their functions. A computer consists of the following major hardware components (see Figure 1.1): ■■
A central processing unit (CPU)
■■
Memory (main memory)
■■
Storage devices (such as disks and CDs)
■■
Input devices (such as the mouse and the keyboard)
■■
Output devices (such as monitors and printers)
■■
Communication devices (such as modems and network interface cards (NIC))
A computer’s components are interconnected by a subsystem called a bus. You can think of a bus as a sort of system of roads running among the computer’s components; data and power travel along the bus from one part of the computer to another. In personal computers,
12/09/19 8:26 PM
1.2 What Is a Computer? 3 Bus
Storage Devices
Memory
CPU
e.g., Disk, CD, and Tape
Communication Devices
Input Devices
Output Devices
e.g., Modem, and NIC
e.g., Keyboard, Mouse
e.g., Monitor, Printer
Figure 1.1 A computer consists of a CPU, memory, storage devices, input devices, output devices, and communication devices.
the bus is built into the computer’s motherboard, which is a circuit case that connects all of the parts of a computer together.
motherboard
1.2.1 Central Processing Unit The central processing unit (CPU) is the computer’s brain. It retrieves instructions from the memory and executes them. The CPU usually has two components: a control unit and an arithmetic/logic unit. The control unit controls and coordinates the actions of the other components. The arithmetic/logic unit performs numeric operations (addition, subtraction, multiplication, and division) and logical operations (comparisons). Today’s CPUs are built on small silicon semiconductor chips that contain millions of tiny electric switches, called transistors, for processing information. Every computer has an internal clock that emits electronic pulses at a constant rate. These pulses are used to control and synchronize the pace of operations. A higher clock speed enables more instructions to be executed in a given period of time. The unit of measurement of clock speed is the hertz (Hz), with 1 Hz equaling 1 pulse per second. In the 1990s, computers measured clock speed in megahertz (MHz, i.e., 1 million pulses per second), but CPU speed has been improving continuously; the clock speed of a computer is now usually stated in gigahertz (GHz, i.e., 1 billion pulses per second). Intel’s newest processors run at about 3 GHz. CPUs were originally developed with only one core. The core is the part of the processor that performs the reading and executing of instructions. In order to increase the CPU processing power, chip manufacturers are now producing CPUs that contain multiple cores. A multicore CPU is a single component with two or more independent cores. Today’s consumer computers typically have two, four, and even eight separate cores. Soon, CPUs with dozens or even hundreds of cores will be affordable.
CPU
speed hertz megahertz gigahertz core
1.2.2 Bits and Bytes Before we discuss memory, let’s look at how information (data and programs) are stored in a computer. A computer is really nothing more than a series of switches. Each switch exists in two states: on or off. Storing information in a computer is simply a matter of setting a sequence of switches on or off. If the switch is on, its value is 1. If the switch is off, its value is 0. These 0s and 1s are interpreted as digits in the binary number system and are called bits (binary digits). The minimum storage unit in a computer is a byte. A byte is composed of eight bits. A small number such as 3 can be stored as a single byte. To store a number that cannot fit into a single byte, the computer uses several bytes. Data of various kinds, such as numbers and characters, are encoded as a series of bytes. As a programmer, you don’t need to worry about the encoding and decoding of data, which the computer system performs automatically, based on the encoding scheme. An encoding scheme is a set of rules that govern how a computer translates characters and numbers into data with which the computer can actually work. Most schemes translate each character into
M01_LIAN9966_12_SE_C01.indd 3
bits byte
encoding scheme
12/09/19 8:26 PM
4 Chapter 1 Introduction to Computers, Programs, and Java™ a predetermined string of bits. In the popular ASCII encoding scheme, for example, the character C is represented as 01000011 in 1 byte. A computer’s storage capacity is measured in bytes and multiples of the byte, as follows: kilobyte (KB)
■■
A kilobyte (KB) is about 1,000 bytes.
megabyte (MB)
■■
A megabyte (MB) is about 1 million bytes.
gigabyte (GB)
■■
A gigabyte (GB) is about 1 billion bytes.
terabyte (TB)
■■
A terabyte (TB) is about 1 trillion bytes.
A typical one-page word document might take 20 KB. Therefore, 1 MB can store 50 pages of documents, and 1 GB can store 50,000 pages of documents. A typical two-hour high- resolution movie might take 8 GB, so it would require 160 GB to store 20 movies.
1.2.3 Memory memory
unique address RAM
A computer’s memory consists of an ordered sequence of bytes for storing programs as well as data with which the program is working. You can think of memory as the computer’s work area for executing a program. A program and its data must be moved into the computer’s memory before they can be executed by the CPU. Every byte in the memory has a unique address, as shown in Figure 1.2. The address is used to locate the byte for storing and retrieving the data. Since the bytes in the memory can be accessed in any order, the memory is also referred to as random-access memory (RAM). Memory address
2000 2001 2002 2003 2004
Memory content
01000011 01110010 01100101 01110111 00000011
Encoding for character C Encoding for character r Encoding for character e Encoding for character w Decimal number 3
Figure 1.2 Memory stores data and program instructions in uniquely addressed memory locations. Today’s personal computers usually have at least 4 GB of RAM, but they more commonly have 8 to 32 GB installed. Generally speaking, the more RAM a computer has, the faster it can operate, but there are limits to this simple rule of thumb. A memory byte is never empty, but its initial content may be meaningless to your program. The current content of a memory byte is lost whenever new information is placed in it. Like the CPU, memory is built on silicon semiconductor chips that have millions of transistors embedded on their surface. Compared to CPU chips, memory chips are less complicated, slower, and less expensive.
1.2.4 Storage Devices storage devices
M01_LIAN9966_12_SE_C01.indd 4
A computer’s memory (RAM) is a volatile form of data storage: Any information that has been saved in memory is lost when the system’s power is turned off. Programs and data are permanently stored on storage devices and are moved, when the computer actually uses them, to memory, which operates at much faster speeds than permanent storage devices can.
12/09/19 8:26 PM
1.2 What Is a Computer? 5 There are four main types of storage devices: ■■
Magnetic disk drives
■■
Optical disc drives (CD and DVD)
■■
Universal serial bus (USB) flash drives
■■
Cloud storage
Drives are devices for operating a medium, such as disks and CDs. A storage medium physically stores data and program instructions. The drive reads data from the medium and writes data onto the medium.
drive
Disks A computer usually has at least one hard disk drive. Hard disks are used for permanently storing data and programs. Newer computers have hard disks that can store from 1 terabyte of data to 4 terabytes of data. Hard disk drives are usually encased inside the computer, but removable hard disks are also available.
hard disk
CDs and DVDs CD stands for compact disc. There are three types of CDs: CD-ROM, CD-R, and CD-RW. A CD-ROM is a prepressed disc. It was popular for distributing software, music, and video. Software, music, and video are now increasingly distributed on the Internet without using CDs. A CD-R (CD-Recordable) is a write-once medium. It can be used to record data once and read any number of times. A CD-RW (CD-ReWritable) can be used like a hard disk; that is, you can write data onto the disc, then overwrite that data with new data. A single CD can hold up to 700 MB. DVD stands for digital versatile disc or digital video disc. DVDs and CDs look alike, and you can use either to store data. A DVD can hold more information than a CD; a standard DVD’s storage capacity is 4.7 GB. There are two types of DVDs: DVD-R (Recordable) and DVD-RW (ReWritable).
CD-ROM CD-R
CD-RW
DVD
USB Flash Drives Universal serial bus (USB) connectors allow the user to attach many kinds of peripheral devices to the computer. You can use an USB to connect a printer, digital camera, mouse, external hard disk drive, and other devices to the computer. An USB flash drive is a device for storing and transporting data. A flash drive is small—about the size of a pack of gum. It acts like a portable hard drive that can be plugged into your computer’s USB port. USB flash drives are currently available with up to 256 GB storage capacity.
Cloud Storage Storing data on the cloud is becoming popular. Many companies provide cloud service on the Internet. For example, you can store Microsoft Office documents in Google Docs. Google Docs can be accessed from docs.google.com on the Chrome browser. The documents can be easily shared with others. Microsoft OneDrive is provided free to Windows user for storing files. The data stored in the cloud can be accessed from any device on the Internet.
1.2.5 Input and Output Devices Input and output devices let the user communicate with the computer. The most common input devices are the keyboard and mouse. The most common output devices are monitors and printers.
M01_LIAN9966_12_SE_C01.indd 5
12/09/19 8:26 PM
6 Chapter 1 Introduction to Computers, Programs, and Java™ The Keyboard
function key modifier key numeric keypad arrow keys Insert key Delete key Page Up key Page Down key
A keyboard is a device for entering input. Compact keyboards are available without a numeric keypad. Function keys are located across the top of the keyboard and are prefaced with the letter F. Their functions depend on the software currently being used. A modifier key is a special key (such as the Shift, Alt, and Ctrl keys) that modifies the normal action of another key when the two are pressed simultaneously. The numeric keypad, located on the right side of most keyboards, is a separate set of keys styled like a calculator to use for quickly entering numbers. Arrow keys, located between the main keypad and the numeric keypad, are used to move the mouse pointer up, down, left, and right on the screen in many kinds of programs. The Insert, Delete, Page Up, and Page Down keys are used in word processing and other programs for inserting text and objects, deleting text and objects, and moving up or down through a document one screen at a time.
The Mouse A mouse is a pointing device. It is used to move a graphical pointer (usually in the shape of an arrow) called a cursor around the screen, or to click on-screen objects (such as a button) to trigger them to perform an action.
The Monitor
screen resolution pixels
dot pitch
The monitor displays information (text and graphics). The screen resolution and dot pitch determine the quality of the display. The screen resolution specifies the number of pixels in horizontal and vertical dimensions of the display device. Pixels (short for “picture elements”) are tiny dots that form an image on the screen. A common resolution for a 17-inch screen, for example, is 1,024 pixels wide and 768 pixels high. The resolution can be set manually. The higher the resolution, the sharper and clearer the image is. The dot pitch is the amount of space between pixels, measured in millimeters. The smaller the dot pitch, the sharper is the display.
Touchscreens The cellphones, tablets, appliances, electronic voting machines, as well as some computers use touchscreens. A touchscreen is integrated with a monitor to enable users to enter input and control the display using a finger.
1.2.6 Communication Devices Computers can be networked through communication devices, such as a dial-up modem (modulator/demodulator), a digital subscriber line (DSL) or cable modem, a wired network interface card, or a wireless adapter. dial-up modem
■■
A dial-up modem uses a phone line to dial a phone number to connect to the Internet and can transfer data at a speed up to 56,000 bps (bits per second).
digital subscriber line (DSL)
■■
A digital subscriber line (DSL) connection also uses a standard phone line, but it can transfer data 20 times faster than a standard dial-up modem. Dial-up modem was used in the 90s and is now replaced by DSL and cable modem.
cable modem
■■
A cable modem uses the cable line maintained by the cable company and is generally faster than DSL.
network interface card (NIC) local area network (LAN)
■■
A network interface card (NIC) is a device that connects a computer to a local area network (LAN). LANs are commonly used to connect computers within a limited
M01_LIAN9966_12_SE_C01.indd 6
12/09/19 8:26 PM
1.3 Programming Languages 7
■■
area such as a school, a home, and an office. A high-speed NIC called 1000BaseT can transfer data at 1,000 million bits per second (mbps).
million bits per second (mbps)
Wi-Fi, a special type of wireless networking, is common in homes, businesses, and schools to connect computers, phones, tablets, and printers to the Internet without the need for a physical wired connection.
Wi-Fi
Note Answers to the CheckPoint questions are available at www.pearsonhighered.com/ liang. Choose this book and click Companion Website to select CheckPoint.
1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7
What are hardware and software? List the five major hardware components of a computer. What does the acronym CPU stand for? What unit is used to measure CPU speed? What is a bit? What is a byte? What is memory for? What does RAM stand for? Why is memory called RAM?
Check Point
What unit is used to measure memory size? What unit is used to measure disk size? What is the primary difference between memory and a storage device?
1.3 Programming Languages Computer programs, known as software, are instructions that tell a computer what to do. Computers do not understand human languages, so programs must be written in a language a computer can use. There are hundreds of programming languages, and they were developed to make the programming process easier for people. However, all programs must be converted into the instructions the computer can execute.
Key Point
1.3.1 Machine Language A computer’s native language, which differs among different types of computers, is its machine language—a set of built-in primitive instructions. These instructions are in the form of binary code, so if you want to give a computer an instruction in its native language, you have to enter the instruction as binary code. For example, to add two numbers, you might have to write an instruction in binary code as follows:
machine language
1101101010011010
1.3.2 Assembly Language Programming in machine language is a tedious process. Moreover, programs written in machine language are very difficult to read and modify. For this reason, assembly language was created in the early days of computing as an alternative to machine languages. Assembly language uses a short descriptive word, known as a mnemonic, to represent each of the machine-language instructions. For example, the mnemonic add typically means to add numbers, and sub means to subtract numbers. To add the numbers 2 and 3 and get the result, you might write an instruction in assembly code as follows:
assembly language
add 2, 3, result
Assembly languages were developed to make programming easier. However, because the computer cannot execute assembly language, another program—called an assembler—is used to translate assembly-language programs into machine code, as shown in Figure 1.3. Writing code in assembly language is easier than in machine language. However, it is still tedious to write code in assembly language. An instruction in assembly language essentially
M01_LIAN9966_12_SE_C01.indd 7
assembler
12/09/19 8:26 PM
8 Chapter 1 Introduction to Computers, Programs, and Java™ Assembly Source File ... add 2, 3, result ...
Machine-Code File Assembler
... 1101101010011010 ...
Figure 1.3 An assembler translates assembly-language instructions into machine code. corresponds to an instruction in machine code. Writing in assembly language requires that you know how the CPU works. Assembly language is referred to as a low-level language, because assembly language is close in nature to machine language and is machine dependent.
low-level language
1.3.3 High-Level Language high-level language
statement
In the 1950s, a new generation of programming languages known as high-level languages emerged. They are platform independent, which means that you can write a program in a high-level language and run it in different types of machines. High-level languages are similar to English and easy to learn and use. The instructions in a high-level programming language are called statements. Here, for example, is a high-level language statement that computes the area of a circle with a radius of 5: area = 5 * 5 * 3.14159;
There are many high-level programming languages, and each was designed for a specific purpose. Table 1.1 lists some popular ones.
Table 1.1 Popular High-Level Programming Languages Language
Description
Ada
Named for Ada Lovelace, who worked on mechanical general-purpose computers. Developed for the Department of Defense and used mainly in defense projects.
BASIC
Beginner’s All-purpose Symbolic Instruction Code. Designed to be learned and used easily by beginners.
C
Developed at Bell Laboratories. Combines the power of an assembly language with the ease of use and portability of a high-level language.
C++
An object-oriented language, based on C
C#
Pronounced “C Sharp.” An object-oriented programming language developed by Microsoft.
COBOL
COmmon Business Oriented Language. Used for business applications.
FORTRAN
FORmula TRANslation. Popular for scientific and mathematical applications.
Java
Developed by Sun Microsystems, now part of Oracle. An object-oriented programming language, widely used for developing platform-independent Internet applications.
JavaScript
A Web programming language developed by Netscape
Pascal
Named for Blaise Pascal, who pioneered calculating machines in the seventeenth century. A simple, structured, general-purpose language primarily for teaching programming.
Python
A simple general-purpose scripting language good for writing short programs.
Visual Basic
Visual Basic was developed by Microsoft. Enables the programmers to rapidly develop Windows-based applications.
source program source code interpreter compiler
M01_LIAN9966_12_SE_C01.indd 8
A program written in a high-level language is called a source program or source code. Because a computer cannot execute a source program, a source program must be translated into machine code for execution. The translation can be done using another programming tool called an interpreter or a compiler.
12/09/19 8:26 PM
1.4 Operating Systems 9 ■■
An interpreter reads one statement from the source code, translates it to the machine code or virtual machine code, then executes it right away, as shown in Figure 1.4a. Note a statement from the source code may be translated into several machine instructions.
■■
A compiler translates the entire source code into a machine-code file, and the machine-code file is then executed, as shown in Figure 1.4b. High-Level Source File Output
... area = 5 * 5 * 3.1415; ...
Interpreter
(a) High-Level Source File ... area = 5 * 5 * 3.1415; ...
Machine-Code File Compiler
... 0101100011011100 1111100011000100 ...
Output Executor
(b)
Figure 1.4 (a) An interpreter translates and executes a program one statement at a time. (b) A compiler translates the entire source program into a machine-language file for execution.
1.3.1 1.3.2 1.3.3 1.3.4 1.3.5
What language does the CPU understand? What is an assembly language? What is an assembler? What is a high-level programming language? What is a source program? What is an interpreter? What is a compiler? What is the difference between an interpreted language and a compiled language?
Check Point
1.4 Operating Systems The operating system (OS) is the most important program that runs on a computer. The OS manages and controls a computer’s activities. The popular operating systems for general-purpose computers are Microsoft Windows, Mac OS, and Linux. Application programs, such as a web browser or a word processor, cannot run unless an operating system is installed and running on the computer. Figure 1.5 shows the interrelationship of hardware, operating system, application software, and the user.
Key Point operating system (OS)
User
Application Programs
Operating System
Hardware
Figure 1.5 Users and applications access the computer’s hardware via the operating system.
M01_LIAN9966_12_SE_C01.indd 9
12/09/19 8:26 PM
10 Chapter 1 Introduction to Computers, Programs, and Java™ The major tasks of an operating system are as follows: ■■
Controlling and monitoring system activities
■■
Allocating and assigning system resources
■■
Scheduling operations
1.4.1 Controlling and Monitoring System Activities Operating systems perform basic tasks, such as recognizing input from the keyboard, sending output to the monitor, keeping track of files and folders on storage devices, and controlling peripheral devices such as disk drives and printers. An operating system must also ensure different programs and users working at the same time do not interfere with each other. In addition, the OS is responsible for security, ensuring unauthorized users and programs are not allowed to access the system.
1.4.2 Allocating and Assigning System Resources The operating system is responsible for determining what computer resources a program needs (such as CPU time, memory space, disks, and input and output devices) and for allocating and assigning them to run the program.
1.4.3 Scheduling Operations The OS is responsible for scheduling programs’ activities to make efficient use of system resources. Many of today’s operating systems support techniques such as multiprogramming, multithreading, and multiprocessing to increase system performance. Multiprogramming allows multiple programs such as Microsoft Word, E-mail, and web browser to run simultaneously by sharing the same CPU. The CPU is much faster than the computer’s other components. As a result, it is idle most of the time—for example, while waiting for data to be transferred from a disk or waiting for other system resources to respond. A multiprogramming OS takes advantage of this situation by allowing multiple programs to use the CPU when it would otherwise be idle. For example, multiprogramming enables you to use a word processor to edit a file at the same time as your web browser is downloading a file. Multithreading allows a single program to execute multiple tasks at the same time. For instance, a word-processing program allows users to simultaneously edit text and save it to a disk. In this example, editing and saving are two tasks within the same program. These two tasks may run concurrently. Multiprocessing is similar to multithreading. The difference is that multithreading is for running multithreads concurrently within one program, but multiprocessing is for running multiple programs concurrently using multiple processors.
multiprogramming multithreading multiprocessing
Check Point
1.4.1 What is an operating system? List some popular operating systems. 1.4.2 What are the major responsibilities of an operating system? 1.4.3 What are multiprogramming, multithreading, and multiprocessing?
1.5 Java, the World Wide Web, and Beyond Key Point
M01_LIAN9966_12_SE_C01.indd 10
Java is a powerful and versatile programming language for developing software running on mobile devices, desktop computers, and servers. This book introduces Java programming. Java was developed by a team led by James Gosling at Sun Microsystems. Sun Microsystems was purchased by Oracle in 2010. Originally called Oak, Java was designed in 1991 for use in embedded chips in consumer electronic appliances.
12/09/19 8:26 PM
1.6 The Java Language Specification, API, JDK, JRE, and IDE 11 In 1995, renamed Java, it was redesigned for developing web applications. For the history of Java, see www.java.com/en/javahistory/index.jsp. Java has become enormously popular. Its rapid rise and wide acceptance can be traced to its design characteristics, particularly its promise that you can write a program once and run it anywhere. As stated by its designer, Java is simple, object oriented, distributed, interpreted, robust, secure, architecture neutral, portable, high performance, multithreaded, and dynamic. For the anatomy of Java characteristics, see liveexample.pearsoncmg.com/etc/JavaCharacteristics.pdf. Java is a full-featured, general-purpose programming language that can be used to develop robust mission-critical applications. It is employed not only on desktop computers, but also on servers and mobile devices. Today, more than 3 billion devices run Java. Most major companies use Java in some applications. Most server-side applications were developed using Java. Java was used to develop the code to communicate with and control the robotic rover on Mars. The software for Android cell phones is developed using Java. Java initially became attractive because Java programs can run from a web browser. Such programs are called applets. Today applets are no longer allowed to run from a Web browser due to security issues. Java, however, is now very popular for developing applications on web servers. These applications process data, perform computations, and generate dynamic webpages. Many commercial Websites are developed using Java on the backend.
1.5.1 Who invented Java? Which company owns Java now? 1.5.2 What is a Java applet? 1.5.3 What programming language does Android use?
Check Point
1.6 The Java Language Specification, API, JDK, JRE, and IDE Java syntax is defined in the Java language specification, and the Java library is defined in the Java application program interface (API). The JDK is the software for compiling and running Java programs. An IDE is an integrated development environment for rapidly developing programs. Computer languages have strict rules of usage. If you do not follow the rules when writing a program, the computer will not be able to understand it. The Java language specification and the Java API define the Java standards. The Java language specification is a technical definition of the Java programming language’s syntax and semantics. You can find the complete Java language specification at docs.oracle.com/javase/specs/. The application program interface (API), also known as library, contains predefined classes and interfaces for developing Java programs. The API is still expanding. You can view the latest Java API documentation at https://docs.oracle.com/en/java/javase/11/. Java is a full-fledged and powerful language that can be used in many ways. It comes in three editions: ■■
Java Standard Edition (Java SE) to develop client-side applications. The applications can run on desktop.
■■
Java Enterprise Edition (Java EE) to develop server-side applications, such as Java servlets, JavaServer Pages (JSP), and JavaServer Faces (JSF).
■■
Java Micro Edition (Java ME) to develop applications for mobile devices, such as cell phones.
Key Point
Java language specification
API library
Java SE, EE, and ME
This book uses Java SE to introduce Java programming. Java SE is the foundation upon which all other Java technology is based. There are many versions of Java SE. The latest,
M01_LIAN9966_12_SE_C01.indd 11
12/09/19 8:26 PM
12 Chapter 1 Introduction to Computers, Programs, and Java™ Java Development Toolkit (JDK)
Java Runtime Environment (JRE) Integrated development environment
Check Point
Java SE 11 (or simply Java 11), is used in this book. Oracle releases each version with a Java Development Toolkit (JDK). For Java 11, the Java Development Toolkit is called JDK 11. The JDK consists of a set of separate programs, each invoked from a command line, for compiling, running, and testing Java programs. The program for running Java programs is known as Java Runtime Environment (JRE). Instead of using the JDK, you can use a Java development tool (e.g., NetBeans, Eclipse, and TextPad)—software that provides an integrated development environment (IDE) for developing Java programs quickly. Editing, compiling, building, debugging, and online help are integrated in one graphical user interface. You simply enter source code in one window or open an existing file in a window, and then click a button or menu item or press a function key to compile and run the program.
1.6.1 1.6.2 1.6.3 1.6.4
What is the Java language specification? What does JDK stand for? What does JRE stand for? What does IDE stand for? Are tools like NetBeans and Eclipse different languages from Java, or are they dialects or extensions of Java?
1.7 A Simple Java Program Key Point what is a console? console input console output
A Java program is executed from the main method in the class. Let’s begin with a simple Java program that displays the message Welcome to Java! on the console. (The word console is an old computer term that refers to the text entry and display device of a computer. Console input means to receive input from the keyboard, and console output means to display output on the monitor.) The program is given in Listing 1.1.
Listing 1.1 Welcome.java class main method
display message
VideoNote
1 2 3 4 5 6
public class Welcome { public static void main(String[] args) { // Display message Welcome to Java! on the console
System.out.println("Welcome to Java!"); } }
Your first Java program Welcome to Java!
line numbers
class name
main method
string statement terminator keyword
M01_LIAN9966_12_SE_C01.indd 12
Note the line numbers are for reference purposes only; they are not part of the program. So, don’t type line numbers in your program. Line 1 defines a class. Every Java program must have at least one class. Each class has a name. By convention, class names start with an uppercase letter. In this example, the class name is Welcome. Line 2 defines the main method. The program is executed from the main method. A class may contain several methods. The main method is the entry point where the program begins execution. A method is a construct that contains statements. The main method in this program contains the System.out.println statement. This statement displays the string Welcome to Java! on the console (line 4). String is a programming term meaning a sequence of characters. A string must be enclosed in double quotation marks. Every statement in Java ends with a semicolon (;), known as the statement terminator. Keywords have a specific meaning to the compiler and cannot be used for other purposes in the program. For example, when the compiler sees the word class, it understands that
12/09/19 8:26 PM
1.7 A Simple Java Program 13 the word after class is the name for the class. Other keywords in this program are public, static, and void. Line 3 is a comment that documents what the program is and how it is constructed. Comments help programmers to communicate and understand the program. They are not programming statements, and thus are ignored by the compiler. In Java, comments are preceded by two slashes (//) on a line, called a line comment, or enclosed between /* and */ on one or several lines, called a block comment or paragraph comment. When the compiler sees //, it ignores all text after // on the same line. When it sees /*, it scans for the next */ and ignores any text between /* and */. Here are examples of comments:
comment
line comment block comment
// This application program displays Welcome to Java! /* This application program displays Welcome to Java! */ /* This application program displays Welcome to Java! */
A pair of braces in a program forms a block that groups the program’s components. In Java, each block begins with an opening brace ({) and ends with a closing brace (}). Every class has a class block that groups the data and methods of the class. Similarly, every method has a method block that groups the statements in the method. Blocks can be nested, meaning that one block can be placed within another, as shown in the following code: public class Welcome { public static void main(String[] args) { System.out.println("Welcome to Java!"); } Method block }
block
Class block
Tip An opening brace must be matched by a closing brace. Whenever you type an opening brace, immediately type a closing brace to prevent the missing-brace error. Most Java IDEs automatically insert the closing brace for each opening brace.
match braces
Caution Java source programs are case sensitive. It would be wrong, for example, to replace main in the program with Main.
You have seen several special characters (e.g., { }, //, ;) in the program. They are used in almost every program. Table 1.2 summarizes their uses. The most common errors you will make as you learn to program will be syntax errors. Like any programming language, Java has its own syntax, and you need to write code that conforms to the syntax rules. If your program violates a rule—for example, if the semicolon is missing, a brace is missing, a quotation mark is missing, or a word is misspelled—the Java
case sensitive special characters common errors syntax rules
Table 1.2 Special Characters Character
Name
Description
{}
Opening and closing braces
Denote a block to enclose statements.
()
Opening and closing parentheses
Used with methods.
[]
Opening and closing brackets
Denote an array.
//
Double slashes
Precede a comment line.
""
Opening and closing quotation marks
Enclose a string (i.e., sequence of characters).
;
Semicolon
Mark the end of a statement.
M01_LIAN9966_12_SE_C01.indd 13
12/09/19 8:26 PM
14 Chapter 1 Introduction to Computers, Programs, and Java™ compiler will report syntax errors. Try to compile the program with these errors and see what the compiler reports.
Note You are probably wondering why the main method is defined this way and why System.out.println(...) is used to display a message on the console. For the time being, simply accept that this is how things are done. Your questions will be fully answered in subsequent chapters.
The program in Listing 1.1 displays one message. Once you understand the program, it is easy to extend it to display more messages. For example, you can rewrite the program to display three messages, as shown in Listing 1.2.
Listing 1.2 WelcomeWithThreeMessages.java 1 2 3 4 5 6 7
class main method
display message
public class WelcomeWithThreeMessages { public static void main(String[] args) { System.out.println("Programming is fun!"); System.out.println("Fundamentals First"); System.out.println("Problem Driven"); } } Programming is fun! Fundamentals First Problem Driven
Further, you can perform mathematical computations and display the result on the console. 10.5 + 2 * 3 Listing 1.3 gives an example of evaluating . 45 - 3.5
Listing 1.3 ComputeExpression.java 1 2 3 4 5 6
class main method
compute expression
public class ComputeExpression { public static void main(String[] args) { System.out.print("(10.5 + 2 * 3) / (45 – 3.5) = "); System.out.println((10.5 + 2 * 3) / (45 – 3.5)); } }
(10.5 + 2 * 3) / (45 – 3.5) = 0.39759036144578314
The print method in line 3
print vs. println
System.out.print("(10.5 + 2 * 3) / (45 – 3.5) = ");
is identical to the println method except that println moves to the beginning of the next line after displaying the string, but print does not advance to the next line when completed. The multiplication operator in Java is *. As you can see, it is a straightforward process to translate an arithmetic expression to a Java expression. We will discuss Java expressions fur ther in Chapter 2. Check Point
M01_LIAN9966_12_SE_C01.indd 14
1.7.1 What is a keyword? List some Java keywords. 1.7.2 Is Java case sensitive? What is the case for Java keywords?
12/09/19 8:27 PM
1.8 Creating, Compiling, and Executing a Java Program 15 1.7.3 What is a comment? Is the comment ignored by the compiler? How do you denote a 1.7.4 1.7.5
comment line and a comment paragraph? What is the statement to display a string on the console? Show the output of the following code:
public class Test { public static void main(String[] args) { System.out.println("3.5 * 4 / 2 – 2.5 is "); System.out.println(3.5 * 4 / 2 – 2.5); } }
1.8 Creating, Compiling, and Executing a Java Program You save a Java program in a .java file and compile it into a .class file. The .class file is executed by the Java Virtual Machine (JVM). You have to create your program and compile it before it can be executed. This process is repetitive, as shown in Figure 1.6. If your program has compile errors, you have to modify the program to fix them, then recompile it. If your program has runtime errors or does not produce the correct result, you have to modify the program, recompile it, and execute it again. You can use any text editor or IDE to create and edit a Java source-code file. This section demonstrates how to create, compile, and run Java programs from a command window. Sections 1.11 and 1.12 will introduce developing Java programs using NetBeans and Eclipse. From the command window, you can use a text editor such as Notepad to create the Java source-code file, as shown in Figure 1.7.
Key Point
command window
Create/Modify Source Code Source code (developed by the programmer) Saved on the disk public class Welcome { public static void main(String[] args) { System.out.println("Welcome to Java!"); Source Code } } Bytecode (generated by the compiler for JVM to read and interpret) … Method Welcome() 0 aload_0 … Method void main(java.lang.String[]) 0 getstatic #2 … 3 ldc #3 5 invokevirtual #4 … 8 return
Compile Source Code e.g., javac Welcome.java If compile errors occur Stored on the disk Bytecode
Run Bytecode e.g., java Welcome
“Welcome to Java” is displayed on the console Welcome to Java!
Result If runtime errors or incorrect result
Figure 1.6 The Java program-development process consists of repeatedly creating/modifying source code, compiling, and executing programs.
M01_LIAN9966_12_SE_C01.indd 15
12/09/19 8:27 PM
16 Chapter 1 Introduction to Computers, Programs, and Java™
Figure 1.7 You can create a Java source file using Windows Notepad.
Note The source file must end with the extension .java and must have the same exact name as the public class name. For example, the file for the source code in Listing 1.1 should be named Welcome.java, since the public class name is Welcome.
file name Welcome.java,
A Java compiler translates a Java source file into a Java bytecode file. The following command compiles Welcome.java:
compile
javac Welcome.java
Note You must first install and configure the JDK before you can compile and run programs. See Supplement I.A, Installing and Configuring JDK 11, for how to install the JDK and set up the environment to compile and run Java programs. If you have trouble compiling and running programs, see Supplement I.B, Compiling and Running Java from the Command Window. This supplement also explains how to use basic DOS commands and how to use Windows Notepad to create and edit files. All the supplements are accessible from the Companion Website.
Supplement I.B Supplement I.C
.class bytecode file
bytecode Java Virtual Machine (JVM)
If there aren’t any syntax errors, the compiler generates a bytecode file with a .class extension. Thus, the preceding command generates a file named Welcome.class, as shown in Figure 1.8a. The Java language is a high-level language, but Java bytecode is a low-level language. The bytecode is similar to machine instructions but is architecture neutral and can run on any platform that has a Java Virtual Machine (JVM), as shown in Figure 1.8b. Rather than a physical machine, the virtual machine is a program that interprets Java bytecode. This is one of Java’s primary advantages: Java bytecode can run on a variety of hardware platforms and operating systems. Java source code is compiled into Java bytecode, and Java bytecode is interpreted by the JVM. Your Java code may use the code in the Java library. The JVM executes your code along with the code in the library. Java Bytecode
generates
Welcome.class (Java bytecode executable file)
Ja
Java Compiler
executed by JVM
tual Mac Vir h va
e in
Welcome.java (Java sourcecode file)
compiled by
Any Computer
Library Code
(a)
(b)
Figure 1.8 (a) Java source code is translated into bytecode. (b) Java bytecode can be executed on any computer with a Java Virtual Machine.
M01_LIAN9966_12_SE_C01.indd 16
12/09/19 8:27 PM
1.8 Creating, Compiling, and Executing a Java Program 17 To execute a Java program is to run the program’s bytecode. You can execute the bytecode on any platform with a JVM, which is an interpreter. It translates the individual instructions in the bytecode into the target machine language code one at a time, rather than the whole program as a single unit. Each step is executed immediately after it is translated. The following command runs the bytecode for Listing 1.1:
interpret bytecode
run
java Welcome
Figure 1.9 shows the javac command for compiling Welcome.java. The compiler generates the Welcome.class file, and this file is executed using the java command.
javac command java command
Note For simplicity and consistency, all source-code and class files used in this book are placed under c:\book unless specified otherwise.
Compile Show files
c:\book
VideoNote
Compile and Run a Java Program
Run
Figure 1.9 The output of Listing 1.1 displays the message “Welcome to Java!”
Caution Do not use the extension .class in the command line when executing the program. Use java ClassName to run the program. If you use java ClassName.class in the command line, the system will attempt to fetch ClassName.class.class.
java ClassName
Note In JDK 11, you can use java ClassName.java to compile and run a single-file source code program. This command combines compiling and running in one command. A single-file source code program contains only one class in the file. This is the case for all of our programs in the first eight chapters.
Tip If you execute a class file that does not exist, a NoClassDefFoundError will occur. If you execute a class file that does not have a main method or you mistype the main method (e.g., by typing Main instead of main), a NoSuchMethodError will occur.
NoClassDefFoundError NoSuchMethodError
Note When executing a Java program, the JVM first loads the bytecode of the class to memory using a program called the class loader. If your program uses other classes, the class loader dynamically loads them just before they are needed. After a class is loaded, the JVM uses a program called the bytecode verifier to check the validity of the
M01_LIAN9966_12_SE_C01.indd 17
class loader bytecode verifier
12/09/19 8:27 PM
18 Chapter 1 Introduction to Computers, Programs, and Java™ bytecode and to ensure that the bytecode does not violate Java’s security restrictions. Java enforces strict security to make sure Java class files are not tampered with and do not harm your computer.
Pedagogical Note Your instructor may require you to use packages for organizing programs. For example, you may place all programs in this chapter in a package named chapter 1. For instructions on how to use packages, see Supplement I.F, Using Packages to Organize the Classes in the Text.
use package
Check Point
1.8.1 What is the Java source filename extension, and what is the Java bytecode filename 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8
extension? What are the input and output of a Java compiler? What is the command to compile a Java program? What is the command to run a Java program?
What is the JVM? Can Java run on any machine? What is needed to run Java on a computer? If a NoClassDefFoundError occurs when you run a program, what is the cause of the error? If a NoSuchMethodError occurs when you run a program, what is the cause of the error?
1.9 Programming Style and Documentation Key Point programming style documentation
Good programming style and proper documentation make a program easy to read and help programmers prevent errors. Programming style deals with what programs look like. A program can compile and run properly even if written on only one line, but writing it all on one line would be a bad programming style because it would be hard to read. Documentation is the body of explanatory remarks and comments pertaining to a program. Programming style and documentation are as important as coding. Good programming style and appropriate documentation reduce the chance of errors and make programs easy to read. This section gives several guidelines. For more detailed guidelines, see Supplement I.C, Java Coding Style Guidelines, on the Companion Website.
1.9.1 Appropriate Comments and Comment Styles
javadoc comment
M01_LIAN9966_12_SE_C01.indd 18
Include a summary at the beginning of the program that explains what the program does, its key features, and any unique techniques it uses. In a long program, you should also include comments that introduce each major step and explain anything that is difficult to read. It is important to make comments concise so that they do not crowd the program or make it difficult to read. In addition to line comments (beginning with //) and block comments (beginning with /*), Java supports comments of a special type, referred to as javadoc comments. javadoc comments begin with /** and end with */. They can be extracted into an HTML file using the JDK’s javadoc command. For more information, see Supplement III.X, javadoc Comments, on the Companion Website. Use javadoc comments (/** . . . */) for commenting on an entire class or an entire method. These comments must precede the class or the method header in order to be extracted into a javadoc HTML file. For commenting on steps inside a method, use line comments (//). To see an example of a javadoc HTML file, check out liveexample.pearsoncmg.com/javadoc/Exercise1. html. Its corresponding Java code is shown in liveexample.pearsoncmg.com/javadoc/Exercise1.txt.
12/09/19 8:27 PM
1.10 Programming Errors 19
1.9.2 Proper Indentation and Spacing A consistent indentation style makes programs clear and easy to read, debug, and maintain. Indentation is used to illustrate the structural relationships between a program’s components or statements. Java can read the program even if all of the statements are on the same long line, but humans find it easier to read and maintain code that is aligned properly. Indent each subcomponent or statement at least two spaces more than the construct within which it is nested. A single space should be added on both sides of a binary operator, as shown in (a), rather in (b). System.out.println(3 + 4 * 4);
indent code
System.out.println(3+4*4);
(a) Good style
(b) Bad style
1.9.3 Block Styles A block is a group of statements surrounded by braces. There are two popular styles, next-line style and end-of-line style, as shown below. public class Test
{ public static void main(String[] args)
public class Test { public static void main(String[] args) { System.out.println("Block Styles");
{
} System.out.println("Block Styles");
}
} } Next-line style
End-of-line style
The next-line style aligns braces vertically and makes programs easy to read, whereas the end-of-line style saves space and may help avoid some subtle programming errors. Both are acceptable block styles. The choice depends on personal or organizational preference. You should use a block style consistently—mixing styles is not recommended. This book uses the end-of-line style to be consistent with the Java API source code.
1.9.1 Reformat the following program according to the programming style and documentation guidelines. Use the end-of-line brace style.
Check Point
public class Test {
// Main method public static void main(String[] args) {
/** Display output */ System.out.println("Welcome to Java"); } }
1.10 Programming Errors Programming errors can be categorized into three types: syntax errors, runtime errors, and logic errors.
Key Point
1.10.1 Syntax Errors Errors that are detected by the compiler are called syntax errors or compile errors. Syntax errors result from errors in code construction, such as mistyping a keyword, omitting some necessary punctuation, or using an opening brace without a corresponding closing brace.
M01_LIAN9966_12_SE_C01.indd 19
syntax errors compile errors
12/09/19 8:27 PM
20 Chapter 1 Introduction to Computers, Programs, and Java™ These errors are usually easy to detect because the compiler tells you where they are and what caused them. For example, the program in Listing 1.4 has a syntax error, as shown in Figure 1.10.
Listing 1.4 ShowSyntaxErrors.java 1 2 3 4 5
public class ShowSyntaxErrors { public static main(String[] args) { System.out.println("Welcome to Java); } }
Four errors are reported, but the program actually has two errors: ■■
The keyword void is missing before main in line 2.
■■
The string Welcome to Java should be closed with a closing quotation mark in line 3.
Since a single error will often display many lines of compile errors, it is a good practice to fix errors from the top line and work downward. Fixing errors that occur earlier in the program may also fix additional errors that occur later.
Compile
Figure 1.10 The compiler reports syntax errors.
Tip fix syntax errors
If you don’t know how to correct an error, compare your program closely, character by character, with similar examples in the text. In the first few weeks of this course, you will probably spend a lot of time fixing syntax errors. Soon you will be familiar with Java syntax, and can quickly fix syntax errors.
1.10.2 Runtime Errors runtime errors
M01_LIAN9966_12_SE_C01.indd 20
Runtime errors are errors that cause a program to terminate abnormally. They occur while a program is running if the environment detects an operation that is impossible to carry out. Input mistakes typically cause runtime errors. An input error occurs when the program is waiting for the user to enter a value, but the user enters a value that the program cannot handle. For instance, if the program expects to read in a number, but instead the user enters a string, this causes data-type errors to occur in the program.
12/09/19 8:27 PM
1.10 Programming Errors 21 Another example of runtime errors is division by zero. This happens when the divisor is zero for integer divisions. For instance, the program in Listing 1.5 would cause a runtime error, as shown in Figure 1.11.
Listing 1.5 ShowRuntimeErrors.java public class ShowRuntimeErrors { public static void main(String[] args) { System.out.println(1 / 0); } }
1 2 3 4 5
runtime error
Run
Figure 1.11 The runtime error causes the program to terminate abnormally.
1.10.3 Logic Errors Logic errors occur when a program does not perform the way it was intended to. Errors of this kind occur for many different reasons. For example, suppose you wrote the program in Listing 1.6 to convert Celsius 35 degrees to a Fahrenheit degree:
logic errors
Listing 1.6 ShowLogicErrors.java 1 2 3 4 5 6
public class ShowLogicErrors { public static void main(String[] args) { System.out.print("Celsius 35 is Fahrenheit degree "); System.out.println((9 / 5) * 35 + 32); } }
Celsius 35 is Fahrenheit degree 67
You will get Fahrenheit 67 degrees, which is wrong. It should be 95.0. In Java, the division for integers is the quotient—the fractional part is truncated—so in Java 9 / 5 is 1. To get the correct result, you need to use 9.0 / 5, which results in 1.8. In general, syntax errors are easy to find and easy to correct because the compiler gives indications as to where the errors came from and why they are wrong. Runtime errors are not difficult to find, either, since the reasons and locations for the errors are displayed on the console when the program aborts. Finding logic errors, on the other hand, can be very challenging. In the upcoming chapters, you will learn the techniques of tracing programs and finding logic errors.
1.10.4 Common Errors Missing a closing brace, missing a semicolon, missing quotation marks for strings, and misspelling names are common errors for new programmers.
M01_LIAN9966_12_SE_C01.indd 21
12/09/19 8:27 PM
22 Chapter 1 Introduction to Computers, Programs, and Java™ Common Error 1: Missing Braces The braces are used to denote a block in the program. Each opening brace must be matched by a closing brace. A common error is missing the closing brace. To avoid this error, type a closing brace whenever an opening brace is typed, as shown in the following example: public class Welcome { }
Type this closing brace right away to match the opening brace
If you use an IDE such as NetBeans and Eclipse, the IDE automatically inserts a closing brace for each opening brace typed. Common Error 2: Missing Semicolons Each statement ends with a statement terminator (;). Often, a new programmer forgets to place a statement terminator for the last statement in a block, as shown in the following example: public static void main(String[] args) { System.out.println("Programming is fun!"); System.out.println("Fundamentals First"); System.out.println("Problem Driven") } Missing a semicolon
Common Error 3: Missing Quotation Marks A string must be placed inside the quotation marks. Often, a new programmer forgets to place a quotation mark at the end of a string, as shown in the following example: System.out.println("Problem Driven ); Missing a quotation mark
If you use an IDE such as NetBeans and Eclipse, the IDE automatically inserts a closing quotation mark for each opening quotation mark typed. Common Error 4: Misspelling Names Java is case sensitive. Misspelling names is a common error for new programmers. For example, the word main is misspelled as Main and String is misspelled as string in the following code: public class Test { public static void Main(string[] args) { System.out.println((10.5 + 2 * 3) / (45 - 3.5)); } }
Check Point
1.10.1 What are syntax errors (compile errors), runtime errors, and logic errors? 1.10.2 Give examples of syntax errors, runtime errors, and logic errors. 1.10.3 If you forget to put a closing quotation mark on a string, what kind of error will be 1.10.4 1.10.5
M01_LIAN9966_12_SE_C01.indd 22
raised? If your program needs to read integers, but the user entered strings, an error would occur when running this program. What kind of error is this? Suppose you write a program for computing the perimeter of a rectangle and you mistakenly write your program so it computes the area of a rectangle. What kind of error is this?
12/09/19 8:27 PM
1.11 Developing Java Programs Using NetBeans 23 1.10.6 Identify and fix the errors in the following code: 1 2 3 4 5
public class Welcome { public void Main(String[] args) { System.out.println('Welcome to Java!); } )
1.11 Developing Java Programs Using NetBeans You can edit, compile, run, and debug Java Programs using NetBeans.
Note Section 1.8 introduced developing programs from the command line. Many of our readers also use an IDE. This section and next section introduce two most popular Java IDEs: NetBeans and Eclipse. These two sections may be skipped.
NetBeans and Eclipse are two free popular integrated development environments for developing Java programs. They are easy to learn if you follow simple instructions. We recommend that you use either one for developing Java programs. This section gives the essential instructions to guide new users to create a project, create a class, compile, and run a class in NetBeans. The use of Eclipse will be introduced in the next section. To use JDK 11, you need NetBeans 9 or higher. For instructions on downloading and installing latest version of NetBeans, see Supplement II.B.
Key Point
VideoNote
NetBeans brief tutorial
1.11.1 Creating a Java Project Before you can create Java programs, you need to first create a project. A project is like a folder to hold Java programs and all supporting files. You need to create a project only once. Here are the steps to create a Java project: 1. Choose File, New Project to display the New Project dialog box, as shown in Figure 1.12. 2. Select Java in the Categories section and Java Application in the Projects section, and then click Next to display the New Java Application dialog box, as shown in Figure 1.13. 3. Type demo in the Project Name field and c:\michael in Project Location field. Uncheck Use Dedicated Folder for Storing Libraries and uncheck Create Main Class. 4. Click Finish to create the project, as shown in Figure 1.14.
Figure 1.12 The New Project dialog is used to create a new project and specify a project type. Source: Copyright © 1995–2016 Oracle and/or its affiliates. All rights reserved. Used with permission.
M01_LIAN9966_12_SE_C01.indd 23
12/09/19 8:27 PM
24 Chapter 1 Introduction to Computers, Programs, and Java™
Figure 1.13 The New Java Application dialog is for specifying a project name and location. Source: Copyright © 1995–2016 Oracle and/or its affiliates. All rights reserved. Used with permission.
Figure 1.14 A New Java project named demo is created. Source: Copyright © 1995–2016 Oracle and/or its affiliates. All rights reserved. Used with permission.
1.11.2 Creating a Java Class After a project is created, you can create Java programs in the project using the following steps: 1. Right-click the demo node in the project pane to display a context menu. Choose New, Java Class to display the New Java Class dialog box, as shown in Figure 1.15. 2. Type Welcome in the Class Name field and select the Source Packages in the Location field. Leave the Package field blank. This will create a class in the default package.
M01_LIAN9966_12_SE_C01.indd 24
12/09/19 8:27 PM
1.11 Developing Java Programs Using NetBeans 25 3. Click Finish to create the Welcome class. The source-code file Welcome.java is placed under the node. 4. Modify the code in the Welcome class to match Listing 1.1 in the text, as shown in Figure 1.16.
1.11.3 Compiling and Running a Class To run Welcome.java, right-click Welcome.java to display a context menu and choose Run File, or simply press Shift + F6. The output is displayed in the Output pane, as shown in Figure 1.16. The Run File command automatically compiles the program if the program has been changed.
Figure 1.15 The New Java Class dialog box is used to create a new Java class. Source: Copyright © 1995–2016 Oracle and/or its affiliates. All rights reserved. Used with permission.
Edit pane
Output pane
Figure 1.16 You can edit a program and run it in NetBeans. Source: Copyright © 1995–2016 Oracle and/or its affiliates. All rights reserved. Used with permission.
M01_LIAN9966_12_SE_C01.indd 25
12/09/19 8:27 PM
26 Chapter 1 Introduction to Computers, Programs, and Java™
1.12 Developing Java Programs Using Eclipse You can edit, compile, run, and debug Java Programs using Eclipse. The preceding section introduced developing Java programs using NetBeans. You can also use Eclipse to develop Java programs. This section gives the essential instructions to guide new users to create a project, create a class, and compile/run a class in Eclipse. To use JDK 11, you need Eclipse 4.9 or higher. For instructions on downloading and installing latest version of Eclipse, see Supplement II.D.
Key Point
1.12.1 Creating a Java Project VideoNote
Eclipse brief tutorial
Before creating Java programs in Eclipse, you need to first create a project to hold all files. Here are the steps to create a Java project in Eclipse: 1. Choose File, New, Java Project to display the New Project wizard, as shown in Figure 1.17.
Figure 1.17 The New Java Project dialog is for specifying a project name and the properties. Source: Eclipse Foundation, Inc.
2. Type demo in the Project name field. As you type, the Location field is automatically set by default. You may customize the location for your project. 3. Make sure you selected the options Use project folder as root for sources and class files so the .java and .class files are in the same folder for easy access. 4. Click Finish to create the project, as shown in Figure 1.18.
M01_LIAN9966_12_SE_C01.indd 26
12/09/19 8:27 PM
1.12 Developing Java Programs Using Eclipse 27
Figure 1.18 A New Java project named demo is created. Source: Eclipse Foundation, Inc.
1.12.2 Creating a Java Class After a project is created, you can create Java programs in the project using the following steps: 1. Choose File, New, Class to display the New Java Class wizard. 2. Type Welcome in the Name field. 3. Check the option public static void main(String[] args). 4. Click Finish to generate the template for the source code Welcome.java, as shown in Figure 1.19.
Figure 1.19 The New Java Class dialog box is used to create a new Java class. Source: Eclipse Foundation, Inc.
M01_LIAN9966_12_SE_C01.indd 27
12/09/19 8:27 PM
28 Chapter 1 Introduction to Computers, Programs, and Java™
1.12.3 Compiling and Running a Class To run the program, right-click the class in the project to display a context menu. Choose Run, Java Application in the context menu to run the class. The output is displayed in the Console pane, as shown in Figure 1.20. The Run command automatically compiles the program if the program has been changed.
Edit pane
Output pane
Figure 1.20 You can edit a program and run it in Eclipse. Source: Eclipse Foundation, Inc.
Key Terms Application Program Interface (API) 11 assembler 7 assembly language 7 bit 3 block 13 block comment 13 bus 2 byte 3 bytecode 16 bytecode verifier 17 cable modem 6 central processing unit (CPU) 3 class loader 17 comment 13 compiler 8 console 12 dial-up modem 6 dot pitch 6 DSL (digital subscriber line) 6 encoding scheme 3 hardware 2 high-level language 8 integrated development environment (IDE) 12
M01_LIAN9966_12_SE_C01.indd 28
interpreter 8 java command 17 Java Development Toolkit (JDK) 12 Java language specification 11 Java Runtime Environment (JRE) 12 Java Virtual Machine (JVM) 16 javac command 17 keyword 12 library 11 line comment 13 logic error 21 low-level language 8 machine language 7 main method 12 memory 4 motherboard 3 network interface card (NIC) 6 operating system (OS) 9 pixel 6 program 2 programming 2 runtime error 20 screen resolution 6 software 2
12/09/19 8:27 PM
Chapter Summary 29 source code 8 source program 8 statement 8
statement terminator 12 storage devices 4 syntax error 19
Note The above terms are defined in this chapter. Glossary (at the end of TOC) lists all the key terms and descriptions in the book, organized by chapters.
Supplement I.A
Chapter Summary 1. A computer is an electronic device that stores and processes data. 2. A computer includes both hardware and software. 3. Hardware is the physical aspect of the computer that can be touched. 4. Computer programs, known as software, are the invisible instructions that control the hardware and make it perform tasks.
5. Computer programming is the writing of instructions (i.e., code) for computers to perform.
6. The central processing unit (CPU) is a computer’s brain. It retrieves instructions from memory and executes them.
7. Computers use zeros and ones because digital devices have two stable states, referred to by convention as zero and one.
8. A bit is a binary digit 0 or 1. 9. A byte is a sequence of 8 bits. 10. A kilobyte is about 1,000 bytes, a megabyte about 1 million bytes, a gigabyte about 1 billion bytes, and a terabyte about 1,000 gigabytes.
11. Memory stores data and program instructions for the CPU to execute. 12. A memory unit is an ordered sequence of bytes. 13. Memory is volatile, because information is lost when the power is turned off. 14. Programs and data are permanently stored on storage devices and are moved to memory when the computer actually uses them.
15. The machine language is a set of primitive instructions built into every computer. 16. Assembly language is a low-level programming language in which a mnemonic is used to represent each machine-language instruction.
17. High-level languages are English-like and easy to learn and program. 18. A program written in a high-level language is called a source program. 19. A compiler is a software program that translates the source program into a machine- language program.
20. The operating system (OS) is a program that manages and controls a computer’s activities.
M01_LIAN9966_12_SE_C01.indd 29
12/09/19 8:27 PM
30 Chapter 1 Introduction to Computers, Programs, and Java™ 21. Java is platform independent, meaning you can write a program once and run it on any computer.
22. The Java source file name must match the public class name in the program. Java source-code files must end with the .java extension.
23. Every class is compiled into a separate bytecode file that has the same name as the class and ends with the .class extension.
24. To compile a Java source-code file from the command line, use the javac command. 25. To run a Java class from the command line, use the java command. 26. Every Java program is a set of class definitions. The keyword class introduces a class definition. The contents of the class are included in a block.
27. A block begins with an opening brace ({) and ends with a closing brace (}). 28. Methods are contained in a class. To run a Java program, the program must have a main method. The main method is the entry point where the program starts when it is
executed.
29. Every statement in Java ends with a semicolon (;), known as the statement terminator. 30. Keywords have a specific meaning to the compiler and cannot be used for other purposes in the program.
31. In Java, comments are preceded by two slashes (//) on a line, called a line comment, or enclosed between /* and */ on one or several lines, called a block comment or paragraph comment. Comments are ignored by the compiler.
32. Java source programs are case sensitive. 33. Programming errors can be categorized into three types: syntax errors, runtime
errors, and logic errors. Errors reported by a compiler are called syntax errors or compile errors. Runtime errors are errors that cause a program to terminate abnormally. Logic errors occur when a program does not perform the way it was intended to.
Quiz Answer the quiz for this chapter at www.pearsonhighered.com/liang. Choose this book and click Companion Website to select Quiz.
Programming Exercises Pedagogical Note
level of difficulty
M01_LIAN9966_12_SE_C01.indd 30
We cannot stress enough the importance of learning programming through exercises. For this reason, the book provides a large number of programming exercises at various levels of difficulty. The problems cover many application areas, including math, science, business, financial, gaming, animation, and multimedia. Solutions to most even-numbered programming exercises are on the Companion Website. Solutions to most odd-numbered programming exercises are on the Instructor Resource Website. The level of difficulty is rated easy (no star), moderate (*), hard (**), or challenging (***).
12/09/19 8:27 PM
Programming Exercises 31
1.1 (Display three messages) Write a program that displays Welcome
1.2 (Display five messages) Write a program that displays Welcome
*1.3
J J J J J
to Java five
times. (Display a pattern) Write a program that displays the following pattern:
J
to Java,
Welcome to Computer Science, and Programming is fun.
A A A AAAAA A
V
V V V V V
A
A A A AAAAA
V A
A
1.4 (Print a table) Write a program that displays the following table: a
a^2
a^3
1
1
1
2
4
8
3
9
27
4
16
64
1.5 (Compute expressions) Write a program that displays the result of
1.6
9.5 * 4.5 - 2.5 * 3 . 45.5 - 3.5 (Summation of a series) Write a program that displays the result of 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9.
1.7 (Approximate p) p can be computed using the following formula: 1 1 1 1 1 + + + cb 3 5 7 9 11 1 1 1 1 1 - + b Write a program that displays the result of 4 * a 1 - + 3 5 7 9 11 1 1 1 1 1 1 - + + b . Use 1.0 instead of 1 in your and 4 * a 1 - + 3 5 7 9 11 13 program. p = 4 * a1 -
1.8 (Area and perimeter of a circle) Write a program that displays the area and perimeter of a circle that has a radius of 5.5 using the following formulas: perimeter = 2 * radius * p area = radius * radius * p
1.9 (Area and perimeter of a rectangle) Write a program that displays the area and
perimeter of a rectangle with a width of 4.5 and a height of 7.9 using the following formula: area = width * height
1.10 (Average speed in miles) Assume that a runner runs 14 kilometers in 45 minutes
and 30 seconds. Write a program that displays the average speed in miles per hour. (Note 1 mile is equal to 1.6 kilometers.)
M01_LIAN9966_12_SE_C01.indd 31
12/09/19 8:27 PM
32 Chapter 1 Introduction to Computers, Programs, and Java™ *1.11 (Population projection) The U.S. Census Bureau projects population based on the following assumptions:
■■ ■■ ■■
1.12 *1.13
One birth every 7 seconds One death every 13 seconds One new immigrant every 45 seconds
Write a program to display the population for each of the next five years. Assume that the current population is 312,032,486, and one year has 365 days. Hint: In Java, if two integers perform division, the result is an integer. The fractional part is truncated. For example, 5 / 4 is 1 (not 1.25) and 10 / 4 is 2 (not 2.5). To get an accurate result with the fractional part, one of the values involved in the division must be a number with a decimal point. For example, 5.0 / 4 is 1.25 and 10 / 4.0 is 2.5. (Average speed in kilometers) Assume that a runner runs 24 miles in 1 hour, 40 minutes, and 35 seconds. Write a program that displays the average speed in kilometers per hour. (Note 1 mile is equal to 1.6 kilometers.) (Algebra: solve 2 * 2 linear equations) You can use Cramer’s rule to solve the following 2 * 2 system of linear equation provided that ad – bc is not 0: ed - bf ax + by = e x = cx + dy = f ad - bc
y =
af - ec ad - bc
Write a program that solves the following equation and displays the value for x and y: (Hint: replace the symbols in the formula with numbers to compute x and y. This exercise can be done in Chapter 1 without using materials in later chapters.) 3.4x + 50.2y = 44.5 2.1x + .55y = 5.9
Note More than 200 additional programming exercises with solutions are provided to the instructors on the Instructor Resource Website.
M01_LIAN9966_12_SE_C01.indd 32
12/09/19 8:27 PM
CHAPTER
2 Elementary Programming Objectives ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■ ■■
To write Java programs to perform simple computations (§2.2). To obtain input from the console using the Scanner class (§2.3). To use identifiers to name variables, constants, methods, and classes (§2.4). To use variables to store data (§§2.5 and 2.6). To program with assignment statements and assignment expressions (§2.6). To use constants to store permanent data (§2.7). To name classes, methods, variables, and constants by following their naming conventions (§2.8). To explore Java numeric primitive data types: byte, short, int, long, float, and double (§2.9). To read a byte, short, int, long, float, or double value from the keyboard (§2.9.1). To perform operations using operators +, -, *, /, and % (§2.9.2). To perform exponent operations using Math.pow(a, b) (§2.9.3). To write integer literals, floating-point literals, and literals in scientific notation (§2.10). To use JShell to quickly test Java code (§2.11). To write and evaluate numeric expressions (§2.12). To obtain the current system time using System.currentTimeMillis() (§2.13). To use augmented assignment operators (§2.14). To distinguish between postincrement and preincrement and between postdecrement and predecrement (§2.15). To cast the value of one type to another type (§2.16). To describe the software development process and apply it to develop the loan payment program (§2.17). To write a program that converts a large amount of money into smaller units (§2.18). To avoid common errors and pitfalls in elementary programming (§2.19).
M02_LIAN9966_12_SE_C02.indd 33
28/09/19 3:45 PM
34 Chapter 2 Elementary Programming
2.1 Introduction Key Point
The focus of this chapter is on learning elementary programming techniques to solve problems. In Chapter 1, you learned how to create, compile, and run very basic Java programs. You will learn how to solve problems by writing programs. Through these problems, you will learn elementary programming using primitive data types, variables, constants, operators, expressions, and input and output. Suppose, for example, you need to take out a student loan. Given the loan amount, loan term, and annual interest rate, can you write a program to compute the monthly payment and total payment? This chapter shows you how to write programs like this. Along the way, you will learn the basic steps that go into analyzing a problem, designing a solution, and implementing the solution by creating a program.
2.2 Writing a Simple Program Key Point problem algorithm pseudocode
Writing a program involves designing a strategy for solving the problem then using a programming language to implement that strategy. Let’s first consider the simple problem of computing the area of a circle. How do we write a program for solving this problem? Writing a program involves designing algorithms and translating algorithms into programming instructions, or code. An algorithm lists the steps you can follow to solve a problem. Algorithms can help the programmer plan a program before writing it in a programming language. Algorithms can be described in natural languages or in pseudocode (natural language mixed with some programming code). The algorithm for calculating the area of a circle can be described as follows: 1. Read in the circle’s radius. 2. Compute the area using the following formula: area = radius * radius * p 3. Display the result.
Tip It’s always a good practice to outline your program (or its underlying problem) in the form of an algorithm before you begin coding.
When you code—that is, when you write a program—you translate an algorithm into a program. You already know every Java program begins with a class definition in which the keyword class is followed by the class name. Assume you have chosen ComputeArea as the class name. The outline of the program would look as follows: public class ComputeArea { // Details to be given later }
As you know, every Java program must have a main method where program execution begins. The program is then expanded as follows: public class ComputeArea { public static void main(String[] args) { // Step 1: Read in radius // Step 2: Compute area
M02_LIAN9966_12_SE_C02.indd 34
28/09/19 3:45 PM
2.2 Writing a Simple Program 35 // Step 3: Display the area } }
The program needs to read the radius entered by the user from the keyboard. This raises two important issues: ■■
Reading the radius
■■
Storing the radius in the program
Let’s address the second issue first. In order to store the radius, the program needs to declare a symbol called a variable. A variable represents a value stored in the computer’s memory. Rather than using x and y as variable names, choose descriptive names: in this case, radius for radius and area for area. To let the compiler know what radius and area are, specify their data types. That is the kind of data stored in a variable, whether an integer, real number, or something else. This is known as declaring variables. Java provides simple data types for representing integers, real numbers, characters, and Boolean types. These types are known as primitive data types or fundamental types. Real numbers (i.e., numbers with a decimal point) are represented using a method known as floating-point in computers. Therefore, the real numbers are also called floating-point numbers. In Java, you can use the keyword double to declare a floating-point variable. Declare radius and area as double. The program can be expanded as follows:
variable descriptive names data type declare variables primitive data types floating-point numbers
public class ComputeArea { public static void main(String[] args) { double radius; double area; // Step 1: Read in radius // Step 2: Compute area // Step 3: Display the area } }
The program declares radius and area as variables. The keyword double indicates that radius and area are floating-point values stored in the computer. The first step is to prompt the user to designate the circle’s radius. You will soon learn how to prompt the user for information. For now, to learn how variables work, you can assign a fixed value to radius in the program as you write the code. Later, you’ll modify the program to prompt the user for this value. The second step is to compute area by assigning the result of the expression radius * radius * 3.14159 to area. In the final step, the program will display the value of area on the console by using the System.out.println method. Listing 2.1 shows the complete program, and a sample run of the program is shown in Figure 2.1.
Listing 2.1 ComputeArea.java 1 2 3 4 5 6 7
public class ComputeArea { public static void main(String[] args) { double radius; // Declare radius double area; // Declare area // Assign a radius radius = 20; // radius is now 20
M02_LIAN9966_12_SE_C02.indd 35
28/09/19 3:45 PM
36 Chapter 2 Elementary Programming 8 9 10 11 12 13 14 15 16
// Compute area area = radius * radius * 3.14159; // Display results System.out.println("The area for the circle of radius " + radius + " is " + area); } }
Compile Run
Figure 2.1 The program displays the area of a circle.
declare variable assign value
tracing program
Variables such as radius and area correspond to memory locations. Every variable has a name, a type, and a value. Line 3 declares that radius can store a double value. The value is not defined until you assign a value. Line 7 assigns 20 into the variable radius. Similarly, line 4 declares the variable area, and line 10 assigns a value into area. The following table shows the value in the memory for area and radius as the program is executed. Each row in the table shows the values of variables after the statement in the corresponding line in the program is executed. This method of reviewing how a program works is called tracing a program. Tracing programs are helpful for understanding how programs work, and they are useful tools for finding errors in programs. line# 3
radius no value
4 7
no value 20
10 concatenate strings concatenate strings with numbers
area
1256.636
The plus sign (+) has two meanings: one for addition, and the other for concatenating (combining) strings. The plus sign (+) in lines 13–14 is called a string concatenation operator. It combines two strings into one. If a string is combined with a number, the number is converted into a string and concatenated with the other string. Therefore, the plus signs (+) in lines 13–14 concatenate strings into a longer string, which is then displayed in the output. Strings and string concatenation will be discussed further in Chapter 4.
Caution A string cannot cross lines in the source code. Thus, the following statement would result in a compile error: System.out.println("Introduction to Java Programming, by Y. Daniel Liang"); break a long string
To fix the error, break the string into separate substrings, and use the concatenation operator (+) to combine them: System.out.println("Introduction to Java Programming, " + "by Y. Daniel Liang");
M02_LIAN9966_12_SE_C02.indd 36
28/09/19 3:45 PM
2.3 Reading Input from the Console 37
2.2.1 Identify and fix the errors in the following code: 1 2 3 4 5 6 7 8 9 10
public class Test { public void main(string[] args) { double i = 50.0; double k = i + 50.0; double j = k + 1;
Check Point
System.out.println("j is " + j + " and k is " + k); } }
2.3 Reading Input from the Console Reading input from the console enables the program to accept input from the user. In Listing 2.1, the radius is fixed in the source code. To use a different radius, you have to modify the source code and recompile it. Obviously, this is not convenient, so instead you can use the Scanner class for console input. Java uses System.out to refer to the standard output device, and System.in to the standard input device. By default, the output device is the display monitor, and the input device is the keyboard. To perform console output, you simply use the println method to display a primitive value or a string to the console. To perform console input, you need to use the Scanner class to create an object to read input from System.in, as follows:
Key Point
VideoNote
Obtain Input
Scanner input = new Scanner(System.in);
The syntax new Scanner(System.in) creates an object of the Scanner type. The syntax Scanner input declares that input is a variable whose type is Scanner. The whole line Scanner input = new Scanner(System.in) creates a Scanner object and assigns its reference to the variable input. An object may invoke its methods. To invoke a method on an object is to ask the object to perform a task. You can invoke the nextDouble() method to read a double value as follows: double radius = input.nextDouble();
This statement reads a number from the keyboard and assigns the number to radius. Listing 2.2 rewrites Listing 2.1 to prompt the user to enter a radius.
Listing 2.2 ComputeAreaWithConsoleInput.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
import java.util.Scanner; // Scanner is in the java.util package
import class
public class ComputeAreaWithConsoleInput { public static void main(String[] args) { // Create a Scanner object Scanner input = new Scanner(System.in);
create a Scanner
// Prompt the user to enter a radius System.out.print("Enter a number for radius: "); double radius = input.nextDouble();
read a double
// Compute area double area = radius * radius * 3.14159; // Display results System.out.println("The area for the circle of radius " +
M02_LIAN9966_12_SE_C02.indd 37
28/09/19 3:45 PM
38 Chapter 2 Elementary Programming 17 18 19
radius + " is " + area); } }
Enter a number for radius: 2.5 The area for the circle of radius 2.5 is 19.6349375
Enter a number for radius: 23 The area for the circle of radius 23.0 is 1661.90111
prompt
The Scanner class is in the java.util package. It is imported in line 1. Line 6 creates a Scanner object. Note the import statement can be omitted if you replace Scanner by java.util.Scanner in line 6. Line 9 displays a string "Enter a number for radius: " to the console. This is known as a prompt, because it directs the user to enter an input. Your program should always tell the user what to enter when expecting input from the keyboard. Recall that the print method in line 9 is identical to the println method, except that println moves to the beginning of the next line after displaying the string, but print does not advance to the next line when completed. Line 6 creates a Scanner object. The statement in line 10 reads input from the keyboard. double radius = input.nextDouble();
specific import
After the user enters a number and presses the Enter key, the program reads the number and assigns it to radius. More details on objects will be introduced in Chapter 9. For the time being, simply accept that this is how we obtain input from the console. The Scanner class is in the java.util package. It is imported in line 1. There are two types of import statements: specific import and wildcard import. The specific import specifies a single class in the import statement. For example, the following statement imports Scanner from the package java.util. import java.util.Scanner;
wildcard import
The wildcard import imports all the classes in a package by using the asterisk as the wildcard. For example, the following statement imports all the classes from the package java.util. import java.util.*;
no performance difference
The information for the classes in an imported package is not read in at compile time or runtime unless the class is used in the program. The import statement simply tells the compiler where to locate the classes. There is no performance difference between a specific import and a wildcard import declaration. Listing 2.3 gives an example of reading multiple inputs from the keyboard. The program reads three numbers and displays their average.
Listing 2.3 ComputeAverage.java import class
create a Scanner
M02_LIAN9966_12_SE_C02.indd 38
1 2 3 4 5 6 7 8 9
import java.util.Scanner; // Scanner is in the java.util package public class ComputeAverage { public static void main(String[] args) { // Create a Scanner object Scanner input = new Scanner(System.in); // Prompt the user to enter three numbers System.out.print("Enter three numbers: ");
28/09/19 3:45 PM
2.3 Reading Input from the Console 39 10 11 12 13 14 15 16 17 18 19 20 21
double number1 = input.nextDouble(); double number2 = input.nextDouble(); double number3 = input.nextDouble();
read a double
// Compute average double average = (number1 + number2 + number3) / 3; // Display results System.out.println("The average of " + number1 + " " + number2 + " " + number3 + " is " + average); } }
Enter three numbers: 1 2 3 The average of 1.0 2.0 3.0 is 2.0
Enter three numbers: 10.5 11 11.5 The average of 10.5 11.0 11.5 is 11.0
The codes for importing the Scanner class (line 1) and creating a Scanner object (line 6) are the same as in the preceding example, as well as in all new programs you will write for reading input from the keyboard. Line 9 prompts the user to enter three numbers. The numbers are read in lines 10–12. You may enter three numbers separated by spaces, then press the Enter key, or enter each number followed by a press of the Enter key, as shown in the sample runs of this program. If you entered an input other than a numeric value, a runtime error would occur. In Chapter 12, you will learn how to handle the exception so the program can continue to run.
enter input in one line
enter input in multiple lines
runtime error
Note Most of the programs in the early chapters of this book perform three steps— input, process, and output—called IPO. Input is receiving input from the user; process is producing results using the input; and output is displaying the results.
IPO
Note If you use an IDE such as Eclipse or NetBeans, you will get a warning to ask you to close the input for preventing a potential resource leak. Ignore the warning for the time being because the input is automatically closed when your program is terminated. In this case, there will be no resource leaking.
2.3.1 How do you write a statement to let the user enter a double value from the keyboard? What happens if you entered 5a when executing the following code?
Warning in IDE
Check Point
double radius = input.nextDouble();
2.3.2 Are there any performance differences between the following two import statements?
import java.util.Scanner; import java.util.*;
M02_LIAN9966_12_SE_C02.indd 39
28/09/19 3:45 PM
40 Chapter 2 Elementary Programming
2.4 Identifiers Key Point
Identifiers are the names that identify the elements such as classes, methods, and variables in a program. As you see in Listing 2.3, ComputeAverage, main, input, number1, number2, number3, and so on are the names of things that appear in the program. In programming terminology, such names are called identifiers. All identifiers must obey the following rules:
identifiers identifier naming rules
■■
An identifier is a sequence of characters that consists of letters, digits, underscores (_), and dollar signs ($).
■■
An identifier must start with a letter, an underscore (_), or a dollar sign ($). It cannot start with a digit.
■■
An identifier cannot be a reserved word. See Appendix A for a list of reserved words. Reserved words have specific meaning in the Java language. Keywords are reserved words.
■■
An identifier can be of any length.
For example, $2, ComputeArea, area, radius, and print are legal identifiers, whereas 2A and d+4 are not because they do not follow the rules. The Java compiler detects illegal identifiers and reports syntax errors.
Note case sensitive
Since Java is case sensitive, area, Area, and AREA are all different identifiers.
Tip Identifiers are for naming variables, methods, classes, and other items in a program. Descriptive identifiers make programs easy to read. Avoid using abbreviations for identifiers. Using complete words is more descriptive. For example, numberOfStudents is better than numStuds, numOfStuds, or numOfStudents. We use descriptive names for complete programs in the text. However, we will occasionally use variable names such as i, j, k, x, and y in the code snippets for brevity. These names also provide a generic tone to the code snippets.
descriptive names
Tip Do not name identifiers with the $ character. By convention, the $ character should be used only in mechanically generated source code.
the $ character
Check Point
2.4.1 Which of the following identifiers are valid? Which are Java keywords? miles, Test, a++, ––a, 4#R, $4, #44, apps class, public, int, x, y, radius
2.5 Variables Variables are used to represent values that may be changed in the program. Key Point why called variables?
M02_LIAN9966_12_SE_C02.indd 40
As you see from the programs in the preceding sections, variables are used to store values to be used later in a program. They are called variables because their values can be changed. In the program in Listing 2.2, radius and area are variables of the double type. You can assign any numerical value to radius and area, and the values of radius and area can be reassigned. For example, in the following code, radius is initially 1.0 (line 2) then changed to 2.0 (line 7), and area is set to 3.14159 (line 3) then reset to 12.56636 (line 8).
28/09/19 3:45 PM
2.5 Variables 41 1 2 3 4 5 6 7 8 9
// Compute the first area radius = 1.0; radius: 1.0 area = radius * radius * 3.14159; area: 3.14159 System.out.println("The area is " + area + " for radius " + radius); // Compute the second area radius = 2.0; radius: 2.0 area = radius * radius * 3.14159; area: 12.56636 System.out.println("The area is " + area + " for radius " + radius);
Variables are for representing data of a certain type. To use a variable, you declare it by telling the compiler its name as well as what type of data it can store. The variable declaration tells the compiler to allocate appropriate memory space for the variable based on its data type. The syntax for declaring a variable is datatype variableName;
Here are some examples of variable declarations: int count; double radius; double interestRate;
declare variable
// Declare count to be an integer variable // Declare radius to be a double variable // Declare interestRate to be a double variable
These examples use the data types int and double. Later you will be introduced to additional data types, such as byte, short, long, float, char, and boolean. If variables are of the same type, they can be declared together, as follows: datatype variable1, variable2, . . . , variablen;
The variables are separated by commas. For example, int i, j, k; // Declare i, j, and k as int variables
Variables often have initial values. You can declare a variable and initialize it in one step. Consider, for instance, the following code:
initialize variables
int count = 1;
This is equivalent to the next two statements: int count; count = 1;
You can also use a shorthand form to declare and initialize variables of the same type together. For example, int i = 1, j = 2;
Tip A variable must be declared before it can be assigned a value. A variable declared in a method must be assigned a value before it can be used. Whenever possible, declare a variable and assign its initial value in one step. This will make the program easy to read and avoid programming errors.
Every variable has a scope. The scope of a variable is the part of the program where the variable can be referenced. The rules that define the scope of a variable will be gradually introduced later in the book. For now, all you need to know is that a variable must be declared and initialized before it can be used.
M02_LIAN9966_12_SE_C02.indd 41
28/09/19 3:45 PM
42 Chapter 2 Elementary Programming Check Point
2.5.1 Identify and fix the errors in the following code: 1 2 3 4 5 6
public class Test { public static void main(String[] args) { int i = k + 2; System.out.println(i); } }
2.6 Assignment Statements and Assignment Expressions Key Point assignment statement assignment operator
An assignment statement assigns a value to a variable. An assignment statement can also be used as an expression in Java. After a variable is declared, you can assign a value to it by using an assignment statement. In Java, the equal sign (=) is used as the assignment operator. The syntax for assignment statements is as follows: variable = expression;
expression
An expression represents a computation involving values, variables, and operators that, taking them together, evaluates to a value. In an assignment statement, the expression on the right-hand side of the assignment operator is evaluated, and then the value is assigned to the variable on the left-hand side of the assignment operator. For example, consider the following code: int y = 1; // Assign 1 to variable y double radius = 1.0; // Assign 1.0 to variable radius int x = 5 * (3 / 2); // Assign the value of the expression to x x = y + 1; // Assign the addition of y and 1 to x double area = radius * radius * 3.14159; // Compute area
You can use a variable in an expression. A variable can also be used in both sides of the = operator. For example, x = x + 1;
In this assignment statement, the result of x + 1 is assigned to x. If x is 1 before the statement is executed, then it becomes 2 after the statement is executed. To assign a value to a variable, you must place the variable name to the left of the assignment operator. Thus, the following statement is wrong: 1 = x; // Wrong
Note In mathematics, x = 2 * x + 1 denotes an equation. However, in Java, x = 2 * x + 1 is an assignment statement that evaluates the expression 2 * x + 1 and assigns the result to x.
assignment expression
In Java, an assignment statement is essentially an expression that evaluates to the value to be assigned to the variable on the left side of the assignment operator. For this reason, an assignment statement is also known as an assignment expression. For example, the following statement is correct: System.out.println(x = 1);
which is equivalent to x = 1; System.out.println(x);
M02_LIAN9966_12_SE_C02.indd 42
28/09/19 3:45 PM
2.7 Named Constants 43 If a value is assigned to multiple variables, you can use chained assignments like this: i = j = k = 1;
which is equivalent to k = 1; j = k; i = j;
Note In an assignment statement, the data type of the variable on the left must be compatible with the data type of the value on the right. For example, int x = 1.0 would be illegal, because the data type of x is int. You cannot assign a double value (1.0) to an int variable without using type casting. Type casting will be introduced in Section 2.15.
2.6.1 Identify and fix the errors in the following code: public class Test { public static void main(String[] args) { int i = j = k = 2; System.out.println(i + " " + j + " " + k); } }
1 2 3 4 5 6
Check Point
2.7 Named Constants A named constant is an identifier that represents a permanent value. The value of a variable may change during the execution of a program, but a named constant, or simply constant, represents permanent data that never changes. A constant is also known as a final variable in Java. In our ComputeArea program, p is a constant. If you use it frequently, you don’t want to keep typing 3.14159; instead, you can declare a constant for p. Here is the syntax for declaring a constant:
Key Point constant
final datatype CONSTANTNAME = value;
A constant must be declared and initialized in the same statement. The word final is a Java keyword for declaring a constant. By convention, all letters in a constant are in uppercase. For example, you can declare p as a constant and rewrite Listing 2.2, as in Listing 2.4.
final keyword
Listing 2.4 ComputeAreaWithConstant.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
import java.util.Scanner; // Scanner is in the java.util package public class ComputeAreaWithConstant { public static void main(String[] args) { final double PI = 3.14159; // Declare a constant // Create a Scanner object Scanner input = new Scanner(System.in); // Prompt the user to enter a radius System.out.print("Enter a number for radius: "); double radius = input.nextDouble(); // Compute area double area = radius * radius * PI; // Display result
M02_LIAN9966_12_SE_C02.indd 43
28/09/19 3:45 PM
44 Chapter 2 Elementary Programming 18 19 20 21 benefits of constants
Check Point
System.out.println("The area for the circle of radius " + radius + " is " + area); } }
There are three benefits of using constants: (1) you don’t have to repeatedly type the same value if it is used multiple times; (2) if you have to change the constant value (e.g., from 3.14 to 3.14159 for PI), you need to change it only in a single location in the source code; and (3) a descriptive name for a constant makes the program easy to read. 2.7.1 What are the benefits of using constants? Declare an int constant SIZE with value 20. 2.7.2 Translate the following algorithm into Java code: Step 1: Declare a double variable named miles with an initial value 100. Step 2: Declare a double constant named KILOMETERS_PER_MILE with value 1.609. Step 3: Declare a double variable named kilometers, multiply miles and KILOMETERS_PER_MILE, and assign the result to kilometers. Step 4: Display kilometers to the console. What is kilometers after Step 4?
2.8 Naming Conventions Sticking with the Java naming conventions makes your programs easy to read and avoids errors.
Key Point name variables and methods
Make sure you choose descriptive names with straightforward meanings for the variables, constants, classes, and methods in your program. As mentioned earlier, names are case sensitive. Listed below are the conventions for naming variables, methods, and classes. ■■
Use lowercase for variables and methods—for example, the variables radius and area, and the method print. If a name consists of several words, concatenate them into one, making the first word lowercase and capitalizing the first letter of each subsequent word—for example, the variable numberOfStudents. This naming style is known as the camelCase because the uppercase characters in the name resemble a camel’s humps.
name classes
■■
Capitalize the first letter of each word in a class name—for example, the class names ComputeArea and System.
name constants
■■
Capitalize every letter in a constant, and use underscores between words—for example, the constants PI and MAX_VALUE.
It is important to follow the naming conventions to make your programs easy to read.
Caution Do not choose class names that are already used in the Java library. For example, since the System class is defined in Java, you should not name your class System. Check Point
M02_LIAN9966_12_SE_C02.indd 44
2.8.1 What are the naming conventions for class names, method names, constants, and
variables? Which of the following items can be a constant, a method, a variable, or a class according to the Java naming conventions? MAX_VALUE, Test, read, readDouble
28/09/19 3:45 PM
2.9 Numeric Data Types and Operations 45
2.9 Numeric Data Types and Operations Java has six numeric types for integers and floating-point numbers with operators +, -, *, /, and %. Every data type has a range of values. The compiler allocates memory space for each variable or constant according to its data type. Java provides eight primitive data types for numeric values, characters, and Boolean values. This section introduces numeric data types and operators. Table 2.1 lists the six numeric data types, their ranges, and their storage sizes.
Key Point
Table 2.1 Numeric Data Types Name
Range
Storage Size
byte
- 27 to 27 - 1 ( - 128 to 127)
8-bit signed
byte type short type
short
- 2 to 2
- 1 ( - 32768 to 32767)
16-bit signed
int
- 231 to 231 - 1 ( - 2147483648 to 2147483647)
32-bit signed
int type
64-bit signed
long type
32-bit IEEE 754
float type
64-bit IEEE 754
double type
long
15
63
15
63
- 2 to 2 - 1 (i.e., - 9223372036854775808 to 9223372036854775807)
float
Negative range: - 3.4028235E + 38 to -1.4E -45 Positive range: 1.4E - 45 to 3.4028235E + 38 6–9 significant digits
double
Negative range: - 1.7976931348623157E +308 to -4.9E -324 Positive range: 4.9E - 324 to 1.7976931348623157E +308 15–17 significant digits
Note IEEE 754 is a standard approved by the Institute of Electrical and Electronics Engineers for representing floating-point numbers on computers. The standard has been widely adopted. Java uses the 32-bit IEEE 754 for the float type and the 64-bit IEEE 754 for the double type. The IEEE 754 standard also defines special floating-point values, which are listed in Appendix E.
Java uses four types for integers: byte, short, int, and long. Choose the type that is most appropriate for your variable. For example, if you know an integer stored in a variable is within a range of a byte, declare the variable as a byte. For simplicity and consistency, we will use int for integers most of the time in this book. Java uses two types for floating-point numbers: float and double. The double type is twice as big as float, so the double is known as double precision, and float as single precision. Normally, you should use the double type, because it is more accurate than the float type.
integer types
floating-point types
2.9.1 Reading Numbers from the Keyboard You know how to use the nextDouble() method in the Scanner class to read a double value from the keyboard. You can also use the methods listed in Table 2.2 to read a number of the byte, short, int, long, and float type.
Table 2.2 Methods for Scanner Objects Method
Description
nextByte()
reads an integer of the byte type. reads an integer of the short type. reads an integer of the int type. reads an integer of the long type. reads a number of the float type. reads a number of the double type.
nextShort() nextInt() nextLong() nextFloat() nextDouble()
M02_LIAN9966_12_SE_C02.indd 45
28/09/19 3:45 PM
46 Chapter 2 Elementary Programming Here are examples for reading values of various types from the keyboard: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Scanner input = new Scanner(System.in); System.out.print("Enter a byte value: "); byte byteValue = input.nextByte(); System.out.print("Enter a short value: "); short shortValue = input.nextShort(); System.out.print("Enter an int value: "); int intValue = input.nextInt(); System.out.print("Enter a long value: "); long longValue = input.nextLong(); System.out.print("Enter a float value: "); float floatValue = input.nextFloat();
If you enter a value with an incorrect range or format, a runtime error would occur. For example, if you enter a value 128 for line 3, an error would occur because 128 is out of range for a byte type integer.
2.9.2 Numeric Operators operators +, –, *, /, and % operands
The operators for numeric data types include the standard arithmetic operators: addition (+), subtraction (–), multiplication (*), division (/), and remainder (%), as listed in Table 2.3. The operands are the values operated by an operator.
Table 2.3 Numeric Operators Name
integer division
Meaning
Result
34 + 1
35
+
Addition
-
Subtraction
34.0 - 0.1
33.9
*
Multiplication
300*30
9000
/
Division
1.0 / 2.0
0.5
%
Remainder
20 % 3
2
When both operands of a division are integers, the result of the division is the quotient and the fractional part is truncated. For example, 5 / 2 yields 2, not 2.5, and –5 / 2 yields –2, not –2.5. To perform a floating-point division, one of the operands must be a floating-point number. For example, 5.0 / 2 yields 2.5. The % operator, known as remainder, yields the remainder after division. The operand on the left is the dividend, and the operand on the right is the divisor. Therefore, 7 % 3 yields 1, 3 % 7 yields 3, 12 % 4 yields 0, 26 % 8 yields 2, and 20 % 13 yields 7.
2 3
7 6 1
M02_LIAN9966_12_SE_C02.indd 46
Example
0 7
3 0 3
3 4
12 12 0
3 8
26 24 2
Divisor
13
1
Quotient
20
Dividend
13 7
Remainder
28/09/19 3:45 PM
2.9 Numeric Data Types and Operations 47 The % operator is often used for positive integers, but it can also be used with negative integers and floating-point values. The remainder is negative only if the dividend is negative. For example, -7 % 3 yields -1, -12 % 4 yields 0, -26 % -8 yields -2, and 20 % -13 yields 7. Remainder is very useful in programming. For example, an even number % 2 is always 0 and a positive odd number % 2 is always 1. Thus, you can use this property to determine whether a number is even or odd. If today is Saturday, it will be Saturday again in 7 days. Suppose you and your friends are going to meet in 10 days. What will be the day in 10 days? You can find that the day is Tuesday using the following expression: Day 6 in a week is Saturday A week has 7 days (6 + 10) % 7 is 2 Day 2 in a week is Tuesday Note: Day 0 is a week is Sunday After 10 days
The program in Listing 2.5 obtains minutes and remaining seconds from an amount of time in seconds. For example, 500 seconds contains 8 minutes and 20 seconds.
Listing 2.5 DisplayTime.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
import java.util.Scanner;
import Scanner
public class DisplayTime { public static void main(String[] args) { Scanner input = new Scanner(System.in); // Prompt the user for input System.out.print("Enter an integer for seconds: "); int seconds = input.nextInt(); int minutes = seconds / 60; // Find minutes in seconds int remainingSeconds = seconds % 60; // Seconds remaining System.out.println(seconds + " seconds is " + minutes + " minutes and " + remainingSeconds + " seconds");
create a Scanner
read an integer divide remainder
} }
Enter an integer for seconds: 500 500 seconds is 8 minutes and 20 seconds
line#
seconds
8
500
10 11
minutes
remainingSeconds
8 20
The nextInt() method (line 8) reads an integer for seconds. Line 10 obtains the minutes using seconds / 60. Line 11 (seconds % 60) obtains the remaining seconds after taking away the minutes.
M02_LIAN9966_12_SE_C02.indd 47
28/09/19 3:45 PM
48 Chapter 2 Elementary Programming The + and - operators can be both unary and binary. A unary operator has only one operand; a binary operator has two. For example, the – operator in –5 is a unary operator to negate number 5, whereas the – operator in 4 – 5 is a binary operator for subtracting 5 from 4.
unary operator binary operator
2.9.3 Exponent Operations Math.pow(a, b) method
The Math.pow(a, b) method can be used to compute ab. The pow method is defined in the Math class in the Java API. You invoke the method using the syntax Math.pow(a, b) (e.g., Math.pow(2, 3)), which returns the result of ab (23). Here, a and b are parameters for the pow method and the numbers 2 and 3 are actual values used to invoke the method. For example, System.out.println(Math.pow(2, 3)); // Displays 8.0 System.out.println(Math.pow(4, 0.5)); // Displays 2.0 System.out.println(Math.pow(2.5, 2)); // Displays 6.25 System.out.println(Math.pow(2.5, –2)); // Displays 0.16
Chapter 6 introduces more details on methods. For now, all you need to know is how to invoke the pow method to perform the exponent operation. Check Point
2.9.1 Find the largest and smallest byte, short, int, long, float, and double. Which 2.9.2
of these data types requires the least amount of memory? Show the result of the following remainders: 56 78 -34 -34 5 1
% % % % % %
6 -4 5 -5 1 5
2.9.3 If today is Tuesday, what will be the day in 100 days? 2.9.4 What is the result of 25 / 4? How would you rewrite the expression if you wished 2.9.5
the result to be a floating-point number? Show the result of the following code: System.out.println(2 System.out.println(2 System.out.println(2 System.out.println(2
* * * *
(5 / 2 + 5 / 2)); 5 / 2 + 2 * 5 / 2); (5 / 2)); 5 / 2);
2.9.6 Are the following statements correct? If so, show the output. System.out.println("25 / 4 is " + 25 / System.out.println("25 / 4.0 is " + 25 System.out.println("3 * 2 / 4 is " + 3 System.out.println("3.0 * 2 / 4 is " +
4); / 4.0); * 2 / 4); 3.0 * 2 / 4);
2.9.7 Write a statement to display the result of 23.5. 2.9.8 Suppose m and r are integers. Write a Java expression for mr2 to obtain a floating-point result.
2.10 Numeric Literals literal
Key Point
A literal is a constant value that appears directly in a program. For example, 34 and 0.305 are literals in the following statements: int numberOfYears = 34; double weight = 0.305;
M02_LIAN9966_12_SE_C02.indd 48
28/09/19 3:45 PM
2.10 Numeric Literals 49
2.10.1 Integer Literals An integer literal can be assigned to an integer variable as long as it can fit into the variable. A compile error will occur if the literal is too large for the variable to hold. The statement byte b = 128, for example, will cause a compile error, because 128 cannot be stored in a variable of the byte type. (Note the range for a byte value is from –128 to 127.) An integer literal is assumed to be of the int type, whose value is between -231 (-2147483648) and 231 -1 (2147483647). To denote an integer literal of the long type, append the letter L or l to it. For example, to write integer 2147483648 in a Java program, you have to write it as 2147483648L or 2147483648l, because 2147483648 exceeds the range for the int value. L is preferred because l (lowercase L) can easily be confused with 1 (the digit one).
Note By default, an integer literal is a decimal integer number. To denote a binary integer literal, use a leading 0b or 0B (zero B); to denote an octal integer literal, use a leading 0 (zero); and to denote a hexadecimal integer literal, use a leading 0x or 0X (zero X). For example,
binary, octal, and hex literals
System.out.println(0B1111); // Displays 15 System.out.println(07777); // Displays 4095 System.out.println(0XFFFF); // Displays 65535
Hexadecimal numbers, binary numbers, and octal numbers will be introduced in Appendix F.
2.10.2 Floating-Point Literals Floating-point literals are written with a decimal point. By default, a floating-point literal is treated as a double type value. For example, 5.0 is considered a double value, not a float value. You can make a number a float by appending the letter f or F, and you can make a number a double by appending the letter d or D. For example, you can use 100.2f or 100.2F for a float number, and 100.2d or 100.2D for a double number.
suffix f or F suffix d or D
Note The double type values are more accurate than the float type values. For example,
double vs. float
System.out.println("1.0 / 3.0 is " + 1.0 / 3.0); displays 1.0 / 3.0 is 0.3333333333333333
16 digits System.out.println("1.0F / 3.0F is " + 1.0F / 3.0F); displays 1.0F / 3.0F is 0.33333334 8 digits
A float value has 6–9 numbers of significant digits, and a double value has 15–17 numbers of significant digits.
Note To improve readability, Java allows you to use underscores to separate two digits in a number literal. For example, the following literals are correct. long value = 232_45_4519; double amount = 23.24_4545_4519_3415;
However, 45_ or _45 is incorrect. The underscore must be placed between two digits.
M02_LIAN9966_12_SE_C02.indd 49
underscores in numbers
28/09/19 3:45 PM
50 Chapter 2 Elementary Programming
2.10.3 Scientific Notation Floating-point literals can be written in scientific notation in the form of a * 10b. For example, the scientific notation for 123.456 is 1.23456 * 102 and for 0.0123456 is 1.23456 * 10-2. A special syntax is used to write scientific notation numbers. For example, 1.23456 * 102 is written as 1.23456E2 or 1.23456E+2 and 1.23456 * 10-2 as 1.23456E-2. E (or e) represents an exponent, and can be in either lowercase or uppercase.
Note why called floating-point?
Check Point
The float and double types are used to represent numbers with a decimal point. Why are they called floating-point numbers? These numbers are stored in scientific notation internally. When a number such as 50.534 is converted into scientific notation, such as 5.0534E+1, its decimal point is moved (i.e., floated) to a new position.
2.10.1 How many accurate digits are stored in a float or double type variable? 2.10.2 Which of the following are correct literals for floating-point numbers? 12.3, 12.3e+2, 23.4e-2, -334.4, 20.5, 39F, 40D
2.10.3 Which of the following are the same as 52.534? 5.2534e+1, 0.52534e+2, 525.34e-1, 5.2534e+0
2.10.4 Which of the following are correct literals? 5_2534e+1, _2534, 5_2, 5_
2.11 JShell JShell is a command line tool for quickly evaluating an expression and executing a statement. Key Point
JShell is a command line interactive tool introduced in Java 9. JShell enables you to type a single Java statement and get it executed to see the result right away without having to write a complete class. This feature is commonly known as REPL (Read-Evaluate-Print Loop), which evaluates expressions and executes statements as they are entered and shows the result immediately. To use JShell, you need to install JDK 9 or higher. Make sure that you set the correct path on the Windows environment if you use Windows. Open a Command Window and type jshell to launch JShell as shown in Figure 2.2.
Figure 2.2 JShell is launched. You can enter a Java statement from the jshell prompt. For example, enter int x = 5, as shown in Figure 2.3.
Figure 2.3 Enter a Java statement at the jshell command prompt
M02_LIAN9966_12_SE_C02.indd 50
28/09/19 3:45 PM
2.11 JShell 51 To print the variable, simply type x. Alternatively, you can type System.out.println(x), as shown in Figure 2.4.
Figure 2.4 Print a variable You can list all the declared variables using the /vars command as shown in Figure 2.5.
Figure 2.5 List all variables You can use the /edit command to edit the code you have entered from the jshell prompt, as shown in Figure 2.6a. This command opens up an edit pane. You can also add/delete the code from the edit pane, as shown in Figure 2.6b. After finishing editing, click the Accept button to make the change in JShell and click the Exit button to exit the edit pane.
(a)
M02_LIAN9966_12_SE_C02.indd 51
28/09/19 3:45 PM
52 Chapter 2 Elementary Programming
(b) Figure 2.6 The /edit command opens up the edit pane In JShell, if you don’t specify a variable for a value, JShell will automatically create a variable for the value. For example, if you type 6.8 from the jshell prompt, you will see variable $7 is automatically created for 6.8, as shown in Figure 2.7.
Figure 2.7 A variable is automatically created for a value. To exit JShell, enter /exit. For more information on JShell, see https://docs.oracle.com/en/java/javase/11/jshell/. Check Point
2.11.1 What does REPL stand for? How do you launch JShell?
2.12 Evaluating Expressions and Operator Precedence Java expressions are evaluated in the same way as arithmetic expressions. Key Point
Writing a numeric expression in Java involves a straightforward translation of an arithmetic expression using Java operators. For example, the arithmetic expression 10(y - 5)(a + b + c) 3 + 4x 4 9 + x b + 9a + x x y 5 can be translated into a Java expression as follows: (3 + 4 * x) / 5 – 10 * (y - 5) * (a + b + c) / x + 9 * (4 / x + (9 + x) / y)
evaluating an expression
M02_LIAN9966_12_SE_C02.indd 52
Although Java has its own way to evaluate an expression behind the scene, the result of a Java expression and its corresponding arithmetic expression is the same. Therefore, you can safely apply the arithmetic rule for evaluating a Java expression. Operators contained within pairs of parentheses are evaluated first. Parentheses can be nested, in which case the expression in the
28/09/19 3:45 PM
2.12 Evaluating Expressions and Operator Precedence 53 inner parentheses is evaluated first. When more than one operator is used in an expression, the following operator precedence rule is used to determine the order of evaluation: ■■
Multiplication, division, and remainder operators are applied first. If an expression contains several multiplication, division, and remainder operators, they are applied from left to right.
■■
Addition and subtraction operators are applied last. If an expression contains several addition and subtraction operators, they are applied from left to right.
operator precedence rule
Here is an example of how an expression is evaluated: 3 + 4 * 4 + 5 * (4 + 3) – 1 (1) inside parentheses first 3 + 4 * 4 + 5 * 7 – 1 (2) multiplication 3 + 16 + 5 * 7 – 1 (3) multiplication 3 + 16 + 35 – 1 (4) addition 19 + 35 – 1 (5) addition 54 – 1 (6) subtraction 53
Listing 2.6 gives a program that converts a Fahrenheit degree to Celsius using the formula Celsius = 1592(Fahrenheit - 32).
Listing 2.6 FahrenheitToCelsius.java import java.util.Scanner;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public class FahrenheitToCelsius { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Enter a degree in Fahrenheit: "); double fahrenheit = input.nextDouble(); // Convert Fahrenheit to Celsius double celsius = (5.0 / 9) * (fahrenheit - 32); System.out.println("Fahrenheit " + fahrenheit + " is " + celsius + " in Celsius");
divide
} }
Enter a degree in Fahrenheit: 100 Fahrenheit 100.0 is 37.77777777777778 in Celsius
line# 8 11
M02_LIAN9966_12_SE_C02.indd 53
fahrenheit
celsius
100 37.77777777777778
28/09/19 3:45 PM
54 Chapter 2 Elementary Programming integer vs. floating-point division
Check Point
Be careful when applying division. Division of two integers yields an integer in Java. 59 is coded 5.0 / 9 instead of 5 / 9 in line 11, because 5 / 9 yields 0 in Java.
2.12.1 How would you write the following arithmetic expressions in Java? a.
3 + d(2 + a) 4 - 9(a + bc) + 3(r + 34) a + bd
b. 5.5 * (r + 2.5)2.5 + t
2.13 Case Study: Displaying the Current Time You can invoke System.currentTimeMillis() to return the current time. Key Point
VideoNote
Use operators / and %
The problem is to develop a program that displays the current time in GMT (Greenwich Mean Time) in the format hour:minute:second, such as 13:19:8. The currentTimeMillis method in the System class returns the current time in milliseconds elapsed since the time midnight, January 1, 1970 GMT, as shown in Figure 2.8. This time is known as the UNIX epoch. The epoch is the point when time starts, and 1970 was the year when the UNIX operating system was formally introduced.
currentTimeMillis UNIX epoch
Elapsed time Time UNIX epoch 01-01-1970 00:00:00 GMT
Current time returned from System.currentTimeMillis()
Figure 2.8 The System.currentTimeMillis() returns the number of milliseconds since the UNIX epoch.
You can use this method to obtain the current time, then compute the current second, minute, and hour as follows: 1. Obtain the total milliseconds since midnight, January 1, 1970, in totalMilliseconds by invoking System.currentTimeMillis() (e.g., 1203183068328 milliseconds). 2. Obtain the total seconds totalSeconds by dividing totalMilliseconds by 1000 (e.g., 1203183068328 milliseconds / 1000 = 1203183068 seconds). 3. Compute the current second from totalSeconds % 60 (e.g., 1203183068 seconds % 60 = 8, which is the current second). 4. Obtain the total minutes totalMinutes by dividing totalSeconds by 60 (e.g., 1203183068 seconds / 60 = 20053051 minutes). 5. Compute the current minute from totalMinutes % 60 (e.g., 20053051 minutes % 60 = 31, which is the current minute). 6. Obtain the total hours totalHours by dividing totalMinutes by 60 (e.g., 20053051 minutes / 60 = 334217 hours). 7. Compute the current hour from totalHours % 24 (e.g., 334217 hours % 24 = 17, which is the current hour). Listing 2.7 gives the complete program.
M02_LIAN9966_12_SE_C02.indd 54
28/09/19 3:45 PM
2.13 Case Study: Displaying the Current Time 55
Listing 2.7 ShowCurrentTime.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
public class ShowCurrentTime { public static void main(String[] args) { // Obtain the total milliseconds since midnight, Jan 1, 1970 long totalMilliseconds = System.currentTimeMillis();
totalMilliseconds
// Obtain the total seconds since midnight, Jan 1, 1970 long totalSeconds = totalMilliseconds / 1000;
totalSeconds
// Compute the current second in the minute in the hour long currentSecond = totalSeconds % 60;
currentSecond
// Obtain the total minutes long totalMinutes = totalSeconds / 60;
totalMinutes
// Compute the current minute in the hour long currentMinute = totalMinutes % 60;
currentMinute
// Obtain the total hours long totalHours = totalMinutes / 60;
totalHours
// Compute the current hour long currentHour = totalHours % 24;
currentHour
// Display results System.out.println("Current time is " + currentHour + ":" + currentMinute + ":" + currentSecond + " GMT");
display output
} }
Current time is 17:31:8 GMT
Line 4 invokes System.currentTimeMillis() to obtain the current time in milliseconds as a long value. Thus, all the variables are declared as the long type in this program. The seconds, minutes, and hours are extracted from the current time using the / and % operators (lines 6–22).
line#
4
7
10
13
16
19
22
variables totalMilliseconds totalSeconds currentSecond totalMinutes currentMinute totalHours currentHour
M02_LIAN9966_12_SE_C02.indd 55
1203183068328 1203183068 8 20053051 31 334217 17
28/09/19 3:45 PM
56 Chapter 2 Elementary Programming
nanoTime Check Point
In the sample run, a single digit 8 is displayed for the second. The desirable output would be 08. This can be fixed by using a method that formats a single digit with a prefix 0 (see Programming Exercise 6.37). The hour displayed in this program is in GMT. Programming Exercise 2.8 enables to display the hour in any time zone. Java also provides the System.nanoTime() method that returns the elapse time in nanoseconds. nanoTime() is more precise and accurate than currentTimeMillis(). 2.13.1 How do you obtain the current second, minute, and hour?
2.14 Augmented Assignment Operators Key Point
The operators +, -, *, /, and % can be combined with the assignment operator to form augmented operators. Very often, the current value of a variable is used, modified, then reassigned back to the same variable. For example, the following statement increases the variable count by 1: count = count + 1;
Java allows you to combine assignment and addition operators using an augmented (or compound) assignment operator. For example, the preceding statement can be written as count += 1; addition assignment operator
The += is called the addition assignment operator. Table 2.4 shows other augmented assignment operators.
Table 2.4 Augmented Assignment Operators Operator
Name
Example
Equivalent
+=
Addition assignment
i += 8
i = i + 8
-=
Subtraction assignment
i -= 8
i = i - 8
*=
Multiplication assignment
i *= 8
i = i * 8
/=
Division assignment
i /= 8
i = i / 8
%=
Remainder assignment
i %= 8
i = i % 8
The augmented assignment operator is performed last after all the other operators in the expression are evaluated. For example, x /= 4 + 5.5 * 1.5;
is same as x = x / (4 + 5.5 * 1.5);
Caution There are no spaces in the augmented assignment operators. For example, + = should be +=.
Note Like the assignment operator (=), the operators (+=, -=, *=, /=, and %=) can be used to form an assignment statement as well as an expression. For example, in the following code, x += 2 is a statement in the first line, and an expression in the second line: x += 2; // Statement System.out.println(x += 2); // Expression
M02_LIAN9966_12_SE_C02.indd 56
28/09/19 3:45 PM
2.15 Increment and Decrement Operators 57 2.14.1 Show the output of the following code:
Check Point
double a = 6.5; a += a + 1; System.out.println(a); a = 6; a /= 2; System.out.println(a);
2.15 Increment and Decrement Operators The increment operator (+ +) and decrement operator (— —) are for incrementing and decrementing a variable by 1. The ++ and — — are two shorthand operators for incrementing and decrementing a variable by 1. These are handy because that’s often how much the value needs to be changed in many programming tasks. For example, the following code increments i by 1 and decrements j by 1.
Key Point increment operator (+ +) decrement operator (— —)
int i = 3, j = 3; i++; // i becomes 4 j— —; // j becomes 2
i++ is pronounced as "i plus plus" and i— — as "i minus minus." These operators are known as postfix increment (or postincrement) and postfix decrement (or postdecrement), because the operators ++ and — — are placed after the variable. These operators can also be placed before the variable. For example,
postincrement postdecrement
int i = 3, j = 3; ++i; // i becomes 4 — —j; // j becomes 2
++i increments i by 1 and — —j decrements j by 1. These operators are known as prefix increment (or preincrement) and prefix decrement (or predecrement). As you see, the effect of i++ and ++i or i— — and — —i are the same in the preceding examples. However, their effects are different when they are used in statements that do more than just increment and decrement. Table 2.5 describes their differences and gives examples.
preincrement predecrement
Table 2.5 Increment and Decrement Operators Operator
Name
Description
Example (assume i = 1)
++var
preincrement
Increment var by 1, and use the new var value in the statement
int j = ++i;
postincrement
var++
predecrement
——var
postdecrement
var——
Increment var by 1, but use the original var value in the statement
// j is 2, i is 2 int j = i++;
// j is 1, i is 2
Decrement var by 1, and use the new var value in the statement
int j = — —i;
Decrement var by 1, and use the original var value in the statement
int j = i— —;
// j is 0, i is 0 // j is 1, i is 0
Here are additional examples to illustrate the differences between the prefix form of ++ (or and the postfix form of ++ (or — —). Consider the following code:
— —)
int i = 10; int newNum = 10 * i++;
Same effect as
int newNum = 10 * i; i = i + 1;
System.out.print("i is " + i + ", newNum is " + newNum); Output is i is 11, newNum is 100
M02_LIAN9966_12_SE_C02.indd 57
28/09/19 3:45 PM
58 Chapter 2 Elementary Programming In this case, i is incremented by 1, then the old value of i is used in the multiplication. Thus, newNum becomes 100. If i++ is replaced by ++i, then it becomes as follows: int i = 10; int newNum = 10 * (++i);
Same effect as
i = i + 1; int newNum = 10 * i;
System.out.print("i is " + i + ", newNum is " + newNum); Output is i is 11, newNum is 110
i is incremented by 1, and the new value of i is used in the multiplication. Thus, newNum becomes 110. Here is another example: double x = 1.0; double y = 5.0; double z = x–– + (++y);
After all three lines are executed, y becomes 6.0, z becomes 7.0, and x becomes 0.0. Operands are evaluated from left to right in Java. The left-hand operand of a binary operator is evaluated before any part of the right-hand operand is evaluated. This rule takes precedence over any other rules that govern expressions. Here is an example: int i = 1; int k = ++i + i * 3;
++i is evaluated and returns 2. When evaluating i * 3, i is now 2. Therefore, k becomes 8.
Tip Using increment and decrement operators makes expressions short, but it also makes them complex and difficult to read. Avoid using these operators in expressions that modify multiple variables or the same variable multiple times, such as this one: int k = ++i + i * 3. Check Point
2.15.1 Which of these statements are true? a. Any expression can be used as a statement. b. The expression x++ can be used as a statement. c. The statement x = x + 5 is also an expression. d. The statement x = y = x = 0 is illegal.
2.15.2 Show the output of the following code: int a = 6; int b = a++; System.out.println(a); System.out.println(b); a = 6; b = ++a; System.out.println(a); System.out.println(b);
2.16 Numeric Type Conversions Floating-point numbers can be converted into integers using explicit casting. Key Point
M02_LIAN9966_12_SE_C02.indd 58
Can you perform binary operations with two operands of different types? Yes. If an integer and a floating-point number are involved in a binary operation, Java automatically converts the integer to a floating-point value. Therefore, 3 * 4.5 is the same as 3.0 * 4.5.
28/09/19 3:45 PM
2.16 Numeric Type Conversions 59 You can always assign a value to a numeric variable whose type supports a larger range of values; thus, for instance, you can assign a long value to a float variable. You cannot, however, assign a value to a variable of a type with a smaller range unless you use type casting. Casting is an operation that converts a value of one data type into a value of another data type. Casting a type with a small range to a type with a larger range is known as widening a type. Casting a type with a large range to a type with a smaller range is known as narrowing a type. Java will automatically widen a type, but you must narrow a type explicitly. The syntax for casting a type is to specify the target type in parentheses, followed by the variable’s name or the value to be cast. For example, the following statement
casting widening a type narrowing a type
System.out.println((int)1.7);
displays 1. When a double value is cast into an int value, the fractional part is truncated. The following statement System.out.println((double)1 / 2);
displays 0.5, because 1 is cast to 1.0 first, then 1.0 is divided by 2. However, the statement System.out.println(1 / 2);
displays 0, because 1 and 2 are both integers and the resulting value should also be an integer.
Caution Casting is necessary if you are assigning a value to a variable of a smaller type range, such as assigning a double value to an int variable. A compile error will occur if casting is not used in situations of this kind. However, be careful when using casting, as loss of information might lead to inaccurate results.
possible loss of precision
Note Casting does not change the variable being cast. For example, d is not changed after casting in the following code: double d = 4.5; int i = (int)d; // i becomes 4, but d is still 4.5
Note In Java, an augmented expression of the form x1 op= x2 is implemented as x1 = (T)(x1 op x2), where T is the type for x1. Therefore, the following code is correct:
casting in an augmented expression
int sum = 0; sum += 4.5; // sum becomes 4 after this statement sum += 4.5 is equivalent to sum = (int)(sum + 4.5).
Note To assign a variable of the int type to a variable of the short or byte type, explicit casting must be used. For example, the following statements have a compile error: int i = 1; byte b = i; // Error because explicit casting is required
However, so long as the integer literal is within the permissible range of the target variable, explicit casting is not needed to assign an integer literal to a variable of the short or byte type (see Section 2.10, Numeric Literals).
The program in Listing 2.8 displays the sales tax with two digits after the decimal point.
M02_LIAN9966_12_SE_C02.indd 59
28/09/19 3:45 PM
60 Chapter 2 Elementary Programming
Listing 2.8 SalesTax.java import java.util.Scanner;
1 2 3 4 5 6 7 8 9 10 11 12 13
casting
public class SalesTax { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Enter purchase amount: "); double purchaseAmount = input.nextDouble(); double tax = purchaseAmount * 0.06; System.out.println("Sales tax is $" + (int)(tax * 100) / 100.0); } }
Enter purchase amount: 197.55 Sales tax is $11.85
line#
purchaseAmount
8
197.55
10
tax
Output
11.853
11
11.85
Using the input in the sample run, the variable purchaseAmount is 197.55 (line 8). The sales tax is 6% of the purchase, so the tax is evaluated as 11.853 (line 10). Note
formatting numbers
is 1185.3 (int)(tax * 100) is 1185 tax * 100
(int)(tax * 100) / 100.0
is 11.85
Thus, the statement in line 11 displays the tax 11.85 with two digits after the decimal point. Note the expression (int)(tax * 100) / 100.0 rounds down tax to two decimal places. If tax is 3.456, (int)(tax * 100) / 100.0 would be 3.45. Can it be rounded up to two decimal places? Note any double value x can be rounded up to an integer using (int)(x + 0.5). Thus, tax can be rounded up to two decimal places using (int)(tax * 100 + 0.5) / 100.0. Check Point
2.16.1 Can different types of numeric values be used together in a computation? 2.16.2 What does an explicit casting from a double to an int do with the fractional part of the double value? Does casting change the variable being cast?
2.16.3 Show the following output: float f = 12.5F; int i = (int)f; System.out.println("f is " + f); System.out.println("i is " + i);
2.16.4 If you change (int)(tax
* 100) / 100.0 to (int)(tax * 100) / 100 in line 11 in Listing 2.8, what will be the output for the input purchase amount of 197.556?
2.16.5 Show the output of the following code: double amount = 5; System.out.println(amount / 2); System.out.println(5 / 2);
2.16.6 Write an expression that rounds up a double value in variable d to an integer.
M02_LIAN9966_12_SE_C02.indd 60
28/09/19 3:45 PM
2.17 Software Development Process 61
2.17 Software Development Process The software development life cycle is a multistage process that includes requirements specification, analysis, design, implementation, testing, deployment, and maintenance. Developing a software product is an engineering process. Software products, no matter how large or how small, have the same life cycle: requirements specification, analysis, design, implementation, testing, deployment, and maintenance, as shown in Figure 2.9. Requirements Specification
Key Point
VideoNote
Software development process
Input, Process, Output IPO
System Analysis System Design
Implementation
Testing
Deployment
Maintenance
Figure 2.9 At any stage of the software development life cycle, it may be necessary to go back to a previous stage to correct errors or deal with other issues that might prevent the software from functioning as expected. Requirements specification is a formal process that seeks to understand the problem the software will address, and to document in detail what the software system needs to do. This phase involves close interaction between users and developers. Most of the examples in this book are simple, and their requirements are clearly stated. In the real world, however, problems are not always well defined. Developers need to work closely with their customers (the individuals or organizations that will use the software) and study the problem carefully to identify what the software needs to do. System analysis seeks to analyze the data flow and to identify the system’s input and output. When you perform analysis, it helps to identify what the output is first, then figure out what input data you need in order to produce the output. System design is to design a process for obtaining the output from the input. This phase involves the use of many levels of abstraction to break down the problem into manageable components and design strategies for implementing each component. You can view each component as a subsystem that performs a specific function of the system. The essence of system analysis and design is input, process, and output (IPO). Implementation involves translating the system design into programs. Separate programs are written for each component then integrated to work together. This phase requires the use of a programming language such as Java. The implementation involves coding, self-testing, and debugging (that is, finding errors, called bugs, in the code). Testing ensures the code meets the requirements specification and weeds out bugs. An independent team of software engineers not involved in the design and implementation of the product usually conducts such testing.
M02_LIAN9966_12_SE_C02.indd 61
requirements specification
system analysis
system design
IOP implementation
testing
28/09/19 3:45 PM
62 Chapter 2 Elementary Programming deployment
maintenance
VideoNote
Compute loan payments
Deployment makes the software available for use. Depending on the type of software, it may be installed on each user’s machine, or installed on a server accessible on the Internet. Maintenance is concerned with updating and improving the product. A software product must continue to perform and improve in an ever-evolving environment. This requires periodic upgrades of the product to fix newly discovered bugs and incorporate changes. To see the software development process in action, we will now create a program that computes loan payments. The loan can be a car loan, a student loan, or a home mortgage loan. For an introductory programming course, we focus on requirements specification, analysis, design, implementation, and testing. Stage 1: Requirements Specification The program must satisfy the following requirements: ■■
It must let the user enter the interest rate, the loan amount, and the number of years for which payments will be made.
■■
It must compute and display the monthly payment and total payment amounts.
Stage 2: System Analysis The output is the monthly payment and total payment, which can be obtained using the following formulas: monthlyPayment =
loanAmount * monthlyInterestRate 1 1 (1 + monthlyInterestRate)numberOf Years * 12
totalPayment = monthlyPayment * numberOf Years * 12 Therefore, the input needed for the program is the monthly interest rate, the length of the loan in years, and the loan amount.
Note The requirements specification says the user must enter the annual interest rate, the loan amount, and the number of years for which payments will be made. During analysis, however, it is possible you may discover that input is not sufficient or some values are unnecessary for the output. If this happens, you can go back and modify the requirements specification.
Note In the real world, you will work with customers from all walks of life. You may develop software for chemists, physicists, engineers, economists, and psychologists, and of course you will not have (or need) complete knowledge of all these fields. Therefore, you don’t have to know how formulas are derived, but given the monthly interest rate, the number of years, and the loan amount, you can compute the monthly payment in this program. You will, however, need to communicate with customers and understand how a mathematical model works for the system.
Stage 3: System Design During system design, you identify the steps in the program. Step 3.1. Prompt the user to enter the annual interest rate, the number of years, and the loan amount. (The interest rate is commonly expressed as a percentage of the principal for a period of one year. This is known as the annual interest rate.)
M02_LIAN9966_12_SE_C02.indd 62
28/09/19 3:45 PM
2.17 Software Development Process 63 Step 3.2. The input for the annual interest rate is a number in percent format, such as 4.5%. The program needs to convert it into a decimal by dividing it by 100. To obtain the monthly interest rate from the annual interest rate, divide it by 12, since a year has 12 months. Thus, to obtain the monthly interest rate in decimal format, you need to divide the annual interest rate in percentage by 1200. For example, if the annual interest rate is 4.5%, then the monthly interest rate is 4.5/1200 = 0.00375. Step 3.3. Compute the monthly payment using the preceding formula. Step 3.4. Compute the total payment, which is the monthly payment multiplied by 12 and multiplied by the number of years. Step 3.5. Display the monthly payment and total payment. Stage 4: Implementation Implementation is also known as coding (writing the code). In the formula, you have to compute (1 + monthlyInterestRate)numberOf Years * 12, which can be obtained using Math. pow(1 + monthlyInterestRate, numberOfYears * 12). Listing 2.9 gives the complete program.
Math.pow(a, b) method
Listing 2.9 ComputeLoan.java 1 import java.util.Scanner; 2 3 public class ComputeLoan { 4 public static void main(String[] args) { 5 // Create a Scanner 6 Scanner input = new Scanner(System.in); 7 8 // Enter annual interest rate in percentage, e.g., 7.25 9 System.out.print("Enter annual interest rate, e.g., 7.25: "); 10 double annualInterestRate = input.nextDouble(); 11 12 // Obtain monthly interest rate 13 double monthlyInterestRate = annualInterestRate / 1200; 14 15 // Enter number of years 16 System.out.print( 17 "Enter number of years as an integer, e.g., 5: "); 18 int numberOfYears = input.nextInt(); 19 20 // Enter loan amount 21 System.out.print("Enter loan amount, e.g., 120000.95: "); 22 double loanAmount = input.nextDouble(); 23 24 // Calculate payment 25 double monthlyPayment = loanAmount * monthlyInterestRate / (1 26 - 1 / Math.pow(1 + monthlyInterestRate, numberOfYears * 12)); 27 double totalPayment = monthlyPayment * numberOfYears * 12; 28 29 // Display results 30 System.out.println("The monthly payment is $" + 31 (int)(monthlyPayment * 100) / 100.0); 32 System.out.println("The total payment is $" + 33 (int)(totalPayment * 100) / 100.0); 34 } 35 }
M02_LIAN9966_12_SE_C02.indd 63
import class
create a Scanner
enter interest rate
enter years
enter loan amount
monthlyPayment totalPayment
casting casting
28/09/19 3:45 PM
64 Chapter 2 Elementary Programming Enter annual interest rate, for example, 7.25: 5.75 Enter number of years as an integer, for example, 5: 15 Enter loan amount, for example, 120000.95: 250000 The monthly payment is $2076.02 The total payment is $373684.53
line#
10
13
18
22
25
27
variables annualInterestRate
5.75
monthlyInterestRate
0.0047916666666
numberOfYears
15
loanAmount
250000
monthlyPayment
2076.0252175
totalPayment
373684.539
Line 10 reads the annual interest rate, which is converted into the monthly interest rate in line 13. Choose the most appropriate data type for the variable. For example, numberOfYears is best declared as an int (line 18), although it could be declared as a long, float, or double. Note byte might be the most appropriate for numberOfYears. For simplicity, however, the examples in this booktext will use int for integer and double for floating-point values. The formula for computing the monthly payment is translated into Java code in lines 25–27. Casting is used in lines 31 and 33 to obtain a new monthlyPayment and totalPayment with two digits after the decimal points. The program uses the Scanner class, imported in line 1. The program also uses the Math class, and you might be wondering why that class isn’t imported into the program. The Math class is in the java.lang package, and all classes in the java.lang package are implicitly imported. Therefore, you don’t need to explicitly import the Math class.
java.lang package
Stage 5: Testing After the program is implemented, test it with some sample input data and verify whether the output is correct. Some of the problems may involve many cases, as you will see in later chapters. For these types of problems, you need to design test data that cover all cases.
Tip incremental coding and testing
Check Point
The system design phase in this example identified several steps. It is a good approach to code and test these steps incrementally by adding them one at a time. This approach, called incremental coding and testing, makes it much easier to pinpoint problems and debug the program.
2.17.1 How would you write the following arithmetic expression? -b + 2b2 - 4ac 2a
2.18 Case Study: Counting Monetary Units This section presents a program that breaks a large amount of money into smaller units. Key Point
M02_LIAN9966_12_SE_C02.indd 64
Suppose you want to develop a program that changes a given amount of money into smaller monetary units. The program lets the user enter an amount as a double value representing a
28/09/19 3:45 PM
2.18 Case Study: Counting Monetary Units 65 total in dollars and cents, and outputs a report listing the monetary equivalent in the maximum number of dollars, quarters, dimes, nickels, and pennies, in this order, to result in the minimum number of coins. Here are the steps in developing the program: 1. Prompt the user to enter the amount as a decimal number, such as 11.56. 2. Convert the amount (e.g., 11.56) into cents (1156). 3. Divide the cents by 100 to find the number of dollars. Obtain the remaining cents using the cents remainder 100. 4. Divide the remaining cents by 25 to find the number of quarters. Obtain the remaining cents using the remaining cents remainder 25. 5. Divide the remaining cents by 10 to find the number of dimes. Obtain the remaining cents using the remaining cents remainder 10. 6. Divide the remaining cents by 5 to find the number of nickels. Obtain the remaining cents using the remaining cents remainder 5. 7. The remaining cents are the pennies. 8. Display the result. The complete program is given in Listing 2.10.
Listing 2.10 ComputeChange.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
import java.util.Scanner;
import class
public class ComputeChange { public static void main(String[] args) { // Create a Scanner Scanner input = new Scanner(System.in); // Receive the amount System.out.print( "Enter an amount in double, for example 11.56: "); double amount = input.nextDouble();
enter input
int remainingAmount = (int)(amount * 100); // Find the number of one dollars int numberOfOneDollars = remainingAmount / 100; remainingAmount = remainingAmount % 100;
dollars
// Find the number of quarters in the remaining amount int numberOfQuarters = remainingAmount / 25; remainingAmount = remainingAmount % 25;
quarters
// Find the number of dimes in the remaining amount int numberOfDimes = remainingAmount / 10; remainingAmount = remainingAmount % 10;
dimes
// Find the number of nickels in the remaining amount int numberOfNickels = remainingAmount / 5; remainingAmount = remainingAmount % 5;
nickels
// Find the number of pennies in the remaining amount int numberOfPennies = remainingAmount;
pennies
M02_LIAN9966_12_SE_C02.indd 65
28/09/19 3:45 PM
66 Chapter 2 Elementary Programming 34 35 36 37 38 39 40 41 42
output
// Display results System.out.println("Your System.out.println(" " + System.out.println(" " + System.out.println(" " + System.out.println(" " + System.out.println(" " +
amount " + amount + " consists of"); numberOfOneDollars + " dollars"); numberOfQuarters + " quarters "); numberOfDimes + " dimes"); numberOfNickels + " nickels"); numberOfPennies + " pennies");
} }
Enter an amount in double, for example, 11.56: 11.56 Your amount 11.56 consists of 11 dollars 2 quarters 0 dimes 1 nickels 1 pennies
line#
11
13
16
17
20
21
24
25
28
29
32
variables amount
11.56
remainingAmount numberOfOneDollars
1156
56
6
6
1
11
numberOfQuarters numberOfDimes numberOfNickels numberOfPennies
2 0 1 1
The variable amount stores the amount entered from the console (line 11). This variable is not changed, because the amount has to be used at the end of the program to display the results. The program introduces the variable remainingAmount (line 13) to store the changing remaining amount. The variable amount is a double decimal representing dollars and cents. It is converted to an int variable remainingAmount, which represents all the cents. For instance, if amount is 11.56, then the initial remainingAmount is 1156. The division operator yields the integer part of the division, so 1156 / 100 is 11. The remainder operator obtains the remainder of the division, so 1156 % 100 is 56. The program extracts the maximum number of singles from the remaining amount and obtains a new remaining amount in the variable remainingAmount (lines 16–17). It then extracts the maximum number of quarters from remainingAmount and obtains a new remainingAmount (lines 20–21). Continuing the same process, the program finds the maximum number of dimes, nickels, and pennies in the remaining amount. One serious problem with this example is the possible loss of precision when casting a double amount to an int remainingAmount. This could lead to an inaccurate result. If you try to enter the amount 10.03, 10.03 * 100 becomes 1002.9999999999999. You will find that the program displays 10 dollars and 2 pennies. To fix the problem, enter the amount as an integer value representing cents (see Programming Exercise 2.22).
loss of precision
Check Point
M02_LIAN9966_12_SE_C02.indd 66
2.18.1 Show the output of Listing 2.10 with the input value 1.99. Why does the program produce an incorrect result for the input 10.03?
28/09/19 3:45 PM
2.19 Common Errors and Pitfalls 67
2.19 Common Errors and Pitfalls Common elementary programming errors often involve undeclared variables, uninitialized variables, integer overflow, unintended integer division, and round-off errors.
Key Point
Common Error 1: Undeclared/Uninitialized Variables and Unused Variables A variable must be declared with a type and assigned a value before using it. A common error is not declaring a variable or initializing a variable. Consider the following code: double interestRate = 0.05; double interest = interestrate * 45;
This code is wrong, because interestRate is assigned a value 0.05; but interestrate has not been declared and initialized. Java is case sensitive, so it considers interestRate and interestrate to be two different variables. If a variable is declared, but not used in the program, it might be a potential programming error. Therefore, you should remove the unused variable from your program. For example, in the following code, taxRate is never used. It should be removed from the code. double interestRate = 0.05; double taxRate = 0.05; double interest = interestRate * 45; System.out.println("Interest is " + interest);
If you use an IDE such as Eclipse and NetBeans, you will receive a warning on unused variables. Common Error 2: Integer Overflow Numbers are stored with a limited numbers of digits. When a variable is assigned a value that is too large (in size) to be stored, it causes overflow. For example, executing the following statement causes overflow, because the largest value that can be stored in a variable of the int type is 2147483647. 2147483648 will be too large for an int value:
what is overflow?
int value = 2147483647 + 1; // value will actually be -2147483648
Likewise, executing the following statement also causes overflow, because the smallest value that can be stored in a variable of the int type is -2147483648. -2147483649 is too large in size to be stored in an int variable. int value = –2147483648 – 1; // value will actually be 2147483647
Java does not report warnings or errors on overflow, so be careful when working with integers close to the maximum or minimum range of a given type. When a floating-point number is too small (i.e., too close to zero) to be stored, it causes underflow. Java approximates it to zero, so normally you don’t need to be concerned about underflow. Common Error 3: Round-off Errors A round-off error, also called a rounding error, is the difference between the calculated approximation of a number and its exact mathematical value. For example, 1/3 is approximately 0.333 if you keep three decimal places, and is 0.3333333 if you keep seven decimal places. Since the number of digits that can be stored in a variable is limited, round-off errors are inevitable. Calculations involving floating-point numbers are approximated because these numbers are not stored with complete accuracy. For example,
M02_LIAN9966_12_SE_C02.indd 67
what is underflow?
floating-point approximation
28/09/19 3:45 PM
68 Chapter 2 Elementary Programming System.out.println(1.0 - 0.1 - 0.1 - 0.1 - 0.1 - 0.1);
displays 0.5000000000000001, not 0.5, and System.out.println(1.0 - 0.9);
displays 0.09999999999999998, not 0.1. Integers are stored precisely. Therefore, calculations with integers yield a precise integer result. Common Error 4: Unintended Integer Division Java uses the same divide operator, namely /, to perform both integer and floating-point division. When two operands are integers, the / operator performs an integer division. The result of the operation is an integer. The fractional part is truncated. To force two integers to perform a floating-point division, make one of the integers into a floating-point number. For example, the code in (a) displays that average as 1 and the code in (b) displays that average as 1.5. int number1 = 1; int number2 = 2; double average = (number1 + number2) / 2;
int number1 = 1; int number2 = 2; double average = (number1 + number2) / 2.0;
System.out.println(average);
System.out.println(average);
(a)
(b)
Common Pitfall 1: Redundant Input Objects New programmers often write the code to create multiple input objects for each input. For example, the following code in (a) reads an integer and a double value: Scanner input = new Scanner(System.in); System.out.print("Enter an integer: "); int v1 = input.nextInt(); Scanner input1 = new Scanner(System.in); BAD CODE System.out.print("Enter a double value: "); double v2 = input1.nextDouble();
The code is not good. It creates two input objects unnecessarily and may lead to some subtle errors. You should rewrite the code in (b): Scanner input = new Scanner(System.in); GOOD CODE System.out.print("Enter an integer: "); int v1 = input.nextInt(); System.out.print("Enter a double value: "); double v2 = input.nextDouble(); Check Point
2.19.1 2.19.2 2.19.3 2.19.4
Can you declare a variable as int and later redeclare it as double? What is an integer overflow? Can floating-point operations cause overflow? Will overflow cause a runtime error? hat is a round-off error? Can integer operations cause round-off errors? Can W floating-point operations cause round-off errors?
Key Terms algorithm, 34 assignment operator (=), 42 assignment statement, 42 byte type, 45
M02_LIAN9966_12_SE_C02.indd 68
casting, 59 constant, 43 data type, 35 declare variables, 35
28/09/19 3:45 PM
Chapter Summary 69 decrement operator (– –), 57 double type, 45 expression, 42 final keyword, 43 float type, 45 floating-point number, 35 identifier, 40 increment operator (++), 57 incremental coding and testing, 64 int type, 45 IPO, 39 literal, 48 long type, 45 narrowing a type, 59 operand, 46 operator, 46 overflow, 67
postdecrement, 57 postincrement, 57 predecrement, 57 preincrement, 57 primitive data type, 35 pseudocode, 34 requirements specification, 61 scope of a variable, 41 short type, 45 specific import, 38 system analysis, 61 system design, 61 underflow, 67 UNIX epoch, 54 variable, 35 widening a type, 59 wildcard import, 38
Chapter Summary 1. Identifiers are names for naming elements such as variables, constants, methods, classes, and packages in a program.
2. An identifier is a sequence of characters that consists of letters, digits, underscores (_),
and dollar signs ($). An identifier must start with a letter or an underscore. It cannot start with a digit. An identifier cannot be a reserved word. An identifier can be of any length.
3. Variables are used to store data in a program. To declare a variable is to tell the compiler what type of data a variable can hold.
4. There are two types of import statements: specific import and wildcard import. The specific import specifies a single class in the import statement. The wildcard import imports all the classes in a package.
5. In Java, the equal sign (=) is used as the assignment operator. 6. A variable declared in a method must be assigned a value before it can be used. 7. A named constant (or simply a constant) represents permanent data that never changes. 8. A named constant is declared by using the keyword final. 9. Java provides four integer types (byte, short, int, and long) that represent integers of four different sizes.
10. Java provides two floating-point types (float and double) that represent floating-point numbers of two different precisions.
11. Java provides operators that perform numeric operations: + (addition), – (subtraction), * (multiplication), / (division), and % (remainder).
12. Integer arithmetic (/) yields an integer result. 13. The numeric operators in a Java expression are applied the same way as in an arithmetic expression.
M02_LIAN9966_12_SE_C02.indd 69
28/09/19 3:45 PM
70 Chapter 2 Elementary Programming 14. Java provides the augmented assignment operators += (addition assignment), –= (sub-
traction assignment), *= (multiplication assignment), /= (division assignment), and %= (remainder assignment).
15. The increment operator (++) and the decrement operator (––) increment or decrement a variable by 1.
16. When evaluating an expression with values of mixed types, Java automatically converts the operands to appropriate types.
17. You can explicitly convert a value from one type to another using the (type)value notation.
18. Casting a variable of a type with a small range to a type with a larger range is known as widening a type.
19. Casting a variable of a type with a large range to a type with a smaller range is known as narrowing a type.
20. Widening a type can be performed automatically without explicit casting. Narrowing a type must be performed explicitly.
21. In computer science, midnight of January 1, 1970, is known as the UNIX epoch.
Quiz Answer the quiz for this chapter online at the Companion Website.
Programming Exercises Debugging Tip The compiler usually gives a reason for a syntax error. If you don’t know how to correct it, compare your program closely, character by character, with similar examples in the text.
learn from examples
Pedagogical Note Instructors may ask you to document your analysis and design for selected exercises. Use your own words to analyze the problem, including the input, output, and what needs to be computed, and describe how to solve the problem in pseudocode.
document analysis and design
Pedagogical Note The solution to most even-numbered programming exercises are provided to students. These exercises serve as additional examples for a variety of programs. To maximize the benefits of these solutions, students should first attempt to complete the even-numbered exercises and then compare their solutions with the solutions provided in the book. Since the book provides a large number of programming exercises, it is sufficient if you can complete all even-numbered programming exercises.
even-numbered programming exercises
Sections 2.2–2.13
2.1 (Convert Celsius to Fahrenheit) Write a program that reads a Celsius degree in a double value from the console, then converts it to Fahrenheit, and displays the result. The formula for the conversion is as follows:
fahrenheit = (9 / 5) * celsius + 32
Hint: In Java, 9 / 5 is 1, but 9.0 / 5 is 1.8. Here is a sample run:
M02_LIAN9966_12_SE_C02.indd 70
28/09/19 3:45 PM
Programming Exercises 71 Enter a degree in Celsius: 43.5 43.5 Celsius is 110.3 Fahrenheit
2.2 (Compute the volume of a cylinder) Write a program that reads in the radius and length of a cylinder and computes the area and volume using the following formulas: area = radius * radius * π volume = area * length
Here is a sample run: Enter the radius and length of a cylinder: 5.5 12 The area is 95.0331 The volume is 1140.4
2.3 (Convert feet into meters) Write a program that reads a number in feet, converts it to meters, and displays the result. One foot is 0.305 meter. Here is a sample run: Enter a value for feet: 16.5 16.5 feet is 5.0325 meters
2.4 (Convert pounds into kilograms) Write a program that converts pounds into ki-
lograms. The program prompts the user to enter a number in pounds, converts it to kilograms, and displays the result. One pound is 0.454 kilogram. Here is a sample run: Enter a number in pounds: 55.5 55.5 pounds is 25.197 kilograms
*2.5 (Financial application: calculate tips) Write a program that reads the subtotal
and the gratuity rate, then computes the gratuity and total. For example, if the user enters 10 for subtotal and 15% for gratuity rate, the program displays $1.5 as gratuity and $11.5 as total. Here is a sample run: Enter the subtotal and a gratuity rate: 10 15 The gratuity is $1.5 and total is $11.5
**2.6 (Sum the digits in an integer) Write a program that reads an integer between 0 and 1000 and adds all the digits in the integer. For example, if an integer is 932, the sum of all its digits is 14. Hint: Use the % operator to extract digits, and use the / operator to remove the extracted digit. For instance, 932 % 10 = 2 and 932 / 10 = 93. Here is a sample run: Enter a number between 0 and 1000: 999 The sum of the digits is 27
M02_LIAN9966_12_SE_C02.indd 71
28/09/19 3:45 PM
72 Chapter 2 Elementary Programming *2.7 (Find the number of years) Write a program that prompts the user to enter the
minutes (e.g., 1 billion), and displays the maximum number of years and remaining days for the minutes. For simplicity, assume that a year has 365 days. Here is a sample run: Enter the number of minutes: 1000000000 1000000000 minutes is approximately 1902 years and 214 days
*2.8 (Current time) Listing 2.7, ShowCurrentTime.java, gives a program that displays the current time in GMT. Revise the program so it prompts the user to enter the time zone offset to GMT and displays the time in the specified time zone. Here is a sample run: Enter the time zone offset to GMT: -5 The current time is 4:50:34
2.9 (Physics: acceleration) Average acceleration is defined as the change of velocity
divided by the time taken to make the change, as given by the following formula:
v1 - v0 t Write a program that prompts the user to enter the starting velocity v0 in meters/ second, the ending velocity v1 in meters/second, and the time span t in seconds, then displays the average acceleration. Here is a sample run: a =
Enter v0, v1, and t: 5.5 50.9 4.5 The average acceleration is 10.0889
2.10 (Science: calculating energy) Write a program that calculates the energy needed
to heat water from an initial temperature to a final temperature. Your program should prompt the user to enter the amount of water in kilograms and the initial and final temperatures of the water. The formula to compute the energy is Q = M * (finalTemperature – initialTemperature) * 4184
where M is the weight of water in kilograms, initial and final temperatures are in degrees Celsius, and energy Q is measured in joules. Here is a sample run: Enter the amount of water in kilograms: 55.5 Enter the initial temperature: 3.5 Enter the final temperature: 10.5 The energy needed is 1625484.0
2.11 (Population projection) Rewrite Programming Exercise 1.11 to prompt the user
to enter the number of years and display the population after the number of years. Use the hint in Programming Exercise 1.11 for this program. Here is a sample run of the program: Enter the number of years: 5 The population in 5 years is 325932969
M02_LIAN9966_12_SE_C02.indd 72
28/09/19 3:45 PM
Programming Exercises 73 2.12 (Physics: finding runway length) Given an airplane’s acceleration a and take-off speed v, you can compute the minimum runway length needed for an airplane to take off using the following formula: v2 2a Write a program that prompts the user to enter v in meters/second (m/s) and the acceleration a in meters/second squared (m/s2), then, displays the minimum runway length. length =
Enter speed and acceleration: 60 3.5 The minimum runway length for this airplane is 514.286
**2.13 (Financial application: compound value) Suppose you save $100 each month into
a savings account with an annual interest rate of 5%. Thus, the monthly interest rate is 0.05/12 = 0.00417. After the first month, the value in the account becomes 100 * (1 + 0.00417) = 100.417
After the second month, the value in the account becomes (100 + 100.417) * (1 + 0.00417) = 201.252
After the third month, the value in the account becomes (100 + 201.252) * (1 + 0.00417) = 302.507
and so on. Write a program that prompts the user to enter a monthly saving amount and displays the account value after the sixth month. (In Programming Exercise 5.30, you will use a loop to simplify the code and display the account value for any month.) Enter the monthly saving amount: 100 After the sixth month, the account value is $608.81
*2.14 (Health application: computing BMI) Body Mass Index (BMI) is a measure of
health on weight. It can be calculated by taking your weight in kilograms and dividing, by the square of your height in meters. Write a program that prompts the user to enter a weight in pounds and height in inches and displays the BMI. Note one pound is 0.45359237 kilograms and one inch is 0.0254 meters. Here is a sample run:
VideoNote
Compute BMI
Enter weight in pounds: 95.5 Enter height in inches: 50 BMI is 26.8573
2.15 (Geometry: distance of two points) Write a program that prompts the user to
enter two points (x1, y1) and (x2, y2) and displays their distance. The formula for computing the distance is 2(x2 - x1)2 + (y2 - y1)2. Note you can use Math.pow(a, 0.5) to compute 2a. Here is a sample run: Enter x1 and y1: 1.5 -3.4 Enter x2 and y2: 4 5 The distance between the two points is 8.764131445842194
M02_LIAN9966_12_SE_C02.indd 73
28/09/19 3:45 PM
74 Chapter 2 Elementary Programming 2.16 (Geometry: area of a hexagon) Write a program that prompts the user to enter the side of a hexagon and displays its area. The formula for computing the area of a hexagon is 323 2 Area = s, 2 where s is the length of a side. Here is a sample run: Enter the length of the side: 5.5 The area of the hexagon is 78.5918
*2.17 (Science: wind-chill temperature) How cold is it outside? The temperature alone is
not enough to provide the answer. Other factors including wind speed, relative humidity, and sunshine play important roles in determining coldness outside. In 2001, the National Weather Service (NWS) implemented the new wind-chill temperature to measure the coldness using temperature and wind speed. The formula is twc = 35.74 + 0.6215ta - 35.75v 0.16 + 0.4275tav 0.16
where ta is the outside temperature measured in degrees Fahrenheit, v is the speed measured in miles per hour, and twc is the wind-chill temperature. The formula cannot be used for wind speeds below 2 mph or temperatures below -58°F or above 41°F. Write a program that prompts the user to enter a temperature between -58°F and 41°F and a wind speed greater than or equal to 2 then displays the wind-chill temperature. Use Math.pow(a, b) to compute v 0.16. Here is a sample run: Enter the temperature in Fahrenheit between -58°F and 41°F: 5.3 Enter the wind speed ( 7 = 2) in miles per hour: 6 The wind chill index is -5.56707
2.18 (Print a table) Write a program that displays the following table. Cast floating-point numbers into integers.
a b pow(a, b) 1 2 1 2 3 8 3 4 81 4 5 1024 5 6 15625
*2.19 (Geometry: area of a triangle) Write a program that prompts the user to enter
three points, (x1, y1), (x2, y2), and (x3, y3), of a triangle then displays its area. The formula for computing the area of a triangle is s = (side1 + side2 + side3)/2; area = 2s(s - side1)(s - side2)(s - side3)
Here is a sample run:
Enter the coordinates of three points separated by spaces like x1 y1 x2 y2 x3 y3: 1.5 -3.4 4.6 5 9.5 -3.4 The area of the triangle is 33.6
M02_LIAN9966_12_SE_C02.indd 74
28/09/19 3:45 PM
Programming Exercises 75 Sections 2.13–2.18
*2.20 (Financial application: calculate interest) If you know the balance and the an-
nual percentage interest rate, you can compute the interest on the next monthly payment using the following formula: interest = balance * (annualInterestRate/1200) Write a program that reads the balance and the annual percentage interest rate and displays the interest for the next month. Here is a sample run:
Enter balance and interest rate (e.g., 3 for 3%): 1000 3.5 The interest is 2.91667
*2.21 (Financial application: calculate future investment value) Write a program that
reads in investment amount, annual interest rate, and number of years and displays the future investment value using the following formula: futureInvestmentValue = investmentAmount * (1 + monthlyInterestRate)numberOfYears*12
For example, if you enter amount 1000, annual interest rate 3.25%, and number of years 1, the future investment value is 1032.98. Here is a sample run: Enter investment amount: 1000.56 Enter annual interest rate in percentage: 4.25 Enter number of years: 1 Future value is $1043.92
*2.22 (Financial
*2.23
application: monetary units) Rewrite Listing 2.10, ComputeChange.java, to fix the possible loss of accuracy when converting a double value to an int value. Enter the input as an integer whose last two digits represent the cents. For example, the input 1156 represents 11 dollars and 56 cents. (Cost of driving) Write a program that prompts the user to enter the distance to drive, the fuel efficiency of the car in miles per gallon, and the price per gallon then displays the cost of the trip. Here is a sample run:
Enter the driving distance: 900.5 Enter miles per gallon: 25.5 Enter price per gallon: 3.55 The cost of driving is $125.36
Note More than 200 additional programming exercises with solutions are provided to the instructors on the Instructor Resource Website.
M02_LIAN9966_12_SE_C02.indd 75
28/09/19 3:45 PM
M02_LIAN9966_12_SE_C02.indd 76
28/09/19 3:45 PM
CHAPTER
3 Selections Objectives ■■
To declare boolean variables and write Boolean expressions using relational operators (§3.2).
■■
To implement selection control using one-way if statements (§3.3).
■■
To implement selection control using two-way if-else statements (§3.4).
■■
To implement selection control using nested if and multi-way if statements (§3.5).
■■
To avoid common errors and pitfalls in if statements (§3.6).
■■
To generate random numbers using the Math.random() method (§3.7).
■■
To program using selection statements for a variety of examples (SubtractionQuiz, BMI, ComputeTax) (§§3.7–3.9).
■■
To combine conditions using logical operators (!, &&, ||, and ^) (§3.10).
■■
To program using selection statements with combined conditions (LeapYear, Lottery) (§§3.11 and 3.12).
■■
To implement selection control using switch statements (§3.13).
■■
To write expressions using the conditional operator (§3.14).
■■
To examine the rules governing operator precedence and associativity (§3.15).
■■
To apply common techniques to debug errors (§3.16).
M03_LIAN9966_12_SE_C03.indd 77
28/09/19 3:54 PM
78 Chapter 3 Selections
3.1 Introduction The program can decide which statements to execute based on a condition. problem
Key Point
selection statements
If you enter a negative value for radius in Listing 2.2, ComputeAreaWithConsoleInput.java, the program displays an invalid result. If the radius is negative, you don’t want the program to compute the area. How can you deal with this situation? Like all high-level programming languages, Java provides selection statements: statements that let you choose actions with alternative courses. You can use the following selection statement to replace lines 12–17 in Listing 2.2: if (radius < 0) { System.out.println("Incorrect input"); } else { double area = radius * radius * 3.14159; System.out.println("Area is " + area); }
Selection statements use conditions that are Boolean expressions. A Boolean expression is an expression that evaluates to a Boolean value: true or false. We now introduce the boolean type and relational operators.
Boolean expression Boolean value
3.2 boolean Data Type, Values, and Expressions The boolean data type declares a variable with the value either true or false. Key Point boolean data type relational operators
How do you compare two values, such as whether a radius is greater than 0, equal to 0, or less than 0? Java provides six relational operators (also known as comparison operators), shown in Table 3.1, which can be used to compare two values (assume radius is 5 in the table).
Table 3.1 Relational Operators Java Operator Mathematics Symbol
Name
Example (radius is 5)
Result
=
≥
Greater than or equal to
radius >= 0
true
==
=
Equal to
radius == 0
false
!=
≠
Not equal to
radius != 0
true
Caution == vs. =
The equality testing operator is two equal signs (==), not a single equal sign (=). The latter symbol is for assignment.
The result of the comparison is a Boolean value: true or false. For example, the following statement displays true: double radius = 1; System.out.println(radius > 0); Boolean variable
M03_LIAN9966_12_SE_C03.indd 78
A variable that holds a Boolean value is known as a Boolean variable. The boolean data type is used to declare Boolean variables. A boolean variable can hold one of the two
28/09/19 3:54 PM
3.2 boolean Data Type, Values, and Expressions 79 values: true or false. For example, the following statement assigns true to the variable lightsOn: boolean lightsOn = true;
true and false are literals, just like a number such as 10. They are not keywords, but are reserved words and cannot be used as identifiers in the program. Suppose you want to develop a program to let a first-grader practice addition. The program randomly generates two single-digit integers, number1 and number2, and displays to the student a question such as “What is 1 + 7?, ” as shown in the sample run in Listing 3.1. After the student types the answer, the program displays a message to indicate whether it is true or false. There are several ways to generate random numbers. For now, generate the first integer using System.currentTimeMillis() % 10 (i.e., the last digit in the current time) and the second using System.currentTimeMillis() / 10 % 10 (i.e., the second last digit in the current time). Listing 3.1 gives the program. Lines 5–6 generate two numbers, number1 and number2. Line 14 obtains an answer from the user. The answer is graded in line 18 using a Boolean expression number1 + number2 == answer.
Boolean literals
VideoNote
Program addition quiz
Listing 3.1 AdditionQuiz.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
import java.util.Scanner; public class AdditionQuiz { public static void main(String[] args) { int number1 = (int)(System.currentTimeMillis() % 10); int number2 = (int)(System.currentTimeMillis() / 10 % 10);
generate number1 generate number2
// Create a Scanner Scanner input = new Scanner(System.in); System.out.print( "What is " + number1 + " + " + number2 + "? ");
show question
int answer = input.nextInt();
receive answer
System.out.println( number1 + " + " + number2 + " = " + answer + " is " + (number1 + number2 == answer));
display result
} }
What is 1 + 7? 8 1 + 7 = 8 is true What is 4 + 8? 9 4 + 8 = 9 is false
line# 5 6 14 16
M03_LIAN9966_12_SE_C03.indd 79
number1
number2
answer
output
4 8 9 4 + 8 = 9 is false
28/09/19 3:54 PM
80 Chapter 3 Selections Check Point
3.2.1 3.2.2
List six relational operators. Assuming x is 1, show the result of the following Boolean expressions: (x (x (x (x (x
3.2.3
> 0) < 0) != 0) >= 0) != 1)
Can the following conversions involving casting be allowed? Write a test program to verify it. boolean b = true; i = (int)b; int i = 1; boolean b = (boolean)i;
3.3 if Statements Key Point why if statement?
An if statement is a construct that enables a program to specify alternative paths of execution. The preceding program displays a message such as “6 + 2 = 7 is false.” If you wish the message to be “6 + 2 = 7 is incorrect,” you have to use a selection statement to make this minor change. Java has several types of selection statements: one-way if statements, two-way if-else statements, nested if statements, multi-way if-else statements, switch statements, and conditional operators. A one-way if statement executes an action if and only if the condition is true. The syntax for a one-way if statement is as follows: if (boolean-expression) { statement(s); }
if statement?
The flowchart in Figure 3.1a illustrates how Java executes the syntax of an if statement. A flowchart is a diagram that describes an algorithm or process, showing the steps as boxes of various kinds, and their order by connecting these with arrows. Process operations are represented in these boxes, and the arrows connecting them represent the flow of control. A diamond box denotes a Boolean condition, and a rectangle box represents statements.
flowchart
booleanexpression
true Statement(s)
(a)
false
(radius >= 0)
false
true area = radius * radius * PI; System.out.println("The area for the circle of" + " radius " + radius + " is " + area);
(b)
Figure 3.1 An if statement executes statements if the boolean-expression evaluates to true.
M03_LIAN9966_12_SE_C03.indd 80
28/09/19 3:54 PM
3.3 if Statements 81 If the boolean-expression evaluates to true, the statements in the block are executed. As an example, see the following code: if (radius >= 0) { area = radius * radius * PI; System.out.println("The area for the circle of radius " + radius + " is " + area); }
The flowchart of the preceding statement is shown in Figure 3.1b. If the value of radius is greater than or equal to 0, then the area is computed and the result is displayed; otherwise, the two statements in the block will not be executed. The boolean-expression is enclosed in parentheses. For example, the code in (a) is wrong. It should be corrected, as shown in (b).
if
i > 0 { System.out.println("i is positive");
}
if (i > 0) { System.out.println("i is positive"); } (b) Correct
(a) Wrong
The block braces can be omitted if they enclose a single statement. For example, the following statements are equivalent:
if (i > 0) { System.out.println("i is positive"); }
Equivalent
if (i > 0) System.out.println("i is positive");
(a)
(b)
Caution Omitting braces makes the code shorter, but it is prone to errors. It is a common mistake to forget the braces when you go back to modify the code that omits the braces.
Omitting braces or not
Listing 3.2 gives a program that prompts the user to enter an integer. If the number is a multiple of 5, the program displays HiFive. If the number is divisible by 2, it displays HiEven.
Listing 3.2 SimpleIfDemo.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
import java.util.Scanner; public class SimpleIfDemo { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Enter an integer: "); int number = input.nextInt();
enter input
if (number % 5 == 0) System.out.println("HiFive");
check 5
if (number % 2 == 0) System.out.println("HiEven");
check even
} }
M03_LIAN9966_12_SE_C03.indd 81
28/09/19 3:54 PM
82 Chapter 3 Selections Enter an integer: 4 HiEven
Enter an integer: 30 HiFive HiEven
The program prompts the user to enter an integer (lines 6–7) and displays HiFive if it is divisible by 5 (lines 9–10) and HiEven if it is divisible by 2 (lines 12–13). Check Point
3.3.1 Write an if statement that assigns 1 to x if y is greater than 0. 3.3.2 Write an if statement that increases pay by 3% if score is greater than 90. 3.3.3 What is wrong in the following code? if radius >= 0 { area = radius * radius * PI; System.out.println("The area for the circle of " + " radius " + radius + " is " + area); }
3.4 Two-Way if-else Statements Key Point
An if-else statement decides the execution path based on whether the condition is true or false. A one-way if statement performs an action if the specified condition is true. If the condition is false, nothing is done. But what if you want to take alternative actions when the condition is false? You can use a two-way if-else statement. The actions that a two-way if-else statement specifies differ based on whether the condition is true or false. Here is the syntax for a two-way if-else statement: if (boolean-expression) { statement(s)-for-the-true-case; } else { statement(s)-for-the-false-case; }
The flowchart of the statement is shown in Figure 3.2.
true
Statement(s) for the true case
booleanexpression
false
Statement(s) for the false case
Figure 3.2 An if-else statement executes statements for the true case if the booleanexpression evaluates to true; otherwise, statements for the false case are executed.
M03_LIAN9966_12_SE_C03.indd 82
28/09/19 3:54 PM
3.5 Nested if and Multi-Way if-else Statements 83 If the boolean-expression evaluates to true, the statement(s) for the true case are executed; otherwise, the statement(s) for the false case are executed. For example, consider the following code: if (radius >= 0) { area = radius * radius * PI; System.out.println("The area for the circle of radius " + radius + " is " + area); } else { System.out.println("Negative input"); }
two-way if-else statement
If radius >= 0 is true, area is computed and displayed; if it is false, the message "Negative input" is displayed. As usual, the braces can be omitted if there is only one statement within them. The braces enclosing the System.out.println("Negative input") statement can therefore be omitted in the preceding example. Here is another example of using the if-else statement. The example checks whether a number is even or odd, as follows: if (number % 2 == 0) System.out.println(number + " is even."); else System.out.println(number + " is odd.");
3.4.1 3.4.2
Write an if statement that increases pay by 3% if score is greater than 90, otherwise increases pay by 1%. What is the output of the code in (a) and (b) if number is 30? What if number is 35? if (number % 2 == 0) System.out.println(number + "is even."); System.out.println(number + "is odd"); (a)
Check Point
if (number % 2 == 0) System.out.println(number + "is even."); else System.out.println(number + "is odd"); (b)
3.5 Nested if and Multi-Way if-else Statements An if statement can be inside another if statement to form a nested if statement. The statement in an if or if-else statement can be any legal Java statement, including another if or if-else statement. The inner if statement is said to be nested inside the outer if statement. The inner if statement can contain another if statement; in fact, there is no limit to the depth of the nesting. For example, the following is a nested if statement:
Key Point nested if statement
if (i > k) { if (j > k) System.out.println("i and j are greater than k"); } else System.out.println("i is less than or equal to k");
The if (j > k) statement is nested inside the if (i > k) statement. The nested if statement can be used to implement multiple alternatives. The statement given in Figure 3.3a, for instance, prints a letter grade according to the score, with multiple alternatives.
M03_LIAN9966_12_SE_C03.indd 83
28/09/19 3:54 PM
84 Chapter 3 Selections if (score >= 90) System.out.print("A"); else if (score >= 80) System.out.print("B"); else if (score >= 70) System.out.print("C"); else if (score >= 60) System.out.print("D"); else System.out.print("F");
Equivalent
if (score >= 90) System.out.print("A"); else if (score >= 80) System.out.print("B"); else if (score >= 70) System.out.print("C"); else if (score >= 60) System.out.print("D"); else System.out.print("F");
This is better
(a)
(b)
Figure 3.3 A preferred format for multiple alternatives is shown in (b) using a multi-way if-else statement.
The execution of this if statement proceeds as shown in Figure 3.4. The first condition (score >= 90) is tested. If it is true, the grade is A. If it is false, the second condition (score >= 80) is tested. If the second condition is true, the grade is B. If that condition is false, the third condition and the rest of the conditions (if necessary) are tested until a condition is met or all of the conditions prove to be false. If all of the conditions are false, the grade is F. Note a condition is tested only when all of the conditions that come before it are false.
(score >= 90) false
true
(score >= 80) false
grade is A true
(score >= 70) false
grade is B true
(score >= 60) false
grade is C true
grade is D grade is F
Figure 3.4 You can use a multi-way if-else statement to assign a grade.
M03_LIAN9966_12_SE_C03.indd 84
28/09/19 3:54 PM
3.6 Common Errors and Pitfalls 85 The if statement in Figure 3.3a is equivalent to the if statement in Figure 3.3b. In fact, Figure 3.3b is the preferred coding style for multiple alternative if statements. This style, called multi-way if-else statements, avoids deep indentation and makes the program easy to read.
3.5.1
Suppose x = 3 and y = 2; show the output, if any, of the following code. What is the output if x = 3 and y = 4? What is the output if x = 2 and y = 2? Draw a flowchart of the code.
multi-way if statement
Check Point
if (x > 2) { if (y > 2) { z = x + y; System.out.println("z is " + z); } } else System.out.println("x is " + x);
3.5.2 Suppose x
= 2 and y = 3. Show the output, if any, of the following code. What is the output if x = 3 and y = 2? What is the output if x = 3 and y = 3? if (x > 2) if (y > 2) { int z = x + y; System.out.println("z is " + z); } else System.out.println("x is " + x);
3.5.3 What is wrong in the following code? if (score >= 60) System.out.println("D"); else if (score >= 70) System.out.println("C"); else if (score >= 80) System.out.println("B"); else if (score >= 90) System.out.println("A"); else System.out.println("F");
3.6 Common Errors and Pitfalls Forgetting necessary braces, ending an if statement in the wrong place, mistaking == for =, and dangling else clauses are common errors in selection statements. Duplicated statements in if-else statements and testing equality of double values are common pitfalls.
Key Point
The following errors are common among new programmers. Common Error 1: Forgetting Necessary Braces The braces can be omitted if the block contains a single statement. However, forgetting the braces when they are needed for grouping multiple statements is a common programming error. If you modify the code by adding new statements in an if statement without braces, you will have to insert the braces. For example, the following code in (a) is wrong. It should be written with braces to group multiple statements, as shown in (b).
M03_LIAN9966_12_SE_C03.indd 85
28/09/19 3:54 PM
86 Chapter 3 Selections if (radius >= 0) area = radius * radius * PI; System.out.println("The area " + " is " + area);
if (radius >= 0) { area = radius * radius * PI; System.out.println("The area " + " is " + area); } (b) Correct
(a) Wrong
In (a), the console output statement is not part of the if statement. It is the same as the following code: if (radius >= 0) area = radius * radius * PI; System.out.println(“The area " + “ is " + area);
Regardless of the condition in the if statement, the console output statement is always executed. Common Error 2: Wrong Semicolon at the if Line Adding a semicolon at the end of an if line, as shown in (a) below, is a common mistake. Logic error
Empty block
if (radius >= 0); { area = radius * radius * PI; System.out.println("The area " + " is " + area); }
Equivalent
if (radius >= 0) { }; { area = radius * radius * PI; System.out.println("The area " + " is " + area); }
(a)
(b)
This mistake is hard to find, because it is neither a compile error nor a runtime error; it is a logic error. The code in (a) is equivalent to that in (b) with an empty block. This error often occurs when you use the next-line block style. Using the end-of-line block style can help prevent this error. Common Error 3: Redundant Testing of Boolean Values To test whether a boolean variable is true or false in a test condition, it is redundant to use the equality testing operator like the code in (a): if (even == true) System.out.println( "It is even."); (a)
Equivalent This is better
if (even) System.out.println( "It is even."); (b)
Instead, it is better to test the boolean variable directly, as shown in (b). Another good reason for doing this is to avoid errors that are difficult to detect. Using the = operator instead of the == operator to compare the equality of two items in a test condition is a common error. It could lead to the following erroneous statement: if (even = true) System.out.println("It is even.");
This statement does not have compile errors. It assigns true to even, so even is always true.
M03_LIAN9966_12_SE_C03.indd 86
28/09/19 3:54 PM
3.6 Common Errors and Pitfalls 87 Common Error 4: Dangling else Ambiguity The code in (a) below has two if clauses and one else clause. Which if clause is matched by the else clause? The indentation indicates that the else clause matches the first if clause. However, the else clause actually matches the second if clause. This situation is known as the dangling else ambiguity. The else clause always matches the most recent unmatched if clause in the same block. Therefore, the statement in (a) is equivalent to the code in (b). int i = 1, j = 2, k = 3; if (i > j) if (i > k) System.out.println("A");
else
System.out.println("B");
Equivalent
This is better with correct indentation
dangling else ambiguity
int i = 1, j = 2, k = 3; if (i > j) if (i > k) System.out.println("A");
else
System.out.println("B");
(a)
(b)
Since (i > j) is false, nothing is displayed from the statements in (a) and (b). To force the else clause to match the first if clause, you must add a pair of braces: int i = 1, j = 2, k = 3; if (i > j) { if (i > k) System.out.println("A"); } else System.out.println("B");
This statement displays B. Common Error 5: Equality Test of Two Floating-Point Values As discussed in Common Error 3 in Section 2.19, floating-point numbers have a limited precision and calculations; involving floating-point numbers can introduce round-off errors. Therefore, equality test of two floating-point values is not reliable. For example, you expect the following code to display true, but surprisingly, it displays false: double x = 1.0 − 0.1 − 0.1 − 0.1 − 0.1 − 0.1; System.out.println(x == 0.5);
Here, x is not exactly 0.5, but is 0.5000000000000001. You cannot reliably test equality of two floating-point values. However, you can compare whether they are close enough by testing whether the difference of the two numbers is less than some threshold. That is, two numbers x and y are very close if x - y 6 e, for a very small value, e. e, a Greek letter pronounced "epsilon", is commonly used to denote a very small value. Normally, you set e to 10-14 for comparing two values of the double type, and to 10-7 for comparing two values of the float type. For example, the following code final double EPSILON = 1E−14; double x = 1.0 − 0.1 − 0.1 − 0.1 − 0.1 − 0.1; if (Math.abs(x − 0.5) < EPSILON) System.out.println(x + " is approximately 0.5");
will display 0.5000000000000001 is approximately 0.5.
The Math.abs(a) method can be used to return the absolute value of a.
M03_LIAN9966_12_SE_C03.indd 87
28/09/19 3:54 PM
88 Chapter 3 Selections Common Pitfall 1: Simplifying Boolean Variable Assignment Often, new programmers write the code that assigns a test condition to a boolean variable like the code in (a): if (number % 2 == 0) even = true; else even = false;
boolean even = number % 2 == 0;
Equivalent This is better
(a)
(b)
This is not an error, but it should be better written as shown in (b). Common Pitfall 2: Avoiding Duplicate Code in Different Cases Often, new programmers write the duplicate code in different cases that should be combined in one place. For example, the highlighted code in the following statement is duplicated: if (inState) { tuition = 5000; System.out.println("The tuition is " + tuition); } else { tuition = 15000; System.out.println("The tuition is " + tuition); }
This is not an error, but it should be better written as follows: if (inState) { tuition = 5000; } else { tuition = 15000; } System.out.println("The tuition is " + tuition);
The new code removes the duplication and makes the code easy to maintain, because you only need to change in one place if the print statement is modified. Check Point
3.6.1 Which of the following statements are equivalent? Which ones are correctly indented?
if (i > 0) if (j > 0) x = 0; else if (k > 0) y = 0; else z = 0;
(a)
if (i > 0) { if (j > 0) x = 0; else if (k > 0) y = 0; } else z = 0; (b)
if (i > if (j x = else y = else z =
0) > 0) 0; if (k > 0) 0; 0;
if (i > 0) if (j > 0) x = 0; else if (k > 0) y = 0; else z = 0;
(c)
(d)
3.6.2 Rewrite the following statement using a Boolean expression: if (count % 10 == 0) newLine = true; else newLine = false;
M03_LIAN9966_12_SE_C03.indd 88
28/09/19 3:54 PM
3.7 Generating Random Numbers 89 3.6.3 Are the following statements correct? Which one is better? if (age < 16) System.out.println ("Cannot get a driver’s license"); if (age >= 16) System.out.println ("Can get a driver’s license");
if (age < 16) System.out.println ("Cannot get a driver’s license"); else System.out.println ("Can get a driver’s license");
(a)
(b)
3.6.4 What is the output of the following code if number is 14, 15, or 30? if (number % 2 == 0) System.out.println (number + " is even"); if (number % 5 == 0) System.out.println (number + " is multiple of 5");
if (number % 2 == 0) System.out.println (number + " is even"); else if (number % 5 == 0) System.out.println (number + " is multiple of 5");
(a)
(b)
3.7 Generating Random Numbers You can use Math.random() to obtain a random double value between 0.0 and 1.0, excluding 1.0. Suppose you want to develop a program for a first-grader to practice subtraction. The program randomly generates two single-digit integers, number1 and number2, with number1 >= number2, and it displays to the student a question such as “What is 9 - 2?” After the student enters the answer, the program displays a message indicating whether it is correct. The previous programs generate random numbers using System.currentTimeMillis(). A better approach is to use the random() method in the Math class. Invoking this method returns a random double value d such that 0.0 … d 6 1.0. Thus, (int)(Math.random() * 10) returns a random single-digit integer (i.e., a number between 0 and 9). The program can work as follows:
Key Point
VideoNote
Program subtraction quiz random() method
1. Generate two single-digit integers into number1 and number2. 2. If number1 < number2, swap number1 with number2. 3. Prompt the student to answer, "What is number1 − number2?" 4. Check the student’s answer and display whether the answer is correct. The complete program is given in Listing 3.3.
Listing 3.3 SubtractionQuiz.java 1 import java.util.Scanner; 2 3 public class SubtractionQuiz { 4 public static void main(String[] args) { 5 // 1. Generate two random single-digit integers 6 int number1 = (int)(Math.random() * 10); 7 int number2 = (int)(Math.random() * 10); 8 9 // 2. If number1 < number2, swap number1 with number2 10 if (number1 < number2) { 11 int temp = number1;
M03_LIAN9966_12_SE_C03.indd 89
random number
28/09/19 3:54 PM
90 Chapter 3 Selections 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 } 31 }
get answer
check the answer
number1 = number2; number2 = temp; } // 3. Prompt the student to answer "What is number1 – number2?" System.out.print ("What is " + number1 + " − " + number2 + "? "); Scanner input = new Scanner(System.in); int answer = input.nextInt(); // 4. Grade the answer and display the result if (number1 − number2 == answer) System.out.println("You are correct!"); else { System.out.println("Your answer is wrong."); System.out.println(number1 + " − " + number2 + " should be " + (number1 − number2)); }
What is 6 − 6? 0 You are correct!
What is 9 − 2? 5 Your answer is wrong 9 − 2 is 7
line#
number1
6
2
7
number2
13
answer
output
9
11 12
temp
2 9 2
20
5
26
Your answer is wrong 9 − 2 should be 7
To swap two variables number1 and number2, a temporary variable temp (line 11) is used to first hold the value in number1. The value in number2 is assigned to number1 (line 12), and the value in temp is assigned to number2 (line 13). Check Point
3.7.1 Which of the following is a possible output from invoking Math.random()? 323.4, 0.5, 34, 1.0, 0.0, 0.234
3.7.2 a. How do you generate a random integer i such that 0 … i 6 20? b. How do you generate a random integer i such that 10 … i 6 20? c. How do you generate a random integer i such that 10 … i … 50? d. Write an expression that returns 0 or 1 randomly.
M03_LIAN9966_12_SE_C03.indd 90
28/09/19 3:54 PM
3.8 Case Study: Computing Body Mass Index 91
3.8 Case Study: Computing Body Mass Index You can use nested if statements to write a program that interprets body mass index. Body mass index (BMI) is a measure of health based on height and weight. It can be calculated by taking your weight in kilograms and dividing it by the square of your height in meters. The interpretation of BMI for people 20 years or older is as follows:
BMI
Interpretation
BMI 6 18.5
Underweight
18.5 … BMI 6 25.0
Normal
25.0 … BMI 6 30.0
Overweight
30.0 … BMI
Obese
Key Point
Write a program that prompts the user to enter a weight in pounds and height in inches and displays the BMI. Note that one pound is 0.45359237 kilograms, and one inch is 0.0254 meters. Listing 3.4 gives the program.
Listing 3.4 ComputeAndInterpretBMI.java 1 import java.util.Scanner; 2 3 public class ComputeAndInterpretBMI { 4 public static void main(String[] args) { 5 Scanner input = new Scanner(System.in); 6 7 // Prompt the user to enter weight in pounds 8 System.out.print("Enter weight in pounds: "); 9 double weight = input.nextDouble(); 10 11 // Prompt the user to enter height in inches 12 System.out.print("Enter height in inches: "); 13 double height = input.nextDouble(); 14 15 final double KILOGRAMS_PER_POUND = 0.45359237; // Constant 16 final double METERS_PER_INCH = 0.0254; // Constant 17 18 // Compute BMI 19 double weightInKilograms = weight * KILOGRAMS_PER_POUND; 20 double heightInMeters = height * METERS_PER_INCH; 21 double bmi = weightInKilograms / 22 (heightInMeters * heightInMeters); 23 24 // Display result 25 System.out.println("BMI is " + bmi); 26 if (bmi < 18.5) 27 System.out.println("Underweight"); 28 else if (bmi < 25) 29 System.out.println("Normal"); 30 else if (bmi < 30) 31 System.out.println("Overweight"); 32 else 33 System.out.println("Obese"); 34 } 35 }
M03_LIAN9966_12_SE_C03.indd 91
input weight
input height
compute bmi
display output
28/09/19 3:54 PM
92 Chapter 3 Selections Enter weight in pounds: 146 Enter height in inches: 70 BMI is 20.948603801493316 Normal
line# weight height weightInKilograms 9 13
heightInMeters
bmi
output
146 70
19
66.22448602
20
1.778
21
20.9486
25
BMI is 20.95
29
Normal
The constants KILOGRAMS_PER_POUND and METERS_PER_INCH are defined in lines 15–16. Using constants here makes programs easy to read. You should test the input that covers all possible cases for BMI to ensure that the program works for all cases.
3.9 Case Study: Computing Taxes You can use nested if statements to write a program for computing taxes. Key Point
VideoNote
Use multi-way if-else statements
The U.S. federal personal income tax is calculated based on filing status and taxable income. There are four filing statuses: single filers, married filing jointly or qualified widow(er), married filing separately, and head of household. The tax rates vary every year. Table 3.2 shows the rates for 2009. If you are single with a taxable income of $10,000, for example, the first $8,350 is taxed at 10% and the other $1,650 is taxed at 15%, so your total tax is $1,082.50.
Table 3.2 2009 U.S. Federal Personal Tax Rates Marginal Tax Rate
Single
10%
$0–$8,350
Married Filing Jointly or Qualifying Widow(er) $0–$16,700 $16,701–$67,900
Married Filing Separately $0–$8,350 $8,351–$33,950
Head of Household $0–$11,950
15%
$8,351–$33,950
$11,951–$45,500
25%
$33,951–$82,250
$67,901–$137,050
$33,951–$68,525
$45,501–$117,450
28%
$82,251–$171,550
$137,051–$208,850
$68,526–$104,425
$117,451–$190,200
33%
$171,551–$372,950
$208,851–$372,950
$104,426–$186,475
$190,201–$372,950
35%
+372,951+
+372,951+
+186,476+
+372,951+
You are to write a program to compute personal income tax. Your program should prompt the user to enter the filing status and taxable income and compute the tax. Enter 0 for single filers, 1 for married filing jointly or qualified widow(er), 2 for married filing separately, and 3 for head of household.
M03_LIAN9966_12_SE_C03.indd 92
28/09/19 3:54 PM
3.9 Case Study: Computing Taxes 93 Your program computes the tax for the taxable income based on the filing status. The filing status can be determined using if statements outlined as follows: if (status == 0) { // Compute tax for single filers } else if (status == 1) { // Compute tax for married filing jointly or qualifying widow(er) } else if (status == 2) { // Compute tax for married filing separately } else if (status == 3) { // Compute tax for head of household } else { // Display wrong status }
For each filing status there are six tax rates. Each rate is applied to a certain amount of taxable income. For example, of a taxable income of $400,000 for single filers, $8,350 is taxed at 10%, (33,950 - 8,350) at 15%, (82,250 - 33,950) at 25%, (171,550 - 82,250) at 28%, (372,950 - 171,550) at 33%, and (400,000 - 372,950) at 35%. Listing 3.5 gives the solution for computing taxes for single filers. The complete solution is left as an exercise.
Listing 3.5 ComputeTax.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
import java.util.Scanner; public class ComputeTax { public static void main(String[] args) { // Create a Scanner Scanner input = new Scanner(System.in); // Prompt the user to enter filing status System.out.print("(0-single filer, 1-married jointly or " + "qualifying widow(er), 2-married separately, 3-head of " + "household) Enter the filing status: "); int status = input.nextInt();
input status
// Prompt the user to enter taxable income System.out.print("Enter the taxable income: "); double income = input.nextDouble();
input income
// Compute tax double tax = 0;
compute tax
if (status == 0) { // Compute tax for single filers if (income 34) || (weight >= 150) is false, because (age > 34) and (weight >= 150) are both false.
false
true
true
true
false
true
(age > 18) || (weight < 140) is true, because (age > 18)
is true. true
true
true
Table 3.7 Truth Table for Operator ^ p1
p2
p1 ^ p2
Example (assume age = 24, weight = 140)
false
false
false
(age > 34) ^ (weight > 140) is false, because (age > 34) and (weight > 140) are both false.
false
true
true
(age > 34) ^ (weight >= 140) is true, because (age > 34) is false but (weight >= 140) is true.
true
false
true
true
true
false
Listing 3.6 gives a program that checks whether a number is divisible by 2 and 3, by 2 or 3, and by 2 or 3 but not both.
Listing 3.6 TestBooleanOperators.java import class
input and
M03_LIAN9966_12_SE_C03.indd 96
1 2 3 4 5 6 7 8 9 10 11 12 13 14
import java.util.Scanner; public class TestBooleanOperators { public static void main(String[] args) { // Create a Scanner Scanner input = new Scanner(System.in); // Receive an input System.out.print("Enter an integer: "); int number = input.nextInt(); if (number % 2 == 0 && number % 3 == 0) System.out.println(number + " is divisible by 2 and 3.");
28/09/19 3:54 PM
3.10 Logical Operators 97 15 16 17 18 19 20 21 22
if (number % 2 == 0 || number % 3 == 0) System.out.println(number + " is divisible by 2 or 3.");
or
if (number % 2 == 0 ^ number % 3 == 0) System.out.println(number + " is divisible by 2 or 3, but not both.");
exclusive or
} }
Enter an integer: 4 4 is divisible by 2 or 3. 4 is divisible by 2 or 3, but not both.
Enter an integer: 18 18 is divisible by 2 and 3. 18 is divisible by 2 or 3.
(number % 2 == 0 && number % 3 == 0) (line 12) checks whether the number is divisible by both 2 and 3. (number % 2 == 0 || number % 3 == 0) (line 15) checks whether the number is divisible by 2 or by 3. (number % 2 == 0 ^ number % 3 == 0) (line 18) checks whether the number is divisible by 2 or 3, but not both.
Caution In mathematics, the expression 28 = 0) || (x < 0) (x != 1) == !(x == 1)
3.10.2 (a) Write a Boolean expression that evaluates to true if a number stored in vari-
3.10.3 3.10.4
able num is between 1 and 100. (b) Write a Boolean expression that evaluates to true if a number stored in variable num is between 1 and 100 or the number is negative. (a) Write a Boolean expression for x - 5 6 4.5. (b) Write a Boolean expression for x - 5 7 4.5. Assume x and y are int type. Which of the following are legal Java expressions? x > y > 0 x = y && y x /= y x or y x and y (x != 0) || (x = 0)
3.10.5 Are the following two expressions the same? (a) x % 2 == 0 && x % 3 == 0 (b) x % 6 == 0
3.10.6 What is the value of the expression x >= 50 && x
y && y < z)); y || y < z)); z)); z));
} }
3.10.8 Write a Boolean expression that evaluates to true if age is greater than 13 and less than 18.
M03_LIAN9966_12_SE_C03.indd 98
28/09/19 3:54 PM
3.11 Case Study: Determining Leap Year 99 3.10.9 Write a Boolean expression that evaluates to true if weight is greater than 50
pounds or height is greater than 60 inches. 3.10.10 Write a Boolean expression that evaluates to true if weight is greater than 50 pounds and height is greater than 60 inches. 3.10.11 Write a Boolean expression that evaluates to true if either weight is greater than 50 pounds or height is greater than 60 inches, but not both.
3.11 Case Study: Determining Leap Year A year is a leap year if it is divisible by 4 but not by 100, or if it is divisible by 400. A leap year has 366 days. The February of a leap year has 29 days. You can use the following Boolean expressions to check whether a year is a leap year:
Key Point
// A leap year is divisible by 4 boolean isLeapYear = (year % 4 == 0); // A leap year is divisible by 4 but not by 100 isLeapYear = isLeapYear && (year % 100 != 0); // A leap year is divisible by 4 but not by 100 or divisible by 400 isLeapYear = isLeapYear || (year % 400 == 0);
Or you can combine all these expressions into one as follows: isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
Listing 3.7 gives the program that lets the user enter a year and checks whether it is a leap year.
Listing 3.7 LeapYear.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
import java.util.Scanner; public class LeapYear { public static void main(String[] args) { // Create a Scanner Scanner input = new Scanner(System.in); System.out.print("Enter a year: "); int year = input.nextInt(); // Check if the year is a leap year boolean isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); // Display the result System.out.println(year + " is a leap year? " + isLeapYear);
input
leap year?
display result
} }
Enter a year: 2008 2008 is a leap year? true
Enter a year: 1900 1900 is a leap year? false
M03_LIAN9966_12_SE_C03.indd 99
28/09/19 3:54 PM
100 Chapter 3 Selections Enter a year: 2002 2002 is a leap year? false
Check Point
3.11.1 How many days in the February of a leap year? Which of the following is a leap year? 500, 1000, 2000, 2016, and 2020?
3.12 Case Study: Lottery Key Point
The lottery program involves generating random numbers, comparing digits, and using Boolean operators. Suppose you want to develop a program to play lottery. The program randomly generates a lottery of a two-digit number, prompts the user to enter a two-digit number, and determines whether the user wins according to the following rules: 1. If the user input matches the lottery number in the exact order, the award is $10,000. 2. If all digits in the user input match all digits in the lottery number, the award is $3,000. 3. If one digit in the user input matches a digit in the lottery number, the award is $1,000. Note the digits of a two-digit number may be 0. If a number is less than 10, we assume that the number is preceded by a 0 to form a two-digit number. For example, number 8 is treated as 08, and number 0 is treated as 00 in the program. Listing 3.8 gives the complete program.
Listing 3.8 Lottery.java
generate a lottery number
enter a guess
exact match? match all digits?
match one digit?
M03_LIAN9966_12_SE_C03.indd 100
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
import java.util.Scanner; public class Lottery { public static void main(String[] args) { // Generate a lottery number int lottery = (int)(Math.random() * 100); // Prompt the user to enter a guess Scanner input = new Scanner(System.in); System.out.print("Enter your lottery pick (two digits): "); int guess = input.nextInt(); // Get digits from lottery int lotteryDigit1 = lottery / 10; int lotteryDigit2 = lottery % 10; // Get digits from guess int guessDigit1 = guess / 10; int guessDigit2 = guess % 10; System.out.println("The lottery number is " + lottery); // Check the guess if (guess == lottery) System.out.println("Exact match: you win $10,000"); else if (guessDigit2 == lotteryDigit1 && guessDigit1 == lotteryDigit2) System.out.println("Match all digits: you win $3,000"); else if (guessDigit1 == lotteryDigit1 || guessDigit1 == lotteryDigit2 || guessDigit2 == lotteryDigit1 || guessDigit2 == lotteryDigit2)
28/09/19 3:54 PM
3.12 Case Study: Lottery 101 33 34 35 36 37
System.out.println("Match one digit: you win $1,000"); else System.out.println("Sorry, no match"); } }
Enter your lottery pick (two digits): 15 The lottery number is 15 Exact match: you win $10,000
Enter your lottery pick (two digits): 45 The lottery number is 54 Match all digits: you win $3,000
Enter your lottery pick: 23 The lottery number is 34 Match one digit: you win $1,000
Enter your lottery pick: 23 The lottery number is 14 Sorry: no match
line#
6
11
14
15
18
19
33
variable lottery guess lotteryDigit1 lotteryDigit2
34 23 3 4
guessDigit1
2
guessDigit2 Output
3 Match one digit: you win $1,000
The program generates a lottery using the random() method (line 6) and prompts the user to enter a guess (line 11). Note guess % 10 obtains the last digit from guess and guess /10 obtains the first digit from guess, since guess is a two-digit number (lines 18 and 19). The program checks the guess against the lottery number in this order: 1. First, check whether the guess matches the lottery exactly (line 24). 2. If not, check whether the reversal of the guess matches the lottery (lines 26 and 27). 3. If not, check whether one digit is in the lottery (lines 29–32). 4. If not, nothing matches and display "Sorry, no match" (lines 34 and 35).
3.12.1 What happens if you enter an integer as 05?
M03_LIAN9966_12_SE_C03.indd 101
Check Point
28/09/19 3:54 PM
102 Chapter 3 Selections
3.13 switch Statements Key Point
A switch statement executes statements based on the value of a variable or an expression. The if statement in Listing 3.5, ComputeTax.java, makes selections based on a single true or false condition. There are four cases for computing taxes, which depend on the value of status. To fully account for all the cases, nested if statements were used. Overuse of nested if statements makes a program difficult to read. Java provides a switch statement to simplify coding for multiple conditions. You can write the following switch statement to replace the nested if statement in Listing 3.5: switch (status) { case 0: compute tax for single filers; break; case 1: compute tax for married jointly or qualifying widow(er); break; case 2: compute tax for married filing separately; break; case 3: compute tax for head of household; break; default: System.out.println("Error: invalid status"); System.exit(1); }
The flowchart of the preceding switch statement is shown in Figure 3.5.
status is 0
status is 1
status is 2
status is 3
default
Compute tax for single filer
break
Compute tax for married jointly or qualified widow(er)
break
Compute tax for married filing separately
break
Compute tax for head of household
break
Default actions
break
Figure 3.5 The switch statement checks all cases and executes the statements in the matched case.
switch statement
This statement checks to see whether the status matches the value 0, 1, 2, or 3, in that order. If matched, the corresponding tax is computed; if not matched, a message is displayed. Here is the full syntax for the switch statement: switch (switch-expression) { case value1: statement(s)1; break;
M03_LIAN9966_12_SE_C03.indd 102
28/09/19 3:54 PM
3.13 switch Statements 103 case value2: statement(s)2; break; ... case valueN: statement(s)N; break; default: statement(s)-for-default; }
The switch statement observes the following rules: ■■
The switch-expression must yield a value of char, byte, short, int, or String type and must always be enclosed in parentheses. (The char and String types will be introduced in Chapter 4.)
■■
The value1, ..., and valueN must have the same data type as the value of the switch-expression. Note that value1, ..., and valueN are constant expressions, meaning they cannot contain variables, such as 1 + x.
■■
When the value in a case statement matches the value of the switch-expression, the statements starting from this case are executed until either a break statement or the end of the switch statement is reached.
■■
The default case, which is optional, can be used to perform actions when none of the specified cases matches the switch-expression.
■■
The keyword break is optional. The break statement immediately ends the switch statement.
Caution Do not forget to use a break statement when one is needed. Once a case is matched, the statements starting from the matched case are executed until a break statement or the end of the switch statement is reached. This is referred to as fall-through behavior. For example, the following code displays Weekday for days 1–5 and Weekend for day 0 and day 6.
switch case case case case case case case }
without break fall-through behavior
(day) { 1: 2: 3: 4: 5: System.out.println(“Weekday"); break; 0: 6: System.out.println(“Weekend");
Tip To avoid programming errors and improve code maintainability, it is a good idea to put a comment in a case clause if break is purposely omitted.
Now let us write a program to find out the Chinese Zodiac sign for a given year. The Chinese Zodiac is based on a 12-year cycle, with each year represented by an animal— monkey, rooster, dog, pig, rat, ox, tiger, rabbit, dragon, snake, horse, or sheep—in this cycle, as shown in Figure 3.6. Note year % 12 determines the Zodiac sign. 1900 is the year of the rat because 1900 % 12 is 4. Listing 3.9 gives a program that prompts the user to enter a year and displays the animal for the year.
M03_LIAN9966_12_SE_C03.indd 103
28/09/19 3:54 PM
104 Chapter 3 Selections pig
rat ox
dog rooster
tiger
monkey
rabbit
year % 12 5
dragon
sheep horse
snake
0: monkey 1: rooster 2: dog 3: pig 4: rat 5: ox 6: tiger 7: rabbit 8: dragon 9: snake 10: horse 11: sheep
Figure 3.6 The Chinese Zodiac is based on a 12-year cycle.
Listing 3.9 ChineseZodiac.java
enter year determine Zodiac sign
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
import java.util.Scanner; public class ChineseZodiac { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Enter a year: "); int year = input.nextInt(); switch case case case case case case case case case case case case }
(year % 12) { 0: System.out.println("monkey"); break; 1: System.out.println("rooster"); break; 2: System.out.println("dog"); break; 3: System.out.println("pig"); break; 4: System.out.println("rat"); break; 5: System.out.println("ox"); break; 6: System.out.println("tiger"); break; 7: System.out.println("rabbit"); break; 8: System.out.println("dragon"); break; 9: System.out.println("snake"); break; 10: System.out.println("horse"); break; 11: System.out.println("sheep");
} }
Enter a year: 1963 rabbit
Enter a year: 1877 ox
M03_LIAN9966_12_SE_C03.indd 104
28/09/19 3:54 PM
3.14 Conditional Operators 105 3.13.1 What data types are required for a switch variable? If the keyword break is not
3.13.2
used after a case is processed, what is the next statement to be executed? Can you convert a switch statement to an equivalent if statement, or vice versa? What are the advantages of using a switch statement? What is y after the following switch statement is executed? Rewrite the code using an if-else statement.
Check Point
x = 3; y = 3; switch (x + 3) { case 6: y = 1; default: y += 1; }
3.13.3 What is x after the following if-else statement is executed? Use a switch statement to rewrite it and draw the flowchart for the new switch statement. int x = 1, a = 3; if (a == 1) x += 5; else if (a == 2) x += 10; else if (a == 3) x += 16; else if (a == 4) x += 34;
3.13.4 Write a switch statement that displays Sunday, Monday, Tuesday, Wednesday, 3.13.5
Thursday, Friday, Saturday, if day is 0, 1, 2, 3, 4, 5, 6, respectively. Rewrite Listing 3.9 using an if-else statement.
3.14 Conditional Operators A conditional operator evaluates an expression based on a condition. You might want to assign a value to a variable that is restricted by certain conditions. For example, the following statement assigns 1 to y if x is greater than 0 and −1 to y if x is less than or equal to 0:
Key Point
if (x > 0) y = 1; else y = −1;
Alternatively, as in the following example, you can use a conditional operator to achieve the same result.
conditional operator
y = (x > 0)? 1: −1;
The symbols? and: appearing together is called a conditional operator (also known as a ternary operator because it uses three operands. It is the only ternary operator in Java. The conditional operator is in a completely different style, with no explicit if in the statement. The syntax to use the operator is as follows:
ternary operator
boolean-expression? expression1: expression2
The result of this expression is expression1 if boolean-expression is true; otherwise the result is expression2. Suppose you want to assign the larger number of variable num1 and num2 to max. You can simply write a statement using the conditional operator: max = (num1 > num2)? num1: num2;
M03_LIAN9966_12_SE_C03.indd 105
28/09/19 3:54 PM
106 Chapter 3 Selections For another example, the following statement displays the message “num is even” if num is even, and otherwise displays “num is odd.” System.out.println((num % 2 == 0)? "num is even": "num is odd");
As you can see from these examples, the conditional operator enables you to write short and concise code. Conditional expressions can be embedded. For example, the following code assigns 1, 0, or −1 to status if n1 > n1, n1 == n2, or n1 < n2: status = n1 > n2? 1: (n1 == n2? 0: −1); Check Point
3.14.1 Suppose when you run the following program, you enter the input 2
3 6 from the
console. What is the output?
public class Test { public static void main(String[] args) { java.util.Scanner input = new java.util.Scanner(System.in); double x = input.nextDouble(); double y = input.nextDouble(); double z = input.nextDouble(); System.out.println((x < y && y < z)? "sorted": "not sorted"); } }
3.14.2 Rewrite the following if statements using the conditional operator. if (ages >= 16) ticketPrice = 20; else ticketPrice = 10;
3.14.3 Rewrite the following codes using if-else statements. a. score = (x > 10)? 3 * scale: 4 * scale; b. tax = (income > 10000)? income * 0.2: income * 0.17 + 1000; c. System.out.println((number % 3 == 0)? i: j);
3.14.4 Write an expression using a conditional operator that returns randomly −1 or 1.
3.15 Operator Precedence and Associativity Key Point
Operator precedence and associativity determine the order in which operators are evaluated. Section 2.11 introduced operator precedence involving arithmetic operators. This section discusses operator precedence in more detail. Suppose you have this expression: 3 + 4 * 4 > 5 * (4 + 3) – 1 && (4 – 3 > 5)
operator precedence
M03_LIAN9966_12_SE_C03.indd 106
What is its value? What is the execution order of the operators? The expression within parentheses is evaluated first. (Parentheses can be nested, in which case the expression within the inner parentheses is executed first.) When evaluating an expression without parentheses, the operators are applied according to the precedence rule and the associativity rule. The precedence rule defines precedence for operators, as shown in Table 3.8, which contains the operators you have learned so far. Operators are listed in decreasing order of precedence from top to bottom. The logical operators have lower precedence than the relational operators, and the relational operators have lower precedence than the arithmetic operators. Operators with the same precedence appear in the same group. (See Appendix C, Operator Precedence Chart, for a complete list of Java operators and their precedence.)
28/09/19 3:54 PM
3.15 Operator Precedence and Associativity 107 Table 3.8 Operator Precedence Chart Precedence
Operator var++ and var−− (Postfix) +, − (Unary plus and minus), ++var and −−var (Prefix)
(type) (Casting) !(Not) *, /, % (Multiplication, division, and remainder) +, − (Binary addition and subtraction) = (Relational) ==, != (Equality) ^ (Exclusive OR) && (AND) || (OR) ?: (Ternary operator) =, +=, −=, *=, /=, %= (Assignment operators)
If operators with the same precedence are next to each other, their associativity determines the order of evaluation. All binary operators except assignment operators are left associative. For example, since + and − are of the same precedence and are left associative, the expression a - b + c - d
is equivalent to
operator associativity
((a - b) + c) - d
Assignment operators are right associative. Therefore, the expression a = b += c = 5
is equivalent to
a = (b += (c = 5))
Suppose a, b, and c are 1 before the assignment; after the whole expression is evaluated, a becomes 6, b becomes 6, and c becomes 5. Note that left associativity for the assignment operator would not make sense.
Note Java has its own way to evaluate an expression internally. The result of a Java evaluation is the same as that of its corresponding arithmetic evaluation. Advanced readers may refer to Supplement III.B for more discussions on how an expression is evaluated in Java behind the scenes.
3.15.1 List the precedence order of the Boolean operators. Evaluate the following expressions: true || true && false true && true || false
behind the scenes Check Point
3.15.2 True or false? All the binary operators except = are left associative. 3.15.3 Evaluate the following expressions: 2 * 2 – 3 > 2 && 4 – 2 > 5 2 * 2 – 3 > 2 || 4 – 2 > 5
3.15.4 Is (x Is (x Is (x
> 0 && x < 10) the same as ((x > 0) && (x < 10))? > 0 || x < 10) the same as ((x > 0) || (x < 10))?
> 0 || x < 10 && y < 0) the same as (x > 0 || (x < 10 && y < 0))?
M03_LIAN9966_12_SE_C03.indd 107
28/09/19 3:54 PM
108 Chapter 3 Selections
3.16 Debugging Debugging is the process of finding and fixing errors in a program. Key Point
bugs hand-traces debugging
As mentioned in Section 1.10, syntax errors are easy to find and easy to correct because the compiler gives indications as to where the errors came from and why they are there. Runtime errors are not difficult to find either, because the Java interpreter displays them on the console when the program aborts. Finding logic errors, on the other hand, can be very challenging. Logic errors are called bugs. The process of finding and correcting errors is called debugging. A common approach to debugging is to use a combination of methods to help pinpoint the part of the program where the bug is located. You can hand-trace the program (i.e., catch errors by reading the program), or you can insert print statements in order to show the values of the variables or the execution flow of the program. These approaches might work for debugging a short, simple program, but for a large, complex program, the most effective approach is to use a debugger utility. JDK includes a command-line debugger, jdb, which is invoked with a class name. jdb is itself a Java program, running its own copy of Java interpreter. All the Java IDE tools, such as Eclipse and NetBeans, include integrated debuggers. The debugger utilities let you follow the execution of a program. They vary from one system to another, but they all support most of the following helpful features. ■■
Executing a single statement at a time: The debugger allows you to execute one statement at a time so that you can see the effect of each statement.
■■
Tracing into or stepping over a method: If a method is being executed, you can ask the debugger to enter the method and execute one statement at a time in the method, or you can ask it to step over the entire method. You should step over the entire method if you know that the method works. For example, always step over system-supplied methods, such as System.out.println.
■■
Setting breakpoints: You can also set a breakpoint at a specific statement. Your program pauses when it reaches a breakpoint. You can set as many breakpoints as you want. Breakpoints are particularly useful when you know where your programming error starts. You can set a breakpoint at that statement, and have the program execute until it reaches the breakpoint.
■■
Displaying variables: The debugger lets you select several variables and display their values. As you trace through a program, the content of a variable is continuously updated.
■■
Displaying call stacks: The debugger lets you trace all of the method calls. This feature is helpful when you need to see a large picture of the program-execution flow.
■■
Modifying variables: Some debuggers enable you to modify the value of a variable when debugging. This is convenient when you want to test a program with different samples, but do not want to leave the debugger.
Tip debugging in IDE
M03_LIAN9966_12_SE_C03.indd 108
If you use an IDE such as Eclipse or NetBeans, please refer to Learning Java Effectively with Eclipse/NetBeans in Supplements II.C and II.E on the Companion Website. The supplement shows you how to use a debugger to trace programs, and how debugging can help in learning Java effectively.
28/09/19 3:54 PM
Chapter Summary 109
Key Terms boolean data type, 78 Boolean expression, 78 Boolean value, 78 conditional operator, 105 dangling else ambiguity, 87 debugging, 108 fall-through behavior, 103
flowchart, 80 lazy operator, 98 operator associativity, 107 operator precedence, 106 selection statement, 78 short-circuit operator, 98
Chapter Summary 1. A boolean-type variable can store a true or false value. 2. The relational operators (=) yield a Boolean value. 3. Selection statements are used for programming with alternative courses of actions. There are several types of selection statements: one-way if statements, two-way ifelse statements, nested if statements, multi-way if-else statements, switch statements, and conditional operators.
4. The various if statements all make control decisions based on a Boolean expression.
Based on the true or false evaluation of the expression, these statements take one of the two possible courses.
5. The Boolean operators &&, ||, !, and ^ operate with Boolean values and variables. 6. When evaluating p1
&& p2, Java first evaluates p1 then evaluates p2 if p1 is true; if p1 is false, it does not evaluate p2. When evaluating p1 || p2, Java first evaluates p1 then evaluates p2 if p1 is false; if p1 is true, it does not evaluate p2. Therefore, && is referred to as the short-circuit or lazy AND operator, and || is referred to as the
short-circuit or lazy OR operator.
7. The switch statement makes control decisions based on a switch expression of type char, byte, short, int, or String.
8. The keyword break is optional in a switch statement, but it is normally used at the
end of each case in order to skip the remainder of the switch statement. If the break statement is not present, the next case statement will be executed.
9. The operators in expressions are evaluated in the order determined by the rules of parentheses, operator precedence, and operator associativity.
10. Parentheses can be used to force the order of evaluation to occur in any sequence. 11. Operators with higher precedence are evaluated earlier. For operators of the same precedence, their associativity determines the order of evaluation.
12. All binary operators except assignment operators are left associative; assignment operators are right associative.
M03_LIAN9966_12_SE_C03.indd 109
28/09/19 3:54 PM
110 Chapter 3 Selections
Quiz Answer the quiz for this chapter online at the Companion Website.
Programming Exercises Pedagogical Note For each exercise, carefully analyze the problem requirements and design strategies for solving the problem before coding.
think before coding
Debugging Tip Before you ask for help, read and explain the program to yourself, and trace it using several representative inputs by hand or using an IDE debugger. You learn how to program by debugging your own mistakes.
learn from mistakes
Section 3.2
*3.1 (Algebra: solve quadratic equations) The two roots of a quadratic equation ax2 + bx + c = 0 can be obtained using the following formula:
-b + 2b2 - 4ac -b - 2b2 - 4ac and r2 = 2a 2a b2 - 4ac is called the discriminant of the quadratic equation. If it is positive, the equation has two real roots. If it is zero, the equation has one root. If it is negative, the equation has no real roots. Write a program that prompts the user to enter values for a, b, and c and displays the result based on the discriminant. If the discriminant is positive, display two roots. If the discriminant is 0, display one root. Otherwise, display “The equation has no real roots.” Note you can use Math.pow(x, 0.5) to compute 2x. Here are some sample runs: r1 =
Enter a, b, c: 1.0 3 1 The equation has two roots −0.381966 and −2.61803
Enter a, b, c: 1 2.0 1 The equation has one root −1.0
Enter a, b, c: 1 2 3 The equation has no real roots
M03_LIAN9966_12_SE_C03.indd 110
3.2 (Game: add three numbers) The program in Listing 3.1, AdditionQuiz.java, gen-
erates two integers and prompts the user to enter the sum of these two integers. Revise the program to generate three single-digit integers and prompt the user to enter the sum of these three integers.
28/09/19 3:54 PM
Programming Exercises 111 Sections 3.3–3.7
*3.3 (Algebra: solve 2 * 2 linear equations) A linear equation can be solved using
Cramer’s rule given in Programming Exercise 1.13. Write a program that prompts the user to enter a, b, c, d, e, and f and displays the result. If ad - bc is 0, report that “The equation has no solution.”
Enter a, b, c, d, e, f: 9.0 4.0 3.0 −5.0 −6.0 −21.0 x is −2.0 and y is 3.0
Enter a, b, c, d, e, f: 1.0 2.0 2.0 4.0 4.0 5.0 The equation has no solution
**3.4 (Random month) Write a program that randomly generates an integer between 1 *3.5
and 12 and displays the English month names January, February, . . . , December for the numbers 1, 2, . . . , 12, accordingly. (Find future dates) Write a program that prompts the user to enter an integer for today’s day of the week (Sunday is 0, Monday is 1, . . . , and Saturday is 6). Also prompt the user to enter the number of days after today for a future day and display the future day of the week. Here is a sample run:
Enter today’s day: 1 Enter the number of days elapsed since today: 3 Today is Monday and the future day is Thursday
Enter today’s day: 0 Enter the number of days elapsed since today: 31 Today is Sunday and the future day is Wednesday
*3.6 (Health application: BMI) Revise Listing 3.4, ComputeAndInterpretBMI.java, to let the user enter weight, feet, and inches. For example, if a person is 5 feet and 10 inches, you will enter 5 for feet and 10 for inches. Here is a sample run:
Enter weight in pounds: 140 Enter feet: 5 Enter inches: 10 BMI is 20.087702275404553 Normal
3.7 (Financial application: monetary units) Modify Listing 2.10, ComputeChange.
M03_LIAN9966_12_SE_C03.indd 111
java, to display the nonzero denominations only, using singular words for single units such as 1 dollar and 1 penny, and plural words for more than one unit such as 2 dollars and 3 pennies.
28/09/19 3:54 PM
112 Chapter 3 Selections *3.8 (Sort three integers) Write a program that prompts the user to enter three integers VideoNote
Sort three integers
**3.9
and display the integers in non-decreasing order. (Business: check ISBN-10) An ISBN-10 (International Standard Book Number) consists of 10 digits: d1d2d3d4d5d6d7d8d9d10. The last digit, d10, is a checksum, which is calculated from the other 9 digits using the following formula: (d1 * 1 + d2 * 2 + d3 * 3 + d4 * 4 + d5 * 5 + d6 * 6 + d7 * 7 + d8 * 8 + d9 * 9),11
If the checksum is 10, the last digit is denoted as X according to the ISBN-10 convention. Write a program that prompts the user to enter the first 9 digits and displays the 10-digit ISBN (including leading zeros). Your program should read the input as an integer. Here are sample runs: Enter the first 9 digits of an ISBN as integer: 013601267 The ISBN-10 number is 0136012671
Enter the first 9 digits of an ISBN as integer: 013031997 The ISBN-10 number is 013031997X
3.10 (Game: addition quiz) Listing 3.3, SubtractionQuiz.java, randomly generates a subtraction question. Revise the program to randomly generate an addition question with two integers less than 100.
Sections 3.8–3.16
*3.11 (Find the number of days in a month) Write a program that prompts the user
3.12
to enter the month and year and displays the number of days in the month. For example, if the user entered month 2 and year 2012, the program should display that February 2012 has 29 days. If the user entered month 3 and year 2015, the program should display that March 2015 has 31 days. (Palindrome integer) Write a program that prompts the user to enter a three-digit integer and determines whether it is a palindrome integer. An integer is palindrome if it reads the same from right to left and from left to right. A negative integer is treated the same as a positive integer. Here are sample runs of this program: Enter a three-digit integer: 121 121 is a palindrome
Enter a three-digit integer: 123 123 is not a palindrome
*3.13 (Financial application: compute taxes) Listing 3.5, ComputeTax.java, gives the 3.14
M03_LIAN9966_12_SE_C03.indd 112
source code to compute taxes for single filers. Complete this program to compute taxes for all filing statuses. (Game: heads or tails) Write a program that lets the user guess whether the flip of a coin results in heads or tails. The program randomly generates an integer 0 or 1, which represents head or tail. The program prompts the user to enter a guess, and reports whether the guess is correct or incorrect.
28/09/19 3:54 PM
Programming Exercises 113 **3.15 (Game: lottery) Revise Listing 3.8, Lottery.java, to generate a lottery of a three-
digit integer. The program prompts the user to enter a three-digit integer and determines whether the user wins according to the following rules:
3.16 *3.17
1. If the user input matches the lottery number in the exact order, the award is $10,000. 2. If all digits in the user input match all digits in the lottery number, the award is $3,000. 3. If one digit in the user input matches a digit in the lottery number, the award is $1,000. (Random point) Write a program that displays a random coordinate in a rectangle. The rectangle is centered at (0, 0) with width 100 and height 200. (Game: scissor, rock, paper) Write a program that plays the popular scissor– rock–paper game. (A scissor can cut a paper, a rock can knock a scissor, and a paper can wrap a rock.) The program randomly generates a number 0, 1, or 2 representing scissor, rock, and paper. The program prompts the user to enter a number 0, 1, or 2 and displays a message indicating whether the user or the computer wins, loses, or draws. Here are sample runs:
scissor (0), rock (1), paper (2): 1 The computer is scissor. You are rock. You won
scissor (0), rock (1), paper (2): 2 The computer is paper. You are paper too. It is a draw
*3.18 (Cost of shipping) A shipping company uses the following function to calculate the cost (in dollars) of shipping based on the weight of the package (in pounds). 3.5, if 0 6 5.5, if 1 6 c(w) = d 8.5, if 3 6 10.5, if 10
**3.19
*3.20
M03_LIAN9966_12_SE_C03.indd 113
w w w 6
6= 1 6= 3 6 = 10 w 6 = 20
Write a program that prompts the user to enter the weight of the package and displays the shipping cost. If the weight is negative or zero, display a message “Invalid input.” If the weight is greater than 20, display a message “The package cannot be shipped.” (Compute the perimeter of a triangle) Write a program that reads three edges for a triangle and computes the perimeter if the input is valid. Otherwise, display that the input is invalid. The input is valid if the sum of every pair of two edges is greater than the remaining edge. (Science: wind-chill temperature) Programming Exercise 2.17 gives a formula to compute the wind-chill temperature. The formula is valid for temperatures in the range between -58°F and 41°F and wind speed greater than or equal to 2. Write a program that prompts the user to enter a temperature and a wind speed. The program displays the wind-chill temperature if the input is valid; otherwise, it displays a message indicating whether the temperature and/or wind speed is invalid.
28/09/19 3:54 PM
114 Chapter 3 Selections Comprehensive
**3.21 (Science: day of the week) Zeller’s congruence is an algorithm developed by Christian Zeller to calculate the day of the week. The formula is
where
h = aq +
j 26(m + 1) k + k + + + 5jb ,7 10 4 4
is the day of the week (0: Saturday, 1: Sunday, 2: Monday, 3: Tuesday, 4: Wednesday, 5: Thursday, and 6: Friday). q is the day of the month. m is the month (3: March, 4: April, ..., 12: December). January and February are counted as months 13 and 14 of the previous year. year j is . 100 k is the year of the century (i.e., year % 100).
■■ h ■■ ■■
■■ ■■
Note all divisions in this exercise perform an integer division. Write a program that prompts the user to enter a year, month, and day of the month, and displays the name of the day of the week. Here are some sample runs: Enter year: (e.g., 2012): 2015 Enter month: 1−12: 1 Enter the day of the month: 1−31: 25 Day of the week is Sunday
Enter year: (e.g., 2012): 2012 Enter month: 1−12: 5 Enter the day of the month: 1−31: 12 Day of the week is Saturday
**3.22 VideoNote
Check point location
(Hint: January and February are counted as 13 and 14 in the formula, so you need to convert the user input 1 to 13 and 2 to 14 for the month and change the year to the previous year. For example, if the user enters 1 for m and 2015 for year, m will be 13 and year will be 2014 used in the formula.) (Geometry: point in a circle?) Write a program that prompts the user to enter a point (x, y) and checks whether the point is within the circle centered at (0, 0) with radius 10. For example, (4, 5) is inside the circle and (9, 9) is outside the circle, as shown in Figure 3.7a. (Hint: A point is in the circle if its distance to (0, 0) is less than or equal to 10. The formula for computing the distance is 2(x2 - x1)2 + (y2 - y1)2. Test your program to cover all cases.) Two sample runs are shown below: Enter a point with two coordinates: 4 5 Point (4.0, 5.0) is in the circle
Enter a point with two coordinates: 9 9 Point (9.0, 9.0) is not in the circle
M03_LIAN9966_12_SE_C03.indd 114
28/09/19 3:54 PM
Programming Exercises 115 y-axis
y-axis (9, 9) (4, 5)
(6, 4) (2, 2)
(0, 0)
x-axis
(a)
(0, 0)
x-axis
(b)
Figure 3.7 (a) Points inside and outside of the circle. (b) Points inside and outside of the rectangle.
**3.23 (Geometry: point in a rectangle?) Write a program that prompts the user to enter a point (x, y) and checks whether the point is within the rectangle centered at (0, 0) with width 10 and height 5. For example, (2, 2) is inside the rectangle and (6, 4) is outside the rectangle, as shown in Figure 3.7b. (Hint: A point is in the rectangle if its horizontal distance to (0, 0) is less than or equal to 10 / 2 and its vertical distance to (0, 0) is less than or equal to 5.0 / 2. Test your program to cover all cases.) Here are two sample runs:
Enter a point with two coordinates: −4.9 2.49 Point (−4.9, 2.49) is in the rectangle
Enter a point with two coordinates: −5.1 −2.4 Point (−5.1, −2.4) is not in the rectangle
**3.24 (Game: pick a card) Write a program that simulates picking a card from a deck of 52 cards. Your program should display the rank (Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King) and suit (Clubs, Diamonds, Hearts, Spades) of the card. Here is a sample run of the program:
The card you picked is Jack of Hearts
*3.25 (Geometry: intersecting point) Two points on line 1 are given as (x1, y1) and
(x2, y2) and on line 2 as (x3, y3) and (x4, y4), as shown in Figure 3.8a and b. The intersecting point of the two lines can be found by solving the following linear equations: (y1 - y2)x - (x1 - x2)y = (y1 - y2)x1 - (x1 - x2)y1 (y3 - y4)x - (x3 - x4)y = (y3 - y4)x3 - (x3 - x4)y3 This linear equation can be solved using Cramer’s rule (see Programming Exercise 3.3). If the equation has no solutions, the two lines are parallel (see
M03_LIAN9966_12_SE_C03.indd 115
28/09/19 3:54 PM
116 Chapter 3 Selections Figure 3.8c). Write a program that prompts the user to enter four points and displays the intersecting point. Here are sample runs: (x2, y2)
(x2, y2)
(x2, y2)
(x3, y3)
(x3, y3) (x3, y3) (x4, y4) (x1, y1)
(x1, y1) (a)
(x4, y4)
(x1, y1)
(b)
(x4, y4) (c)
Figure 3.8 Two lines intersect in (a and b) and two lines are parallel in (c). Enter x1, y1, x2, y2, x3, y3, x4, y4: 2 2 5 −1.0 4.0 2.0 −1.0 −2.0 The intersecting point is at (2.88889, 1.1111)
Enter x1, y1, x2, y2, x3, y3, x4, y4: 2 2 7 6.0 4.0 2.0 −1.0 −2.0 The two lines are parallel
3.26 (Use the &&, ||, and ^ operators) Write a program that prompts the user to
enter an integer and determines whether it is divisible by 5 and 6, whether it is divisible by 5 or 6, and whether it is divisible by 5 or 6, but not both. Here is a sample run of this program:
Enter Is 10 Is 10 Is 10
an integer: 10 divisible by 5 and 6? false divisible by 5 or 6? true divisible by 5 or 6, but not both? true
** 3.27 (Geometry: points in triangle?) Suppose a right triangle is placed in a plane as
shown below. The right-angle point is placed at (0, 0), and the other two points are placed at (200, 0) and (0, 100). Write a program that prompts the user to enter a point with x- and y-coordinates and determines whether the point is inside the triangle. Here are the sample runs:
(0, 100)
p2
p1 (0, 0)
(200, 0)
Enter a point’s x- and y-coordinates: 100.5 25.5 The point is in the triangle
M03_LIAN9966_12_SE_C03.indd 116
28/09/19 3:54 PM
Programming Exercises 117 Enter a point’s x- and y-coordinates: 100.5 50.5 The point is not in the triangle
**3.28 (Geometry: two rectangles) Write a program that prompts the user to enter the center x-, y-coordinates, width, and height of two rectangles and determines whether the second rectangle is inside the first or overlaps with the first, as shown in Figure 3.9. Test your program to cover all cases. w1
w1
w2 h1 h2
(x1, y1)
h1
w2
(x1, y1)
(x2, y2)
h2 (a)
(x2, y2)
(b)
Figure 3.9 (a) A rectangle is inside another one. (b) A rectangle overlaps another one. Here are the sample runs:
Enter r1’s center x-, y-coordinates, width, and height: 2.5 4 2.5 43 Enter r2’s center x-, y-coordinates, width, and height: 1.5 5 0.5 3 r2 is inside r1
Enter r1’s center x-, y-coordinates, width, and height: 1 2 3 5.5 Enter r2’s center x-, y-coordinates, width, and height: 3 4 4.5 5 r2 overlaps r1
Enter r1’s center x-, y-coordinates, width, and height: 1 2 3 3 Enter r2’s center x-, y-coordinates, width, and height: 40 45 3 2 r2 does not overlap r1
**3.29 (Geometry: two circles) Write a program that prompts the user to enter the center
coordinates and radii of two circles and determines whether the second circle is inside the first or overlaps with the first, as shown in Figure 3.10. (Hint: circle2 is inside circle1 if the distance between the two centers 6 = r1 − r2 and circle2 overlaps circle1 if the distance between the two centers 6 = r1 + r2. Test your program to cover all cases.) Here are the sample runs:
Enter circle1’s center x-, y-coordinates, and radius: 0.5 5.1 13 Enter circle2’s center x-, y-coordinates, and radius: 1 1.7 4.5 circle2 is inside circle1
M03_LIAN9966_12_SE_C03.indd 117
28/09/19 3:54 PM
118 Chapter 3 Selections
r1
r1 (x1, y1)
(x1, y1)
r2
r2
(x2, y2) (a)
(x2, y2) (b)
Figure 3.10 (a) A circle is inside another circle. (b) A circle overlaps another circle.
Enter circle1’s center x-, y-coordinates, and radius: 3.4 5.7 5.5 Enter circle2’s center x-, y-coordinates, and radius: 6.7 3.5 3 circle2 overlaps circle1
Enter circle1’s center x-, y-coordinates, and radius: 3.4 5.5 1 Enter circle2’s center x-, y-coordinates, and radius: 5.5 7.2 1 circle2 does not overlap circle1
*3.30 (Current time) Revise Programming Exercise 2.8 to display the hour using a 12-hour clock. Here is a sample run:
Enter the time zone offset to GMT: −5 The current time is 4:50:34 AM
*3.31 (Financials: currency exchange) Write a program that prompts the user to enter
the exchange rate from currency in U.S. dollars to Chinese RMB. Prompt the user to enter 0 to convert from U.S. dollars to Chinese RMB and 1 to convert from C hinese RMB to U.S. dollars. Prompt the user to enter the amount in U.S. dollars or Chinese RMB to convert it to Chinese RMB or U.S. dollars, respectively. Here are the sample runs: Enter the exchange rate from dollars to RMB: 6.81 Enter 0 to convert dollars to RMB and 1 vice versa: 0 Enter the dollar amount: 100 $100.0 is 681.0 yuan
Enter the exchange rate from dollars to RMB: 6.81 Enter 0 to convert dollars to RMB and 1 vice versa: 1 Enter the RMB amount: 10000 10000.0 yuan is $1468.43
M03_LIAN9966_12_SE_C03.indd 118
28/09/19 3:54 PM
Programming Exercises 119 Enter the exchange rate from dollars to RMB: 6.81 Enter 0 to convert dollars to RMB and 1 vice versa: 5 CIncorrect input
*3.32 (Geometry: point position) Given a directed line from point p0(x0, y0) to p1(x1,
y1), you can use the following condition to decide whether a point p2(x2, y2) is on the left of the line, on the right, or on the same line (see Figure 3.11):
7 0 p2 is on the left side of the line (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0) c =0 p2 is on the same line 6 0 p2 is on the right side of the line p1
p1
p1
p2 p2
p0 (a)
p0 (b)
p2 p0 (c)
Figure 3.11 (a) p2 is on the left of the line. (b) p2 is on the right of the line. (c) p2 is on the same line. Write a program that prompts the user to enter the three points for p0, p1, and p2 and displays whether p2 is on the left of the line from p0 to p1, to the right, or on the same line. Here are some sample runs:
Enter three points for p0, p1, and p2: 4.4 2 6.5 9.5 −5 4 p2 is on the left side of the line
Enter three points for p0, p1, and p2: 1 1 5 5 2 2 p2 is on the same line
Enter three points for p0, p1, and p2: 3.4 2 6.5 9.5 5 2.5 p2 is on the right side of the line
*3.33 (Financial: compare costs) Suppose you shop for rice in two different packages. You would like to write a program to compare the cost. The program prompts the user to enter the weight and price of each package and displays the one with the better price. Here is a sample run:
Enter weight and price for package 1: 50 24.59 Enter weight and price for package 2: 25 11.99 Package 2 has a better price.
M03_LIAN9966_12_SE_C03.indd 119
28/09/19 3:54 PM
120 Chapter 3 Selections Enter weight and price for package 1: 50 25 Enter weight and price for package 2: 25 12.5 Two packages have the same price.
*3.34 (Geometry: point on line segment) Exercise 3.32 shows how to test whether a point is on an unbounded line. Revise Exercise 3.32 to test whether a point is on a line segment. Write a program that prompts the user to enter the three points for p0, p1, and p2 and displays whether p2 is on the line segment from p0 to p1. Here are some sample runs:
Enter three points for p0, p1, and p2: 1 1 2.5 2.5 1.5 1.5 (1.5, 1.5) is on the line segment from (1.0, 1.0) to (2.5, 2.5)
Enter three points for p0, p1, and p2: 1 1 2 2 3.5 3.5 (3.5, 3.5) is not on the line segment from (1.0, 1.0) to (2.0, 2.0)
Note More than 200 additional programming exercises with solutions are provided to the instructors on the Instructor Resource Website.
M03_LIAN9966_12_SE_C03.indd 120
28/09/19 3:54 PM
CHAPTER
4 Mathematical Functions, Characters, and Strings Objectives ■■
To solve mathematical problems by using the methods in the Math class (§4.2).
■■
To represent characters using the char type (§4.3).
■■
To encode characters using ASCII and Unicode (§4.3.1).
■■
To represent special characters using the escape sequences (§4.3.2).
■■
To cast a numeric value to a character and cast a character to an integer (§4.3.3).
■■
To compare and test characters using the static methods in the Character class (§4.3.4).
■■
To introduce objects and instance methods (§4.4).
■■
To represent strings using the String object (§4.4).
■■
To return the string length using the length() method (§4.4.1).
■■
To return a character in the string using the charAt(i) method (§4.4.2).
■■
To use the + operator to concatenate strings (§4.4.3).
■■
To return an uppercase string or a lowercase string and to trim a string (§4.4.4).
■■
To read strings from the console (§4.4.5).
■■
To read a character from the console (§4.4.6).
■■
To compare strings using the equals and the compareTo methods (§4.4.7).
■■
To obtain substrings (§4.4.8).
■■
To find a character or a substring in a string using the indexOf method (§4.4.9).
■■
To program using characters and strings (GuessBirthday) (§4.5.1).
■■
To convert a hexadecimal character to a decimal value (HexDigit2Dec) (§4.5.2).
■■
To revise the lottery program using strings (LotteryUsingStrings) (§4.5.3).
■■
To format output using the System.out.printf method (§4.6).
M04_LIAN9966_12_SE_C04.indd 121
30/09/19 3:52 PM
122 Chapter 4 Mathematical Functions, Characters, and Strings
4.1 Introduction Key Point
problem
The focus of this chapter is to introduce mathematical functions, characters, string objects, and use them to develop programs. The preceding chapters introduced fundamental programming techniques and taught you how to write simple programs to solve basic problems using selection statements. This chapter introduces methods for performing common mathematical operations. You will learn how to create custom methods in Chapter 6. Suppose you need to estimate the area enclosed by four cities, given the GPS locations (latitude and longitude) of these cities, as shown in the following diagram. How would you write a program to solve this problem? You will be able to write such a program in this chapter. Charlotte (35.2270869, 280.8431267)
Atlanta (33.7489954, 284.3879824)
Savannah (32.0835407, 281.0998342)
Orlando (28.5383355, 281.3792365)
Because strings are frequently used in programming, it is beneficial to introduce strings early so that you can begin to use them to develop useful programs. This chapter also gives a brief introduction to string objects; you will learn more on objects and strings in Chapters 9 and 10.
4.2 Common Mathematical Functions Key Point
Java provides many useful methods in the Math lass for performing common mathematical functions. A method is a group of statements that performs a specific task. You have already used the pow(a, b) method to compute ab in Section 2.9.4, Exponent Operations and the random() method for generating a random number in Section 3.7. This section introduces other useful methods in the Math class. They can be categorized as trigonometric methods, exponent methods, and service methods. Service methods include the rounding, min, max, absolute, and random methods. In addition to methods, the Math class provides two useful double constants, PI and E (the base of natural logarithms). You can use these constants as Math.PI and Math.E in any program.
4.2.1 Trigonometric Methods VideoNote
Introduce Math functions
The Math class contains the following methods as listed in Table 4.1 for performing trigonometric functions: The parameter for sin, cos, and tan is an angle in radians. The return value for asin and atan is an angle in radians in the range between -p/2 and p/2, and for acos is between 0 and p. One degree is equal to p/180 in radians, 90 degrees is equal to p/2 in radians, and 30 degrees is equal to p/6 in radians. For example, Math.toDegrees(Math.PI / 2) returns 90.0 Math.toRadians(30) returns 0.5236 (same as π/6) Math.sin(0) returns 0.0
M04_LIAN9966_12_SE_C04.indd 122
30/09/19 3:52 PM
4.2 Common Mathematical Functions 123 Table 4.1 Trigonometric Methods in the Math Class Method
Description
sin(radians)
Returns the trigonometric sine of an angle in radians.
cos(radians)
Returns the trigonometric cosine of an angle in radians.
tan(radians)
Returns the trigonometric tangent of an angle in radians.
toRadians(degree)
Returns the angle in radians for the angle in degrees.
toDegrees(radians)
Returns the angle in degrees for the angle in radians.
asin(a)
Returns the angle in radians for the inverse of sine.
acos(a)
Returns the angle in radians for the inverse of cosine.
atan(a)
Returns the angle in radians for the inverse of tangent.
Math.sin(Math.toRadians(270)) returns −1.0 Math.sin(Math.PI / 6) returns 0.5 Math.sin(Math.PI / 2) returns 1.0 Math.cos(0) returns 1.0 Math.cos(Math.PI / 6) returns 0.866 Math.cos(Math.PI / 2) returns 0 Math.asin(0.5) returns 0.523598333 (same as π/6) Math.acos(0.5) returns 1.0472 (same as π/3) Math.atan(1.0) returns 0.785398 (same as π/4)
4.2.2 Exponent Methods There are five methods related to exponents in the Math class as listed in Table 4.2.
Table 4.2 Exponent Methods in the Math Class Method
Description
exp(x)
Returns e raised to power of x (ex).
log(x)
Returns the natural logarithm of x (ln(x) = loge(x)).
log10(x)
Returns the base 10 logarithm of x (log10(x)).
pow(a, b)
Returns a raised to the power of b (ab).
sqrt(x)
Returns the square root of x ( 2x) for x7 =0.
For example, e3.5 is Math.exp(3.5), which returns 33.11545 ln(3.5) is Math.log(3.5), which returns 1.25276 log10 (3.5) is Math.log10(3.5), which returns 0.544 23 is Math.pow(2, 3), which returns 8.0 32 is Math.pow(3, 2), which returns 9.0 4.52.5 is Math.pow(4.5, 2.5), which returns 42.9567 24 is Math.sqrt(4), which returns 2.0 210.5 is Math.sqrt(10.5), which returns 3.24
4.2.3 The Rounding Methods The Math class contains four rounding methods as listed in Table 4.3.
M04_LIAN9966_12_SE_C04.indd 123
30/09/19 3:52 PM
124 Chapter 4 Mathematical Functions, Characters, and Strings Table 4.3 Rounding Methods in the Math Class Method
Description
ceil(x)
x is rounded up to its nearest integer. This integer is returned as a double value.
floor(x)
x is rounded down to its nearest integer. This integer is returned as a double value.
rint(x)
x is rounded to its nearest integer. If x is equally close to two integers, the even one is returned as a double value.
round(x)
Returns (int)Math.floor(x + 0.5) if x is a float and returns (long)Math.floor(x + 0.5) if x is a double.
For example, Math.ceil(2.1) returns 3.0 Math.ceil(2.0) returns 2.0 Math.ceil(−2.0) returns −2.0 Math.ceil(−2.1) returns −2.0 Math.floor(2.1) returns 2.0 Math.floor(2.0) returns 2.0 Math.floor(−2.0) returns −2.0 Math.floor(−2.1) returns −3.0 Math.rint(2.1) returns 2.0 Math.rint(−2.0) returns −2.0 Math.rint(−2.1) returns −2.0 Math.rint(2.5) returns 2.0 Math.rint(3.5) returns 4.0 Math.rint(−2.5) returns −2.0 Math.round(2.6f) returns 3 // Returns int Math.round(2.0) returns 2 // Returns long Math.round(−2.0f) returns −2 // Returns int Math.round(−2.6) returns −3 // Returns long Math.round(−2.4) returns −2 // Returns long
4.2.4 The min, max, and abs Methods The min and max methods return the minimum and maximum numbers of two numbers (int, long, float, or double). For example, max(4.4, 5.0) returns 5.0, and min(3, 2) returns 2. The abs method returns the absolute value of the number (int, long, float, or double). For example, Math.max(2, 3) returns 3 Math.min(2.5, 4.6) returns 2.5 Math.max(Math.max(2.5, 4.6), Math.min(3, 5.6)) returns 4.6 Math.abs(−2) returns 2 Math.abs(−2.1) returns 2.1
4.2.5 The random Method You used the random() method in the preceding chapter. This method generates a random double value greater than or equal to 0.0 and less than 1.0 (0 = 'A' && ch = '0' && ch , >=, number) System.out.println("Your guess is too high"); else System.out.println("Your guess is too low"); } // End of loop
This loop repeatedly prompts the user to enter a guess. However, this loop is not correct, because it never terminates. When guess matches number, the loop should end. Thus, the loop can be revised as follows: while (guess != number) { // Prompt the user to guess the number
M05_LIAN9966_12_SE_C05.indd 164
28/09/19 4:15 PM
5.3 Case Study: Guessing Numbers 165 System.out.print("\nEnter your guess: "); guess = input.nextInt(); if (guess == number) System.out.println("Yes, the number is " + number); else if (guess > number) System.out.println("Your guess is too high"); else System.out.println("Your guess is too low"); } // End of loop
The complete code is given in Listing 5.3.
Listing 5.3 GuessNumber.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
import java.util.Scanner; public class GuessNumber { public static void main(String[] args) { // Generate a random number to be guessed int number = (int)(Math.random() * 101);
generate a number
Scanner input = new Scanner(System.in); System.out.println("Guess a magic number between 0 and 100"); int guess = –1; while (guess != number) { // Prompt the user to guess the number System.out.print("\nEnter your guess: "); guess = input.nextInt(); if (guess == number) System.out.println("Yes, the number is " + number); else if (guess > number) System.out.println("Your guess is too high"); else System.out.println("Your guess is too low"); } // End of loop
enter a guess
too high too low
} }
iteration 1 b iteration 2 b iteration 3 b iteration 4 b
line#
number
6
39
guess
11
−1
15
50
20 15
Your guess is too high 25
22 15
Your guess is too low 42
20 15 18
output
Your guess is too high 39 Yes, the number is 39
The program generates the magic number in line 6 and prompts the user to enter a guess continuously in a loop (lines 12–23). For each guess, the program checks whether the guess is
M05_LIAN9966_12_SE_C05.indd 165
28/09/19 4:15 PM
166 Chapter 5 Loops correct, too high, or too low (lines 17–22). When the guess is correct, the program exits the loop (line 12). Note that guess is initialized to −1. Initializing it to a value between 0 and 100 would be wrong, because that could be the number to be guessed. Check Point
5.3.1 What is wrong if guess is initialized to 0 in line 11 in Listing 5.3?
5.4 Loop Design Strategies Key Point
The key to designing a loop is to identify the code that needs to be repeated and write a condition for terminating the loop. Writing a correct loop is not an easy task for novice programmers. Consider three steps when writing a loop. Step 1: Identify the statements that need to be repeated. Step 2: Wrap these statements in a loop as follows: while (true) { Statements;
} tep 3: Code the loop-continuation-condition and add appropriate statements for S controlling the loop. while (loop-continuation-condition) { Statements; Additional statements for controlling the loop;
}
VideoNote
Multiple subtraction quiz
The Math subtraction learning tool program in Listing 3.3, SubtractionQuiz.java, generates just one question for each run. You can use a loop to generate questions repeatedly. How do you write the code to generate five questions? Follow the loop design strategy. First, identify the statements that need to be repeated. These are the statements for obtaining two random numbers, prompting the user with a subtraction question, and grading the question. Second, wrap the statements in a loop. Third, add a loop control variable and the loop- continuation-condition to execute the loop five times. Listing 5.4 gives a program that generates five questions and, after a student answers all five, reports the number of correct answers. The program also displays the time spent on the test and lists all the questions.
Listing 5.4 SubtractionQuizLoop.java
get start time
loop
M05_LIAN9966_12_SE_C05.indd 166
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
import java.util.Scanner; public class SubtractionQuizLoop { public static void main(String[] args) { final int NUMBER_OF_QUESTIONS = 5; // Number of questions int correctCount = 0; // Count the number of correct answers int count = 0; // Count the number of questions long startTime = System.currentTimeMillis(); String output = " "; // output string is initially empty Scanner input = new Scanner(System.in); while (count < NUMBER_OF_QUESTIONS) { // 1. Generate two random single-digit integers int number1 = (int)(Math.random() * 10); int number2 = (int)(Math.random() * 10); // 2. If number1 < number2, swap number1 with number2 if (number1 < number2) {
28/09/19 4:15 PM
5.4 Loop Design Strategies 167 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
int temp = number1; number1 = number2; number2 = temp; } // 3. Prompt the student to answer "What is number1 – number2?" System.out.print( "What is " + number1 + " – " + number2 + "? "); int answer = input.nextInt(); // 4. Grade the answer and display the result if (number1 – number2 == answer) { System.out.println("You are correct!"); correctCount++; // Increase the correct answer count } else System.out.println("Your answer is wrong.\n" + number1 + " – " + number2 + " should be " + (number1 — number2)); // Increase the question count count++; output += "\n" + number1 + "–" + number2 + "=" + answer + ((number1 – number2 == answer) ? " correct": " wrong");
display a question
grade an answer increase correct count
increase control variable prepare output
}
end loop
long endTime = System.currentTimeMillis(); long testTime = endTime – startTime;
get end time test time
System.out.println("Correct count is " + correctCount + "\nTest time is " + testTime / 1000 + " seconds\n" + output);
display result
} }
What is 9 – 2? 7 You are correct! What is 3 – 0? 3 You are correct! What is 3 – 2? 1 You are correct! What is 7 – 4? 4 Your answer is wrong. 7 – 4 should be 3 What is 7 – 5? 4 Your answer is wrong. 7 – 5 should be 2 Correct count is 3 Test time is 1021 seconds 9–2=7 3–0=3 3–2=1 7–4=4 7–5=4
correct correct correct wrong wrong
M05_LIAN9966_12_SE_C05.indd 167
28/09/19 4:15 PM
168 Chapter 5 Loops The program uses the control variable count to control the execution of the loop. count is initially 0 (line 7) and is increased by 1 in each iteration (line 39). A subtraction question is displayed and processed in each iteration. The program obtains the time before the test starts in line 8 and the time after the test ends in line 45, then computes the test time in line 46. The test time is in milliseconds and is converted to seconds in line 49. Check Point
5.4.1 Revise the code using the System.nanoTime() to measure the time in nano seconds.
5.5 Controlling a Loop with User Confirmation or a Sentinel Value It is a common practice to use a sentinel value to terminate the input. Key Point
The preceding example executes the loop five times. If you want the user to decide whether to continue, you can offer a user confirmation. The template of the program can be coded as follows: char continueLoop = 'Y'; while (continueLoop == 'Y') { // Execute the loop body once ... // Prompt the user for confirmation System.out.print("Enter Y to continue and N to quit: "); continueLoop = input.getLine().charAt(0); }
sentinel value sentinel-controlled loop
You can rewrite the program given in Listing 5.4 with user confirmation to let the user decide whether to advance to the next question. Another common technique for controlling a loop is to designate a special value when reading and processing a set of values. This special input value, known as a sentinel value, signifies the end of the input. A loop that uses a sentinel value to control its execution is called a sentinel-controlled loop. Listing 5.5 gives a program that reads and calculates the sum of an unspecified number of integers. The input 0 signifies the end of the input. Do you need to declare a new variable for each input value? No. Just use one variable named data (line 12) to store the input value, and use a variable named sum (line 15) to store the total. Whenever a value is read, assign it to data and, if it is not zero, add it to sum (line 17).
Listing 5.5 SentinelValue.java
input
loop
M05_LIAN9966_12_SE_C05.indd 168
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
import java.util.Scanner; public class SentinelValue { /** Main method */ public static void main(String[] args) { // Create a Scanner Scanner input = new Scanner(System.in); // Read an initial data System.out.print( "Enter an integer (the input ends if it is 0): "); int data = input.nextInt(); // Keep reading data until the input is 0 int sum = 0; while (data != 0) { sum += data; // Read the next data System.out.print(
28/09/19 4:15 PM
5.5 Controlling a Loop with User Confirmation or a Sentinel Value 169 21 22 23 24 25 26 27
"Enter an integer (the input ends if it is 0): "); data = input.nextInt(); }
end of loop
System.out.println("The sum is " + sum);
display result
} }
Enter an integer (the input ends if it is 0): 2 Enter an integer (the input ends if it is 0): 3 Enter an integer (the input ends if it is 0): 4 Enter an integer (the input ends if it is 0): 0 The sum is 9
iteration 1 b iteration 2 b iteration 3 b
line#
data
12
2
sum
15
0
17
2
22
3
17 22
5 4
17 22
output
9 0
25
The sum is 9
If data is not 0, it is added to sum (line 17) and the next item of input data is read (lines 20–22). If data is 0, the loop body is no longer executed and the while loop terminates. The input value 0 is the sentinel value for this loop. Note if the first input read is 0, the loop body never executes, and the resulting sum is 0.
Caution Don’t use floating-point values for equality checking in a loop control. Because floating-point values are approximations for some values, using them could result in imprecise counter values and inaccurate results. Consider the following code for computing 1 + 0.9 + 0.8 + ... + 0.1: double item = 1; double sum = 0; while (item != 0) { // No guarantee item will be 0 sum += item; item −= 0.1; } System.out.println(sum);
Variable item starts with 1 and is reduced by 0.1 every time the loop body is executed. The loop should terminate when item becomes 0. However, there is no guarantee that item will be exactly 0, because the floating-point arithmetic is approximated. This loop seems okay on the surface, but it is actually an infinite loop.
numeric error
In the preceding example, if you have a large number of data to enter, it would be c umbersome to type from the keyboard. You can store the data separated by whitespaces in a text file, say input.txt, and run the program using the following command: java SentinelValue < input.txt
M05_LIAN9966_12_SE_C05.indd 169
28/09/19 4:15 PM
170 Chapter 5 Loops This command is called input redirection. The program takes the input from the file input. txt rather than having the user type the data from the keyboard at runtime. Suppose the contents of the file are as follows:
input redirection
2 3 4 5 6 7 8 9 12 23 32 23 45 67 89 92 12 34 35 3 1 2 4 0
The program should get sum to be 518. Similarly, there is output redirection, which sends the output to a file rather than displaying it on the console. The command for output redirection is
output redirection
java ClassName > output.txt
Input and output redirections can be used in the same command. For example, the following command gets input from input.txt and sends output to output.txt: java SentinelValue < input.txt > output.txt
Try running the program to see what contents are in output.txt. When reading data through input redirection, you can invoke input.hasNext() to detect the end of input. For example, the following code reads all int value from the input and displays their total. import java.util.Scanner; public class TestEndOfInput { public static void main(String[] args) { // Create a Scanner Scanner input = new Scanner(System.in); int sum = 0; while (input.hasNext ()) { sum += input.nextInt(); } System.out.println(“The sum is “ + sum); } }
If there is no more input in the file, input.hasNext() will return false.
Note If you enter the input from the command window, you can end the input by pressing ENTER and then CTRL+Z, and then pressing ENTER again. In this case, input.hasNext() will return false. Check Point
5.5.1 Suppose the input is 2
3 4 5 0. What is the output of the following code?
import java.util.Scanner; public class Test { public static void main(String[] args) { Scanner input = new Scanner(System.in); int number, max; number = input.nextInt(); max = number; while (number != 0) { number = input.nextInt(); if (number > max) max = number; } System.out.println("max is " + max); System.out.println("number " + number); } }
M05_LIAN9966_12_SE_C05.indd 170
28/09/19 4:15 PM
5.6 The do-while Loop 171
5.6 The do-while Loop A do-while loop is the same as a while loop except that it executes the loop body first then checks the loop continuation condition. The do-while loop is a variation of the while loop. Its syntax is as follows: do { // Loop body; Statement(s); } while (loop-continuation-condition);
Key Point
VideoNote
Its execution flowchart is shown in Figure 5.2a. The loop body is executed first, then the loop-continuation-condition is evaluated. If the evaluation is true, the loop body is executed again; if it is false, the do-while loop terminates. For example, the following while loop statement
Use do-while loop do-while loop
int count = 0; while (count < 100) { System.out.println("Welcome to Java!"); count++; }
can be written using a do-while loop as follows: int count = 0; do { System.out.println("Welcome to Java!"); count++; } while (count < 100);
The flowchart of this do-while loop is shown in Figure 5.2b. The difference between a while loop and a do-while loop is the order in which the loopcontinuation-condition is evaluated and the loop body is executed. In the case of a dowhile loop, the loop body is executed at least once. You can write a loop using either the while loop or the do-while loop. Sometimes one is a more convenient choice than the other. For example, you can rewrite the while loop in Listing 5.5 using a do-while loop, as given in Listing 5.6.
true
Statement(s) Before loop
int count = 0;
Statement(s) (loop body)
System.out.println("Welcome to Java!"); count++;
loopcontinuationcondition false (a)
true
(count < 100)?
false (b)
Figure 5.2 The do-while loop executes the loop body first then checks the loop- continuation-condition to determine whether to continue or terminate the loop.
M05_LIAN9966_12_SE_C05.indd 171
28/09/19 4:15 PM
172 Chapter 5 Loops
Listing 5.6 TestDoWhile.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
loop
end loop
import java.util.Scanner; public class TestDoWhile { /** Main method */ public static void main(String[] args) { int data; int sum = 0; // Create a Scanner Scanner input = new Scanner(System.in); // Keep reading data until the input is 0 do { // Read the next data System.out.print( "Enter an integer (the input ends if it is 0): "); data = input.nextInt(); sum += data; } while (data != 0); System.out.println("The sum is " + sum); } }
Enter an integer (the input ends if it is 0): 3 Enter an integer (the input ends if it is 0): 5 Enter an integer (the input ends if it is 0): 6 Enter an integer (the input ends if it is 0): 0 The sum is 14
Tip Use a do-while loop if you have statements inside the loop that must be executed at least once, as in the case of the do-while loop in the preceding TestDoWhile program. These statements must appear before the loop as well as inside it if you use a while loop. Check Point
5.6.1 Suppose the input is 2
3 4 5 0. What is the output of the following code?
import java.util.Scanner; public class Test { public static void main(String[] args) { Scanner input = new Scanner(System.in); int number, max; number = input.nextInt(); max = number; do { number = input.nextInt(); if (number > max) max = number; } while (number != 0);
M05_LIAN9966_12_SE_C05.indd 172
28/09/19 4:15 PM
5.7 The for Loop 173 System.out.println("max is " + max); System.out.println("number " + number); } }
5.6.2 What are the differences between a while loop and a do-while loop? Convert the following while loop into a do-while loop:
Scanner input = new Scanner(System.in); int sum = 0; System.out.println("Enter an integer " + "(the input ends if it is 0)"); int number = input.nextInt(); while (number != 0) { sum += number; System.out.println("Enter an integer " + "(the input ends if it is 0)"); number = input.nextInt(); }
5.7 The for Loop A for loop has a concise syntax for writing loops. Often you write a loop in the following common form:
Key Point
i = initialValue; // Initialize loop control variable while (i < endValue) { // Loop body ... i++; // Adjust loop control variable }
This loop is intuitive and easy for beginners to grasp. However, programmers often forget to adjust the control variable, which leads to an infinite loop. A for loop can be used to avoid the potential error and simplify the preceding loop as shown in (a) below. In general, the syntax for a for loop is as shown in (a), which is equivalent to (b).
for (i = initialValue; i < endValue; i++) {
i = initialValue; while (i < endValue) {
// Loop body ... }
// Loop body ... i++; } (a)
(b)
In general, the syntax of a for loop is as follows: for (initial-action; loop-continuation-condition; action-after-each-iteration) { // Loop body; Statement(s); }
for loop
The flowchart of the for loop is shown in Figure 5.3a. The for loop statement starts with the keyword for, followed by a pair of parentheses enclosing the control structure of the loop. This structure consists of initial-action, loopcontinuation-condition, and action-after-each-iteration. The control structure is
M05_LIAN9966_12_SE_C05.indd 173
28/09/19 4:15 PM
174 Chapter 5 Loops
Initial-action
loopcontinuationcondition
i = 0;
false
true
(i < 100)?
false
true
Statement(s) (loop body)
System.out.println( "Welcome to Java!");
action-after-each-iteration
i++;
(a)
(b)
Figure 5.3 A for loop performs an initial action once, then repeatedly executes the statements in the loop body, and performs an action after an iteration when the loop- continuation-condition evaluates to true.
control variable
followed by the loop body enclosed inside braces. The initial-action, loop-continuationcondition, and action-after-each-iteration are separated by semicolons. A for loop generally uses a variable to control how many times the loop body is executed and when the loop terminates. This variable is referred to as a control variable. The initialaction often initializes a control variable, the action-after-each-iteration usually increments or decrements the control variable, and the loop-continuation-condition tests whether the control variable has reached a termination value. For example, the following for loop prints Welcome to Java! a hundred times: int i; for (i = 0; i < 100; i++) { System.out.println("Welcome to Java!"); }
initial-action
action-after-each-iteration
omitting braces
M05_LIAN9966_12_SE_C05.indd 174
The flowchart of the statement is shown in Figure 5.3b. The for loop initializes i to 0, then repeatedly executes the println statement and evaluates i++ while i is less than 100. The initial-action, i = 0, initializes the control variable, i. The loop- continuation-condition, i < 100, is a Boolean expression. The expression is evaluated right after the initialization and at the beginning of each iteration. If this condition is true, the loop body is executed. If it is false, the loop terminates and the program control turns to the line following the loop. The action-after-each-iteration, i++, is a statement that adjusts the control variable. This statement is executed after each iteration and increments the control variable. Eventually, the value of the control variable should force the loop-continuation-condition to become false; otherwise, the loop is infinite. The loop control variable can be declared and initialized in the for loop. Here is an example: for (int i = 0; i < 100; i++) { System.out.println("Welcome to Java!"); }
28/09/19 4:15 PM
5.7 The for Loop 175 If there is only one statement in the loop body, as in this example, the braces can be omitted.
Tip The control variable must be declared inside the control structure of the loop or before the loop. If the loop control variable is used only in the loop, and not elsewhere, it is a good programming practice to declare it in the initial-action of the for loop. If the variable is declared inside the loop control structure, it cannot be referenced outside the loop. In the preceding code, for example, you cannot reference i outside the for loop, because it is declared inside the for loop.
declare control variable
Note The initial-action in a for loop can be a list of zero or more comma-separated variable declaration statements or assignment expressions. For example:
for loop variations
for (int i = 0, j = 0; i + j < 10; i++, j++) { // Do something }
The action-after-each-iteration in a for loop can be a list of zero or more comma-separated statements. For example: for (int i = 1; i < 100; System.out.println(i), i++) ;
This example is correct, but it is a bad example, because it makes the code difficult to read. Normally, you declare and initialize a control variable as an initial action, and increment or decrement the control variable as an action after each iteration.
Note If the loop-continuation-condition in a for loop is omitted, it is implicitly true. Thus, the statement given below in (a), which is an infinite loop, is the same as in (b). To avoid confusion, though, it is better to use the equivalent loop in (c). for ( ; ; ) { // Do something }
Equivalent
for ( ; true; ) { // Do something }
(a)
Equivalent
while (true) { // Do something }
This is better
(b)
(c)
5.7.1 Do the following two loops result in the same value in sum? for (int i = 0; i < 10; ++i) {
Check Point
for (int i = 0; i < 10; i++) {
sum += i;
sum += i;
}
} (a)
(b)
5.7.2 What are the three parts of a for loop control? Write a for loop that prints the 5.7.3
numbers from 1 to 100. Suppose the input is 2 3 4 5 0. What is the output of the following code? import java.util.Scanner; public class Test { public static void main(String[] args) { Scanner input = new Scanner(System.in); int number, sum = 0, count; for (count = 0; count < 5; count++) { number = input.nextInt(); sum += number; }
M05_LIAN9966_12_SE_C05.indd 175
28/09/19 4:15 PM
176 Chapter 5 Loops System.out.println("sum is " + sum); System.out.println("count is " + count); } }
5.7.4 What does the following statement do? for ( ; ; ) { // Do something }
5.7.5 If a variable is declared in a for loop control, can it be used after the loop exits? 5.7.6 Convert the following for loop statement to a while loop and to a do-while loop: long sum = 0; for (int i = 0; i num2) return num1; else return num2; } }
Both max(int, double) and max(double, int) are possible candidates to match max(1, 2). Because neither is more specific than the other, the invocation is ambiguous, resulting in a compile error.
6.8.1 What is method overloading? Is it permissible to define two methods that have the
6.8.2
same name but different parameter types? Is it permissible to define two methods in a class that have identical method names and parameter lists, but different return value types or different modifiers? What is wrong in the following program?
Check Point
public class Test { public static void method(int x) { } public static int method(int y) {
M06_LIAN9966_12_SE_C06.indd 223
16/09/19 4:37 PM
224 Chapter 6 Methods return y; } }
6.8.3 Given two method definitions, public static double m(double x, double y) public static double m(int x, double y)
tell which of the two methods is invoked for: a. double z = m(4, 5); b. double z = m(4, 5.4); c. double z = m(4.5, 5.4);
Key Point scope of variables local variable
6.9 The Scope of Variables The scope of a variable is the part of the program where the variable can be referenced. Section 2.5 introduced the scope of a variable. This section discusses the scope of variables in detail. A variable defined inside a method is referred to as a local variable. The scope of a local variable starts from its declaration and continues to the end of the block that contains the variable. A local variable must be declared and assigned a value before it can be used. A parameter is actually a local variable. The scope of a method parameter covers the entire method. A variable declared in the initial-action part of a for-loop header has its scope in the entire loop. However, a variable declared inside a for-loop body has its scope limited in the loop body from its declaration to the end of the block that contains the variable, as shown in Figure 6.5.
The scope of i
public static void method() { . . for (int i = 1; i < 10; i++) { . . int j; . . .
The scope of j
}
}
Figure 6.5 A variable declared in the initial-action part of a for-loop header has its scope in the entire loop. You can declare a local variable with the same name in different blocks in a method, but you cannot declare a local variable twice in the same block or in nested blocks, as shown in Figure 6.6.
Caution A common mistake is to declare a variable in a for loop and then attempt to use it outside the loop. As shown in the following code, i is declared in the for loop, but it is accessed from the outside of the for loop, which causes a syntax error. for (int i = 0; i < 10; i++) { } System.out.println(i); // Causes a syntax error on i
The last statement would cause a syntax error, because variable i is not defined outside of the for loop.
M06_LIAN9966_12_SE_C06.indd 224
16/09/19 4:37 PM
6.10 Case Study: Generating Random Characters 225 public static void method1() { int x = 1; int y = 1; Scope of i
for (int i = 1; i < 10; i++) { x += i; }
Scope of i
for (int i = 1; i < 10; i++) { y += i; } } (a) It is fine to declare i in two nonnested blocks
Scope of i
public static void method2() { int i = 1; int sum = 0; for (int i = 1; i < 10; i++) { sum += i;
Scope of i
} } (b) It is wrong to declare i in two nested blocks
Figure 6.6 A variable can be declared multiple times in nonnested blocks, but only once in nested blocks.
6.9.1 What is a local variable? 6.9.2 What is the scope of a local variable?
Check Point
6.10 Case Study: Generating Random Characters A character is coded using an integer. Generating a random character is to generate an integer.
Key Point
Computer programs process numerical data and characters. You have seen many examples that involve numerical data. It is also important to understand characters and how to process them. This section presents an example of generating random characters. As introduced in Section 4.3, every character has a unique Unicode between 0 and FFFF in hexadecimal (65535 in decimal). To generate a random character is to generate a random integer between 0 and 65535 using the following expression (note since 0 max) { max = myList[i]; indexOfMax = i; } } random shuffling
VideoNote
7. Random shuffling: In many applications, you need to randomly reorder the elements in an array. This is called shuffling. To accomplish this, for each element myList[i], randomly generate an index j and swap myList[i] with myList[j], as follows:
Random shuffling for (int i = 0; i < myList.length – 1; i++) { // Generate an index j randomly int j = (int)(Math.random() * myList.length);
}
// Swap myList[i] with myList[j] double temp = myList[i]; myList[i] = myList[j]; myList[j] = temp;
i
myList [0] . [1] [i]
A random index [j]
. swap
8. Shifting elements: Sometimes you need to shift the elements left or right. Here is an example of shifting the elements one position to the left and filling the last element with the first element: double temp = myList[0]; // Retain the first element // Shift elements left for (int i = 1; i < myList.length; i++) { myList[i - 1] = myList[i]; }
myList
// Move the first element to fill in the last position myList[myList.length - 1] = temp;
9. Simplifying coding: Arrays can be used to greatly simplify coding for certain tasks. For example, suppose you wish to obtain the English name of a given month by its number. If the month names are stored in an array, the month name for a given month can be accessed simply via
M07_LIAN9966_12_SE_C07.indd 254
14/09/19 9:14 AM
7.2 Array Basics 255 the index. The following code prompts the user to enter a month number and displays its month name: String[] months = {"January", "February",..., "December"}; System.out.print("Enter a month number (1 to 12): "); int monthNumber = input.nextInt(); System.out.println("The month is " + months[monthNumber − 1]);
If you didn’t use the months array, you would have to determine the month name using a lengthy multiway if−else statement as follows: if (monthNumber == 1) System.out.println("The month is January"); else if (monthNumber == 2) System.out.println("The month is February"); ... else System.out.println("The month is December");
7.2.7 Foreach Loops Java supports a convenient for loop, known as a foreach loop, which enables you to traverse the array sequentially without using an index variable. For example, the following code displays all the elements in the array myList: for (double e: myList) { System.out.println(e); }
You can read the code as “for each element e in myList, do the following.” Note that the variable, e, must be declared as the same type as the elements in myList. In general, the syntax for a foreach loop is for (elementType element: arrayRefVar) { // Process the element }
You still have to use an index variable if you wish to traverse the array in a different order or change the elements in the array.
Caution Accessing an array out of bounds is a common programming error that throws a runtime ArrayIndexOutOfBoundsException. To avoid it, make sure you do not use an index beyond arrayRefVar.length − 1 or simply using a foreach loop if possible.
ArrayIndexOutOfBoundsException
Programmers often mistakenly reference the first element in an array with index 1, but it should be 0. This is called the off-by-one error. Another common off-by-one error in a loop is using high. public static int binarySearch( int[] list, int key) { int low = 0; int high = list.length − 1;
public static int binarySearch( int[] list, int key) { int low = 0; int high = list.length − 1;
int mid = (low + high) / 2; if (key < list[mid]) high = mid − 1; else if (key == list[mid]) return mid; else low = mid + 1;
while (high >= low) { int mid = (low + high) / 2; if (key < list[mid]) high = mid - 1; else if (key == list[mid]) return mid; else low = mid + 1; }
why not -1?
return -1; // Not found }
} (a) Version 1
(b) Version 2
Figure 7.10 Binary search is implemented incrementally. When the key is not found, low is the insertion point where a key would be inserted to maintain the order of the list. It is more useful to return the insertion point than −1. The method must return a negative value to indicate that the key is not in the list. Can it simply return −low? No. If the key is less than list[0], low would be 0. −0 is 0. This would indicate the key matches list[0]. A good choice is to let the method return −low − 1 if the key is not in the list. Returning −low − 1 indicates not only that the key is not in the list, but also where the key would be inserted.
M07_LIAN9966_12_SE_C07.indd 271
14/09/19 9:14 AM
272 Chapter 7 Single-Dimensional Arrays The complete program is given in Listing 7.7.
Listing 7.7 BinarySearch.java
first half
second half
precondition postcondition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
public class BinarySearch { /** Use binary search to find the key in the list */ public static int binarySearch(int[] list, int key) { int low = 0; int high = list.length − 1; while (high >= low) { int mid = (low + high) / 2; if (key < list[mid]) high = mid − 1; else if (key == list[mid]) return mid; else low = mid + 1; } return –low - 1; // Now high < low, key not found } }
The binary search returns the index of the search key if it is contained in the list (line 12). Otherwise, it returns −low − 1 (line 17). What would happen if we replaced (high >= low) in line 7 with (high > low)? The search would miss a possible matching element. Consider a list with just one element. The search would miss the element. Does the method still work if there are duplicate elements in the list? Yes, as long as the elements are sorted in increasing order. The method returns the index of one of the matching elements if the element is in the list. The precondition for the binary search method is that the list must be sorted in increasing order. The postcondition is that the method returns the index of the element that matches the key if the key is in the list or a negative integer k such that −k - 1 is the position for inserting the key. Precondition and postcondition are the terms often used to describe the properties of a method. Preconditions are the things that are true before the method is invoked, and postconditions are the things that are true after the method is returned: To better understand this method, trace it with the following statements and identify low and high when the method returns. int[] int i int j int k int l int m
list = {2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79}; = BinarySearch.binarySearch(list, 2); // Returns 0 = BinarySearch.binarySearch(list, 11); // Returns 4 = BinarySearch.binarySearch(list, 12); // Returns –6 = BinarySearch.binarySearch(list, 1); // Returns –1 = BinarySearch.binarySearch(list, 3); // Returns –2
Here is the table that lists the low and high values when the method exits, and the value returned from invoking the method. Method
M07_LIAN9966_12_SE_C07.indd 272
Low
High
Value Returned
binarySearch(list, 2)
0
1
0 (mid)
binarySearch(list, 11)
3
5
4 (mid)
binarySearch(list, 12)
5
4
−6
binarySearch(list, 1)
0
−1
−1
binarySearch(list, 3)
1
0
−2
14/09/19 9:14 AM
7.11 Sorting Arrays 273 Note Linear search is useful for finding an element in a small array or an unsorted array, but it is inefficient for large arrays. Binary search is more efficient, but it requires that the array be presorted.
7.10.1 If high is a very large integer such as the maximum int value 2147483647,
(low + high) / 2 may cause overflow. How do you fix it to avoid overflow?
7.10.2 Use Figure 7.9 as an example to show how to apply the binary search approach to a
binary search benefits
Check Point
search for key 10 and key 12 in list {2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79}.
7.10.3 If the binary search method returns −4, is the key in the list? Where should the key be inserted if you wish to insert the key into the list?
7.11 Sorting Arrays Sorting, like searching, is a common task in computer programming. Many different algorithms have been developed for sorting. This section introduces an intuitive sorting algorithm: selection sort. Suppose you want to sort a list in ascending order. Selection sort finds the smallest number in the list and swaps it with the first element. It then finds the smallest number remaining and swaps it with the second element, and so on, until only a single number remains. Figure 7.11 shows how to sort the list {2, 9, 5, 4, 8, 1, 6} using selection sort.
Key Point
VideoNote
Selection sort
swap Select 1 (the smallest) and swap it with 2 (the first) in the list.
2
9
5
4
1
6
8
2
6
Select 2 (the smallest) and swap it with 9 (the first) in the remaining list.
8
swap The number 1 is now in the correct position, and thus no longer needs to be considered.
1
9
5
4
swap The number 2 is now in the correct position, and thus no longer needs to be considered.
1
2
5
4
8
9
6
Select 4 (the smallest) and swap it with 5 (the first) in the remaining list.
The number 4 is now in the correct position, and thus no longer needs to be considered.
1
2
4
5
8
9
6
5 is the smallest and in the right position. No swap is necessary.
6
Select 6 (the smallest) and swap it with 8 (the first) in the remaining list.
swap The number 5 is now in the correct position, and thus no longer needs to be considered.
1
2
4
5
8
9
swap The number 6 is now in the correct position, and thus no longer needs to be considered.
1
2
4
5
6
9
8
Select 8 (the smallest) and swap it with 9 (the first) in the remaining list.
The number 8 is now in the correct position, and thus no longer needs to be considered.
1
2
4
5
6
8
9
Since there is only one element remaining in the list, the sort is completed.
Figure 7.11 Selection sort repeatedly selects the smallest number and swaps it with the first number in the list. You know how the selection-sort approach works. The task now is to implement it in Java. Beginners find it difficult to develop a complete solution on the first attempt. Start by writing the code for the first iteration to find the smallest element in the list and swap it with the first element, then observe what would be different for the second iteration, the third, and so on. The insight this gives will enable you to write a loop that generalizes all the iterations.
M07_LIAN9966_12_SE_C07.indd 273
selection sort animation on Companion Website
14/09/19 9:14 AM
274 Chapter 7 Single-Dimensional Arrays The solution can be described as follows: for (int i = 0; i < list.length − 1; i++) { select the smallest element in list[i..list.length−1]; swap the smallest with list[i], if necessary; // list[i] is in its correct position. // The next iteration applies on list[i+1..list.length−1] }
Listing 7.8 implements the solution.
Listing 7.8 SelectionSort.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
select
swap
public class SelectionSort { /** The method for sorting the numbers */ public static void selectionSort(double[] list) { for (int i = 0; i < list.length - 1; i++) { // Find the minimum in the list[i..list.length−1] double currentMin = list[i]; int currentMinIndex = i; for (int j = i + 1; j < list.length; j++) { if (currentMin > list[j]) { currentMin = list[j]; currentMinIndex = j; } } // Swap list[i] with list[currentMinIndex] if necessary if (currentMinIndex != i) { list[currentMinIndex] = list[i]; list[i] = currentMin; } } } }
The selectionSort(double[] list) method sorts any array of double elements. The method is implemented with a nested for loop. The outer loop (with the loop control variable i in line 4) is iterated in order to find the smallest element in the list, which ranges from list[i] to list[list.length−1], and exchanges it with list[i]. The variable i is initially 0. After each iteration of the outer loop, list[i] is in the right place. Eventually, all the elements are put in the right place; therefore, the whole list is sorted. To understand this method better, trace it with the following statements: double[] list = {1, 9, 4.5, 6.6, 5.7, −4.5}; SelectionSort.selectionSort(list);
Check Point
7.11.1 Use Figure 7.11 as an example to show how to apply the selection-sort approach to sort {3.4, 5, 3, 3.5, 2.2, 1.9, 2}.
7.11.2 How do you modify the selectionSort method in Listing 7.8 to sort numbers in decreasing order?
7.12 The Arrays Class Key Point
M07_LIAN9966_12_SE_C07.indd 274
The java.util.Arrays class contains useful methods for common array operations such as sorting and searching.
14/09/19 9:14 AM
7.12 The Arrays Class 275 The java.util.Arrays class contains various static methods for sorting and searching arrays, comparing arrays, filling array elements, and returning a string representation of the array. These methods are overloaded for all primitive types. You can use the sort or parallelSort method to sort a whole array or a partial array. For example, the following code sorts an array of numbers and an array of characters:
sort parallelSort
double[] numbers = {6.0, 4.4, 1.9, 2.9, 3.4, 3.5}; java.util.Arrays.sort(numbers); // Sort the whole array java.util.Arrays.parallelSort(numbers); // Sort the whole array char[] chars = {'a', 'A', '4', 'F', 'D', 'P'}; java.util.Arrays.sort(chars, 1, 3); // Sort part of the array java.util.Arrays.parallelSort(chars, 1, 3); // Sort part of the array
Invoking sort(numbers) sorts the whole array numbers. Invoking sort(chars, 1, 3) sorts a partial array from chars[1] to chars[3−1]. parallelSort is more efficient if your computer has multiple processors. You can use the binarySearch method to search for a key in an array. The array must be presorted in increasing order. If the key is not in the array, the method returns −(insertionIndex + 1). For example, the following code searches the keys in an array of integers and an array of characters:
binarySearch
int[] list = {2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79}; System.out.println("1. Index is " + java.util.Arrays.binarySearch(list, 11)); System.out.println("2. Index is " + java.util.Arrays.binarySearch(list, 12)); char[] chars = {'a', 'c', 'g', 'x', 'y', 'z'}; System.out.println("3. Index is " + java.util.Arrays.binarySearch(chars, 'a')); System.out.println("4. Index is " + java.util.Arrays.binarySearch(chars, 't'));
The output of the preceding code is as follows: Index is 4 Index is –6 Index is 0 Index is –4
You can use the equals method to check whether two arrays are strictly equal. Two arrays are strictly equal if their corresponding elements are the same. In the following code, list1 and list2 are equal, but list2 and list3 are not. int[] list1 = {2, 4, 7, 10}; int[] list2 = {2, 4, 7, 10}; int[] list3 = {4, 2, 7, 10}; System.out.println(java.util.Arrays.equals(list1, list2)); // true System.out.println(java.util.Arrays.equals(list2, list3)); // false
You can use the fill method to fill in all or part of the array. For example, the following code fills list1 with 5 and fills 8 into elements list2[1] through list2[5−1].
equals
toString fill
int[] list1 = {2, 4, 7, 10}; int[] list2 = {2, 4, 7, 7, 7, 10}; java.util.Arrays.fill(list1, 5); // Fill 5 to the whole array java.util.Arrays.fill(list2, 1, 5, 8); // Fill 8 to a partial array
M07_LIAN9966_12_SE_C07.indd 275
14/09/19 9:14 AM
276 Chapter 7 Single-Dimensional Arrays You can also use the toString method to return a string that represents all elements in the array. This is a quick and simple way to display all elements in the array. For example, the following code: int[] list = {2, 4, 7, 10}; System.out.println(java.util.Arrays.toString(list));
displays [2, 4, 7, 10]. Check Point
7.12.1 What types of array can be sorted using the java.util.Arrays.sort method? Does this sort method create a new array?
7.12.2 To apply java.util.Arrays.binarySearch(array, 7.12.3
key), should the array
be sorted in increasing order, in decreasing order, or neither? Show the output of the following code: int[] list1 = {2, 4, 7, 10}; java.util.Arrays.fill(list1, 7); System.out.println(java.util.Arrays.toString(list1)); int[] list2 = {2, 4, 7, 10}; System.out.println(java.util.Arrays.toString(list2)); System.out.print(java.util.Arrays.equals(list1, list2));
7.13 Command-Line Arguments Key Point
The main method can receive string arguments from the command line. Perhaps you have already noticed the unusual header for the main method, which has the parameter args of the String[] type. It is clear that args is an array of strings. The main method is just like a regular method with a parameter. You can call a regular method by passing actual parameters. Can you pass arguments to main? Yes, of course you can. In the following examples, the main method in class TestMain is invoked by a method in A:
public class A { public static void main(String[] args) { String[] strings = {"New York", "Boston", "Atlanta"}; TestMain.main(strings); } }
public class TestMain { public static void main(String[] args) { for (int i = 0; i < args.length; i++) System.out.println(args[i]); } }
A main method is just like a regular method. Furthermore, you can pass arguments to a main method from the command line.
7.13.1 Passing Strings to the main Method You can pass strings to a main method from the command line when you run the program. The following command line, for example, starts the program TestMain with three strings: arg0, arg1, and arg2: java TestMain arg0 arg1 arg2
arg0, arg1, and arg2 are strings, but they don’t have to appear in double quotes on the command line. The strings are separated by a space. A string that contains a space must be enclosed in double quotes. Consider the following command line: java TestMain "First num" alpha 53
It starts the program with three strings: First num, alpha, and 53. Since First num is a string, it is enclosed in double quotes. Note 53 is actually treated as a string. You can use "53" instead of 53 in the command line.
M07_LIAN9966_12_SE_C07.indd 276
14/09/19 9:14 AM
7.13 Command-Line Arguments 277 When the main method is invoked, the Java interpreter creates an array to hold the command-line arguments and pass the array reference to args. For example, if you invoke a program with n arguments, the Java interpreter creates an array such as the one that follows: args = new String[n];
The Java interpreter then passes args to invoke the main method.
Note If you run the program with no strings passed, the array is created with new String[0]. In this case, the array is empty with length 0. args references to this empty array. Therefore, args is not null, but args.length is 0.
7.13.2 Case Study: Calculator Suppose you are to develop a program that performs arithmetic operations on integers. The program receives an expression. The expression consists of an integer followed by an operator and another integer. For example, to add two integers, use this command: java Calculator 2 + 3
VideoNote
Command-line arguments
The program will display the following output: 2 + 3 = 5
Figure 7.12 shows sample runs of the program. The strings passed to the main program are stored in args, which is an array of strings. The first string is stored in args[0], and args.length is the number of strings passed. Here are the steps in the program: 1. Use args.length to determine whether the expression has been provided as three arguments in the command line. If not, terminate the program using System.exit(1). 2. Perform a binary arithmetic operation on the operands args[0] and args[2] using the operator in args[1].
Add
Subtract
Multiply
Divide
Figure 7.12 The program takes three arguments (operand1 operator operand2) from the command line and displays the expression and the result of the arithmetic operation.
M07_LIAN9966_12_SE_C07.indd 277
14/09/19 9:14 AM
278 Chapter 7 Single-Dimensional Arrays The program is given in Listing 7.9.
Listing 7.9 Calculator.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
check argument
check operator
public class Calculator { /** Main method */ public static void main(String[] args) { // Check number of strings passed if (args.length != 3) { System.out.println( "Usage: java Calculator operand1 operator operand2"); System.exit(1); } // The result of the operation int result = 0; // Determine the operator switch (args[1].charAt(0)) { case '+': result = Integer.parseInt(args[0]) + Integer.parseInt(args[2]); break; case '−': result = Integer.parseInt(args[0]) − Integer.parseInt(args[2]); break; case '.': result = Integer.parseInt(args[0]) * Integer.parseInt(args[2]); break; case '/': result = Integer.parseInt(args[0]) / Integer.parseInt(args[2]); } // Display result System.out.println(args[0] + ' ' + args[1] + ' ' + args[2] + " = " + result); } }
Integer.parseInt(args[0]) (line 16) converts a digital string into an integer. The string must consist of digits. If not, the program will terminate abnormally. We used the . symbol for multiplication, not the common * symbol. The reason for this is the * symbol refers to all the files in the current directory when it is used on a command line. The following program displays all the files in the current directory when issuing the command java Test *: public class Test { public static void main(String[] args) { for (int i = 0; i < args.length; i++) System.out.println(args[i]); } }
To circumvent this problem, we will have to use a different symbol for the multiplication operator. Check Point
7.13.1 This book declares the main method as public static void main(String[] args)
Can it be replaced by one of the following lines? a. public static void main(String args[]) b. public static void main(String[] x)
M07_LIAN9966_12_SE_C07.indd 278
14/09/19 9:14 AM
Chapter Summary 279 c. public static void main(String x[]) d. static void main(String x[])
7.13.2 Show the output of the following program when invoked using 1. java Test I have a dream 2. java Test “1 2 3” 3. java Test public class Test { public static void main(String[] args) { System.out.println("Number of strings is " + args.length); for (int i = 0; i < args.length; i++) System.out.println(args[i]); } }
Key Terms anonymous array 262 array 250 array initializer 252 binary search 269 garbage collection 260 index 250
indexed variable 252 linear search 269 off-by-one error 255 postcondition 272 precondition 272 selection sort 273
Chapter Summary 1. A variable is declared as an array type using the syntax elementType[]
arrayRefVar
or elementType arrayRefVar[]. The style elementType[] arrayRefVar is preferred, although elementType arrayRefVar[] is legal.
2. Unlike declarations for primitive data type variables, the declaration of an array variable does not allocate any space in memory for the array. An array variable is not a primitive data type variable. An array variable contains a reference to an array.
3. You cannot assign elements to an array unless it has already been created. You can create an array by using the new operator with the following syntax: new elementType[arraySize].
4. Each element in the array is represented using the syntax arrayRefVar[index]. An index must be an integer or an integer expression.
5. After an array is created, its size becomes permanent and can be obtained using
arrayRefVar.length. Since the index of an array always begins with 0, the last index is always arrayRefVar.length − 1. An out-of-bounds error will occur if you
attempt to reference elements beyond the bounds of an array.
6. Programmers often mistakenly reference the first element in an array with index 1, but it should be 0. This is called the index off-by-one error.
M07_LIAN9966_12_SE_C07.indd 279
14/09/19 9:14 AM
280 Chapter 7 Single-Dimensional Arrays 7. When an array is created, its elements are assigned the default value of 0 for the numeric primitive data types, \u0000 for char types, and false for boolean types.
8. Java has a shorthand notation, known as the array initializer, which combines declaring an array, creating an array, and initializing an array in one statement, using the syntax elementType[] arrayRefVar = {value0, value1, . . . , valuek}.
9. When you pass an array argument to a method, you are actually passing the reference of
the array; that is, the called method can modify the elements in the caller’s original array.
10. If an array is sorted, binary search is more efficient than linear search for finding an element in the array.
11. Selection sort finds the smallest number in the list and swaps it with the first element. It then finds the smallest number remaining and swaps it with the first element in the remaining list, and so on, until only a single number remains.
Quiz Answer the quiz for this chapter online at the Companion Website.
Programming Exercises Sections 7.2–7.5
*7.1 (Assign grades) Write a program that reads student scores, gets the best score, and
then assigns grades based on the following scheme: Grade is A if score is Ú best -10; Grade is B if score is Ú best -20; Grade is C if score is Ú best -30; Grade is D if score is Ú best -40; Grade is F otherwise. The program prompts the user to enter the total number of students, then prompts the user to enter all of the scores, and concludes by displaying the grades. Here is a sample run:
Enter the number of students: 4 Enter 4 scores: 40 55 70 58 Student 0 score is 40 and grade Student 1 score is 55 and grade Student 2 score is 70 and grade Student 3 score is 58 and grade
M07_LIAN9966_12_SE_C07.indd 280
is is is is
C B A B
7.2 (Reverse the numbers entered) Write a program that reads 10 integers then displays them in the reverse of the order in which they were read.
14/09/19 9:14 AM
Programming Exercises 281 **7.3 (Count occurrence of numbers) Write a program that reads the integers between
1 and 100 and counts the occurrences of each. Assume the input ends with 0. Here is a sample run of the program: Note that if a number occurs more than one time, the plural word “times” is used in the output. Numbers are displayed in increasing order.
Enter the integers between 1 and 100: 2 5 6 5 4 3 23 43 2 0 2 occurs 2 times 3 occurs 1 time 4 occurs 1 time 5 occurs 2 times 6 occurs 1 time 23 occurs 1 time 43 occurs 1 time
7.4 (Analyze scores) Write a program that reads an unspecified number of scores and
**7.5
determines how many scores are above or equal to the average, and how many scores are below the average. Enter a negative number to signify the end of the input. Assume the maximum number of scores is 100. (Print distinct numbers) Write a program that reads in 10 numbers and displays the number of distinct numbers and the distinct numbers in their input order and separated by exactly one space (i.e., if a number appears multiple times, it is displayed only once). (Hint: Read a number and store it to an array if it is new. If the number is already in the array, ignore it.) After the input, the array contains the distinct numbers. Here is the sample run of the program:
Enter 10 numbers: 1 2 3 2 1 6 3 4 5 2 The number of distinct numbers is 6 The distinct numbers are: 1 2 3 6 4 5
*7.6 (Revise Listing 5.15, PrimeNumber.java) Listing 5.15 determines whether a num-
*7.7
ber n is prime by checking whether 2, 3, 4, 5, 6, . . . , n/2 is a divisor. If a divisor is found, n is not prime. A more efficient approach is to check whether any of the prime numbers less than or equal to 2n can divide n evenly. If not, n is prime. Rewrite Listing 5.15 to display the first 50 prime numbers using this approach. You need to use an array to store the prime numbers, and later use them to check whether they are possible divisors for n. (Count single digits) Write a program that generates 100 random integers between 0 and 9 and displays the count for each number. (Hint: Use an array of 10 integers, say counts, to store the counts for the number of 0s, 1s, . . . , 9s.)
Sections 7.6–7.8
7.8 (Average an array) Write two overloaded methods that return the average of an array with the following headers:
public static double average(int[] array) public static double average(double[] array)
Write a test program that prompts the user to enter 10 integers, invokes the first method, then displays the average value; prompts the user to enter 10 double values, invokes the second method, then displays the average value.
M07_LIAN9966_12_SE_C07.indd 281
14/09/19 9:14 AM
282 Chapter 7 Single-Dimensional Arrays
7.9 (Find the smallest element) Write a method that finds the smallest element in an array of double values using the following header:
public static double min(double[] array)
Write a test program that prompts the user to enter 10 numbers, invokes this method to return the minimum value, and displays the minimum value. Here is a sample run of the program:
Enter 10 numbers: 1.9 2.5 3.7 2 1.5 6 3 4 5 2 The minimum number is 1.5
7.10 (Find the index of the smallest element) Write a method that returns the index of
the smallest element in an array of integers. If the number of such elements is greater than 1, return the smallest index. Use the following header: public static int indexOfSmallestElement(double[] array)
Write a test program that prompts the user to enter 10 numbers, invokes this method to return the index of the smallest element, and displays the index. *7.11 (Statistics: compute deviation) Programming Exercise 5.45 computes the standard deviation of numbers. This exercise uses a different but equivalent formula to compute the standard deviation of n numbers. a xi
2 a (xi - mean)
n
mean =
i=1
n
n
x1 + x2 + g + xn = n
deviation =
i=1
H
n - 1
To compute the standard deviation with this formula, you have to store the individual numbers using an array, so they can be used after the mean is obtained. Your program should contain the following methods: /** Compute the deviation of double values */ public static double deviation(double[] x) /** Compute the mean of an array of double values */ public static double mean(double[] x)
Write a test program that prompts the user to enter 10 numbers and displays the mean and standard deviation, as presented in the following sample run:
Enter 10 numbers: 1.9 2.5 3.7 2 1 6 3 4 5 2 The mean is 3.11 The standard deviation is 1.55738
*7.12 (Reverse an array) The reverse method in Section 7.7 reverses an array by
c opying it to a new array. Rewrite the method that reverses the array passed in the argument and returns this array. Write a test program that prompts the user to enter 10 numbers, invokes the method to reverse the numbers, and displays the numbers.
M07_LIAN9966_12_SE_C07.indd 282
14/09/19 9:14 AM
Programming Exercises 283 Section 7.9
*7.13 (Random number chooser) Write the following method that returns a random number between start and end, excluding the numbers.
public static int getRandom(int start, int end, int... numbers)
For example, invoking getRandom(1,100,4,8,95,93) returns a random number between 1 and 100 excluding 4,8,95,and 93. Write a test program that invokes getRandom(1,100,4,8,95,93) 45 times and displays the resulting numbers 15 per line using the format %4d. 7.14 (Compute gcd) Write a method that returns the gcd of an unspecified number of integers. The method header is specified as follows: public static int gcd(int... numbers)
Write a test program that prompts the user to enter five numbers, invokes the method to find the gcd of these numbers, and displays the gcd.
Sections 7.10–7.12
7.15 (Eliminate duplicates) Write a method that returns a new array by eliminating the duplicate values in the array using the following method header:
public static int[] eliminateDuplicates(int[] list)
Write a test program that reads in 10 integers, invokes the method, and displays the distinct numbers separated by exactly one space. Here is a sample run of the program: Enter 10 numbers: 1 2 3 2 1 6 3 4 5 2 The distinct numbers are: 1 2 3 6 4 5
7.16 (Execution time) Write a program that randomly generates an array of 100,000
integers and a key. Estimate the execution time of invoking the linearSearch method in Listing 7.6. Sort the array and estimate the execution time of invoking the binarySearch method in Listing 7.7. You can use the following code template to obtain the execution time: long startTime = System.nanoTime(); perform the task; long endTime = System.nanoTime(); long executionTime = endTime − startTime;
**7.17 (Sort students) Write a program that prompts the user to enter the number of stu-
**7.18
M07_LIAN9966_12_SE_C07.indd 283
dents, the students’ names, and their scores and prints student names in decreasing order of their scores. Assume the name is a string without spaces, use the Scan ner’s next() method to read a name. (Bubble sort) Write a sort method that uses the bubble-sort algorithm. The bubble-sort algorithm makes several passes through the array. On each pass, successive neighboring pairs are compared. If a pair is not in order, its values are swapped; otherwise, the values remain unchanged. The technique is called a bubble sort or sinking sort because the smaller values gradually “bubble” their way to the top, and the larger values “sink” to the bottom. Write a test program that reads in 10 double numbers, invokes the method, and displays the sorted numbers.
14/09/19 9:14 AM
284 Chapter 7 Single-Dimensional Arrays **7.19 (Sorted?) Write the following method that returns true if the list is already sorted in nondecreasing order:
public static boolean isSorted(int[] list)
Write a test program that prompts the user to enter a list and displays whether the list is sorted or not. Here is a sample run. Note that the program first prompts the user to enter the size of the list. Enter the size of the list: 8 Enter the contents of the list: 10 1 5 16 61 9 11 1 The list has 8 integers 10 1 5 16 61 9 11 1 The list is not sorted
Enter the size of the list: 10 Enter the contents of the list: 1 1 3 4 4 5 7 9 11 21 The list has 10 integers 1 1 3 4 4 5 7 9 11 21 The list is already sorted
*7.20 (Revise selection sort) In Listing 7.8, you used selection sort to sort an array. The
selection-sort method repeatedly finds the smallest number in the current array and swaps it with the first. Rewrite this program by finding the largest number and swapping it with the last. Write a test program that reads in 10 double numbers, invokes the method, and displays the sorted numbers.
Section 7.13
*7.21 (Sum integers) Write a program that passes an unspecified number of integers from *7.22
command line and displays their total. (Find the number of uppercase letters in a string) Write a program that passes a string to the command line and displays the number of uppercase letters in the string.
Comprehensive
**7.23 (Game: locker puzzle) A school has 100 lockers and 100 students. All lockers are
VideoNote
Coupon collector's problem
M07_LIAN9966_12_SE_C07.indd 284
closed on the first day of school. As the students enter, the first student, denoted as S1, opens every locker. Then the second student, S2, begins with the second locker, denoted as L2, and closes every other locker. Student S3 begins with the third locker and changes every third locker (closes it if it was open and opens it if it was closed). Student S4 begins with locker L4 and changes every fourth locker. Student S5 starts with L5 and changes every fifth locker, and so on, until student S100 changes L100. After all the students have passed through the building and changed the lockers, which lockers are open? Write a program to find your answer and display all open locker numbers separated by exactly one space. (Hint: Use an array of 100 Boolean elements, each of which indicates whether a locker is open (true) or closed (false). Initially, all lockers are closed.) **7.24 (Simulation: coupon collector’s problem) Coupon collector is a classic s tatistics problem with many practical applications. The problem is to repeatedly pick objects from a set of objects and find out how many picks are needed for all the objects to be picked at least once. A variation of the problem is to pick cards from a shuffled deck of 52 cards repeatedly, and find out how many picks are needed before you see one of each suit. Assume a picked card is placed back in the deck
14/09/19 9:14 AM
Programming Exercises 285 before picking another. Write a program to simulate the number of picks needed to get four cards from each suit and display the four cards picked (it is possible a card may be picked twice). Here is a sample run of the program: Queen of Spades 5 of Clubs Queen of Hearts 4 of Diamonds Number of picks: 12
7.25 (Algebra: solve quadratic equations) Write a method for solving a quadratic equation using the following header:
public static int solveQuadratic(double[] eqn, double[] roots)
The coefficients of a quadratic equation ax2 + bx + c = 0 are passed to the array eqn and the real roots are stored in roots. The method returns the number of real roots. See Programming Exercise 3.1 on how to solve a quadratic equation. Write a program that prompts the user to enter values for a, b, and c and displays the number of real roots and all real roots. 7.26 (Strictly identical arrays) The arrays list1 and list2 are strictly identical if their corresponding elements are equal. Write a method that returns true if list1 and list2 are strictly identical, using the following header: public static boolean equals(int[] list1, int[] list2)
Write a test program that prompts the user to enter two lists of integers and displays whether the two are strictly identical. Here are the sample runs. Note the first number in the input for each list indicates the number of the elements in the list. This number is not part of the list.
Enter list1 size and contents: 5 2 5 6 1 6 Enter list2 size and contents: 5 2 5 6 1 6 Two lists are strictly identical
Enter list1 size and contents: 5 2 5 6 6 1 Enter list2 size and contents: 5 2 5 6 1 6 Two lists are not strictly identical
7.27 (Identical arrays) The arrays list1 and list2 are identical if they have the same contents. Write a method that returns true if list1 and list2 are identical, using the following header: public static boolean equals(int[] list1, int[] list2)
Write a test program that prompts the user to enter two lists of integers and displays whether the two are identical. Here are the sample runs. Note the first number in the input for each list indicates the number of the elements in the list. This number is not part of the list.
M07_LIAN9966_12_SE_C07.indd 285
14/09/19 9:14 AM
286 Chapter 7 Single-Dimensional Arrays Enter list1 size and contents: 5 2 5 6 6 1 Enter list2 size and contents: 5 5 2 6 1 6 Two lists are identical
Enter list1: 5 5 5 6 6 1 Enter list2: 5 2 5 6 1 6 Two lists are not identical
**7.28 (Math: combinations) Write a program that prompts the user to enter 10 integers **7.29
and displays all combinations of picking two numbers from the 10 numbers. (Game: pick four cards) Write a program that picks four cards from a deck of 52 cards and computes their sum. An Ace, King, Queen, and Jack represent 1, 13, 12, and 11, respectively. Your program should display the number of picks that yields the sum of 24.
*7.30 (Pattern recognition: consecutive four equal numbers) Write the following method that tests whether the array has four consecutive numbers with the same value:
VideoNote
Consecutive four
public static boolean isConsecutiveFour(int[] values)
Write a test program that prompts the user to enter a series of integers and displays it if the series contains four consecutive numbers with the same value. Your program should first prompt the user to enter the input size—i.e., the number of values in the series. Here are sample runs: Enter the number of values: 8 Enter the values: 3 4 5 5 5 5 4 5 The list has consecutive fours
Enter the number of values: 9 Enter the values: 3 4 5 5 6 5 5 4 5 The list has no consecutive fours
**7.31 (Merge two sorted lists) Write the following method that merges two sorted lists into a new sorted list:
public static int[] merge(int[] list1, int[] list2)
Implement the method in a way that takes at most list1.length + list2. l e n g t h comparisons. See liveexample.pearsoncmg.com/dsanimation/ MergeSortNeweBook.html for an animation of the implementation. Write a test program that prompts the user to enter two sorted lists and displays the merged list. Here is a sample run. Note the first number in the input indicates the number of the elements in the list. This number is not part of the list. Enter list1 size and contents: 5 1 5 16 61 111 Enter list2 size and contents: 4 2 4 5 6 list1 is 1 5 16 61 111 list2 is 2 4 5 6 The merged list is 1 2 4 5 5 6 16 61 111
M07_LIAN9966_12_SE_C07.indd 286
14/09/19 9:14 AM
Programming Exercises 287 **7.32 (Partition of a list) Write the following method that partitions the list using the first element, called a pivot:
public static int partition(int[] list)
After the partition, the elements in the list are rearranged so all the elements before the pivot are less than or equal to the pivot, and the elements after the pivot are greater than the pivot. The method returns the index where the pivot is located in the new list. For example, suppose the list is {5, 2, 9, 3, 6, 8}. After the partition, the list becomes {3, 2, 5, 9, 6, 8}. Implement the method in a way that takes at most list.length comparisons. See liveexample.pearsoncmg.com/dsanimation/QuickSortNeweBook.html for an animation of the implementation. Write a test program that prompts the user to enter the size of the list and the contents of the list and displays the list after the partition. Here is a sample run.
Enter list size: 8 Enter list content: 10 1 5 16 61 9 11 1 After the partition, the list is 9 1 5 1 10 61 11 16
*7.33 (Culture: Chinese Zodiac) Simplify Listing 3.9 using an array of strings to store the animal names.
**7.34 (Sort characters in a string) Write a method that returns a sorted string using the following header:
public static String sort(String s)
For example, sort("acb") returns abc. Write a test program that prompts the user to enter a string and displays the sorted string. ***7.35 (Game: hangman) Write a hangman game that randomly generates a word and prompts the user to guess one letter at a time, as presented in the sample run. Each letter in the word is displayed as an asterisk. When the user makes a correct guess, the actual letter is then displayed. When the user finishes a word, display the number of misses and ask the user whether to continue to play with another word. Declare an array to store words, as follows: // Add any words you wish in this array String[] words = {"write", "that",...};
(Guess) Enter a letter in word ******* > (Guess) Enter a letter in word p****** > (Guess) Enter a letter in word pr**r** > p is already in the word (Guess) Enter a letter in word pr**r** > (Guess) Enter a letter in word pro*r** > (Guess) Enter a letter in word progr** > n is not in the word (Guess) Enter a letter in word progr** > (Guess) Enter a letter in word progr*m > The word is program. You missed 1 time Do you want to guess another word? Enter
M07_LIAN9966_12_SE_C07.indd 287
p r p o g n m a y or n>
14/09/19 9:14 AM
288 Chapter 7 Single-Dimensional Arrays ***7.36 (Game: Eight Queens) The classic Eight Queens puzzle is to place eight queens on a
chessboard such that no two queens can attack each other (i.e., no two queens are on the same row, same column, or same diagonal). There are many possible solutions. Write a program that displays one such solution. A sample output is shown below: |Q| | | | | | | | | | | | |Q| | | | | | | | | | | |Q| | | | | | |Q| | | | | |Q| | | | | | | | | | | | |Q| | | |Q| | | | | | | | | | |Q| | | | |
*** 7.37 (Game: bean machine) The bean machine, also known as a quincunx or the Galton box, is a device for statistics experiments named after English scientist Sir Francis Galton. It consists of an upright board with evenly spaced nails (or pegs) in a triangular form, as shown in Figure 7.13.
(a)
(b)
(c)
Balls are dropped from the opening of the board. Every time a ball hits a nail, it has a 50% chance of falling to the left or to the right. The piles of balls are accumulated in the slots at the bottom of the board. Write a program that simulates the bean machine. Your program should prompt the user to enter the number of the balls and the number of the slots in the machine. Simulate the falling of each ball by printing its path. For example, the path for the ball in Figure 7.13b is LLRRLLR and the path for the ball in Figure 7.13c is RLRRLRR. Display the final buildup of the balls in the slots in a histogram. Here is a sample run of the program: (Hint: Create an array named slots. Each element in slots stores the number of balls in a slot. Each ball falls into a slot via a path. The number of Rs in a path is the position of the slot where the ball falls. For example, for the path LRLRLRR, the ball falls into slots[4], and for the path RRLLLLL, the ball falls into slots[2].) Enter the number of balls to drop: 5 Enter the number of slots in the bean machine: 8 LRLRLRR RRLLLRR LLRLLRR RRLLLLL LRLRRLR O O OOO
M07_LIAN9966_12_SE_C07.indd 288
14/09/19 9:14 AM
CHAPTER
8 Multidimensional Arrays Objectives ■■
To give examples of representing data using two-dimensional arrays (§8.1).
■■
To declare variables for two-dimensional arrays, create arrays, and access array elements in a two-dimensional array using row and column indices (§8.2).
■■
To program common operations for two-dimensional arrays (displaying arrays, summing all elements, finding the minimum and maximum elements, and random shuffling) (§8.3).
■■
To pass two-dimensional arrays to methods (§8.4).
■■
To write a program for grading multiple-choice questions using two-dimensional arrays (§8.5).
■■
To solve the closest pair problem using two-dimensional arrays (§8.6).
■■
To check a Sudoku solution using two-dimensional arrays (§8.7).
■■
To use multidimensional arrays (§8.8).
M08_LIAN9966_12_SE_C08.indd 289
21/09/19 3:47 PM
290 Chapter 8 Multidimensional Arrays
8.1 Introduction Data in a table or a matrix can be represented using a two-dimensional array. Key Point
problem
A two-dimensional array is an array that contains other arrays as its elements. The preceding chapter introduced how to use one-dimensional arrays to store linear collections of elements. You can use a two-dimensional array to store a matrix or a table. For example, the following table that lists the distances between cities can be stored using a two-dimensional array named distances. Distance Table (in miles) Chicago Chicago Boston New York Atlanta Miami Dallas Houston
Boston
New York
Atlanta
Miami
Dallas
Houston
0
983
787
714
1375
967
1087
983
0
214
1102
1763
1723
1842
787 714 1375 967 1087
214 1102 1763 1723 1842
0 888 1549 1548 1627
888 0 661 781 810
1549 661 0 1426 1187
1548 781 1426 0 239
1627 810 1187 239 0
double[][] distances = { {0, 983, 787, 714, 1375, 967, 1087}, {983, 0, 214, 1102, 1763, 1723, 1842}, {787, 214, 0, 888, 1549, 1548, 1627}, {714, 1102, 888, 0, 661, 781, 810}, {1375, 1763, 1549, 661, 0, 1426, 1187}, {967, 1723, 1548, 781, 1426, 0, 239}, {1087, 1842, 1627, 810, 1187, 239, 0}, };
Each element in the distances array is another array, so distances is considered a nested array. In this example, a two-dimensional array is used to store two-dimensional data.
8.2 Two-Dimensional Array Basics An element in a two-dimensional array is accessed through a row and a column index. Key Point
How do you declare a variable for two-dimensional arrays? How do you create a two- dimensional array? How do you access elements in a two-dimensional array? This section will address these issues.
8.2.1 Declaring Variables of Two-Dimensional Arrays and Creating Two-Dimensional Arrays The syntax for declaring a two-dimensional array is as follows: elementType[][] arrayRefVar;
or elementType arrayRefVar[][]; // Allowed, but not preferred
As an example, here is how you would declare a two-dimensional array variable matrix of int values: int[][] matrix;
M08_LIAN9966_12_SE_C08.indd 290
21/09/19 3:47 PM
8.2 Two-Dimensional Array Basics 291 or int matrix[][]; // This style is allowed, but not preferred
You can create a two-dimensional array of 5-by-5 int values and assign it to matrix using this syntax: matrix = new int[5][5];
Two subscripts are used in a two-dimensional array: one for the row, and the other for the column. The two subscripts are conveniently called row index and column index. As in a one-dimensional array, the index for each subscript is of the int type and starts from 0, as shown in Figure 8.1a. [0][1][2][3][4]
[0][1][2][3][4]
[0][1][2]
[0] 0
0
0
0
0
[0] 0
0
0
0
0
[0] 1
2
3
[1] 0
0
0
0
0
[1] 0
0
0
0
0
[1] 4
5
6
[2] 0
0
0
0
0
[2] 0
7
0
0
0
[2] 7
8
9
[3] 0
0
0
0
0
[3] 0
0
0
0
0
[3] 10 11 12
[4] 0
0
0
0
0
[4] 0
0
0
0
0
matrix = new int[5][5];
matrix[2][1] = 7;
(a)
(b)
row index column index
int[][] array = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12} }; (c)
Figure 8.1 The index of each subscript of a two-dimensional array is an int value, starting from 0. To assign the value 7 to a specific element at row index 2 and column index 1, as shown in Figure 8.1b, you can use the following syntax: matrix[2][1] = 7;
Caution It is a common mistake to use matrix[2, 1] to access the element at row 2 and column 1. In Java, each subscript must be enclosed in a pair of square brackets.
You can also use an array initializer to declare, create, and initialize a two-dimensional array. For example, the following code in (a) creates an array with the specified initial values, as shown in Figure 8.1c. This is equivalent to the code in (b). int[][] array = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12} }; (a)
Equivalent
int[][] array array[0][0] = array[1][0] = array[2][0] = array[3][0] =
= new int[4][3]; 1; array[0][1] = 2; array[0][2] = 4; array[1][1] = 5; array[1][2] = 7; array[2][1] = 8; array[2][2] = 10; array[3][1] = 11; array[3][2]
3; 6; 9; = 12;
(b)
8.2.2 Obtaining the Lengths of Two-Dimensional Arrays A two-dimensional array is actually an array in which each element is a one-dimensional array. The length of an array x is the number of elements in the array, which can be obtained using x. length. x[0], x[1], . . . , and x[x.length − 1] are arrays. Their lengths can be obtained using x[0].length, x[1].length, . . . , and x[x.length − 1].length.
M08_LIAN9966_12_SE_C08.indd 291
21/09/19 3:47 PM
292 Chapter 8 Multidimensional Arrays For example, suppose that x = new int[3][4], x[0], x[1], and x[2] are one- dimensional arrays and each contains four elements, as shown in Figure 8.2. x.length is 3, and x[0].length, x[1].length, and x[2].length are 4. x
x[0][0] x[0][1] x[0][2] x[0][3]
x[0].length is 4
x[1][0] x[1][1] x[1][2] x[1][3]
x[1].length is 4
x[2][0] x[2][1] x[2][2] x[2][3]
x[2].length is 4
x[0] x[1] x[2] x.length is 3
Figure 8.2 A two-dimensional array is a one-dimensional array in which each element is another one-dimensional array.
8.2.3 Ragged Arrays ragged array
Each row in a two-dimensional array is itself an array. Thus, the rows can have different lengths. An array of this kind is known as a ragged array. Here is an example of creating a ragged array: int[][] triangleArray = { {1, 2, 3, 4, 5}, {2, 3, 4, 5}, {3, 4, 5}, {4, 5}, {5} };
1 2 3 4 5 2 3 4 5 3 4 5 4 5 5
As you can see, triangleArray[0].length is 5, triangleArray[1].length is 4, triangleArray[2].length is 3, triangleArray[3].length is 2, and triangle− Array[4].length is 1. If you don’t know the values in a ragged array in advance, but do know the sizes—say, the same as in the preceding figure—you can create a ragged array using the following syntax: int[][] triangleArray = new int[5][]; triangleArray[0] = new int[5]; triangleArray[1] = new int[4]; triangleArray[2] = new int[3]; triangleArray[3] = new int[2]; triangleArray[4] = new int[1];
You can now assign values to the array. For example, triangleArray[0][3] = 4; triangleArray[4][0] = 5;
Note The syntax new int[5][] for creating an array requires the first index to be specified. The syntax new int[][] would be wrong.
M08_LIAN9966_12_SE_C08.indd 292
21/09/19 3:47 PM
8.3 Processing Two-Dimensional Arrays 293 8.2.1 8.2.2
Declare an array reference variable for a two-dimensional array of int values, create a 4-by-5 int matrix, and assign it to the variable. Which of the following statements are valid? int[][] int[] x int[][] int[][] int[][] int[][]
8.2.3
.2.4 8 8.2.5
r = y z m n
Check Point
= new int[2]; new int[]; = new int[3][]; = {{1, 2}}; = {{1, 2}, {2, 3}}; = {{1, 2}, {2, 3}, };
Write an expression to obtain the row size of a two-dimensional array x and an expression to obtain the size of the first row. Can the rows in a two-dimensional array have different lengths? What is the output of the following code? int[][] array = new int[5][6]; int[] x = {1, 2}; array[0] = x; System.out.println("array[0][1] is " + array[0][1]);
8.3 Processing Two-Dimensional Arrays Nested for loops are often used to process a two-dimensional array. Suppose an array matrix is created as follows: int[][] matrix = new int[10][10];
Key Point
The following are some examples of processing two-dimensional arrays. 1. Initializing arrays with input values. The following loop initializes the array with user input values: java.util.Scanner input = new java.util.Scanner(System.in); System.out.println("Enter " + matrix.length + " rows and " + matrix[0].length + " columns: "); for (int row = 0; row < matrix.length; row++) { for (int column = 0; column < matrix[row].length; column++) { matrix[row][column] = input.nextInt(); } }
2. Initializing arrays with random values. The following loop initializes the array with random values between 0 and 99: for (int row = 0; row < matrix.length; row++) { for (int column = 0; column < matrix[row].length; column++) { matrix[row][column] = (int)(Math.random() * 100); } }
3. Printing arrays. To print a two-dimensional array, you have to print each element in the array using a loop like the following loop: for (int row = 0; row < matrix.length; row++) { for (int column = 0; column < matrix[row].length; column++) { System.out.print(matrix[row][column] + " "); } System.out.println(); }
M08_LIAN9966_12_SE_C08.indd 293
21/09/19 3:47 PM
294 Chapter 8 Multidimensional Arrays 4. Summing all elements. Use a variable named total to store the sum. Initially total is 0. Add each element in the array to total using a loop like this: int total = 0; for (int row = 0; row < matrix.length; row++) { for (int column = 0; column < matrix[row].length; column++) { total += matrix[row][column]; } }
5. Summing elements by column. For each column, use a variable named total to store its sum. Add each element in the column to total using a loop like this: for (int column = 0; column < matrix[0].length; column++) { int total = 0; for (int row = 0; row < matrix.length; row++) total += matrix[row][column]; System.out.println("Sum for column " + column + " is " + total); }
VideoNote
Find the row with the largest sum
6. Which row has the largest sum? Use variables maxRow and indexOfMaxRow to track the largest sum and index of the row. For each row, compute its sum and update maxRow and indexOfMaxRow if the new sum is greater. int maxRow = 0; int indexOfMaxRow = 0; // Get sum of the first row in maxRow for (int column = 0; column < matrix[0].length; column++) { maxRow += matrix[0][column]; } for (int row = 1; row < matrix.length; row++) { int totalOfThisRow = 0; for (int column = 0; column < matrix[row].length; column++) totalOfThisRow += matrix[row][column]; if (totalOfThisRow > maxRow) { maxRow = totalOfThisRow; indexOfMaxRow = row; } } System.out.println("Row " + indexOfMaxRow + " has the maximum sum of " + maxRow);
7. Random shuffling. Shuffling the elements in a one-dimensional array was introduced in Section 7.2.6. How do you shuffle all the elements in a two-dimensional array? To accomplish this, for each element matrix[i][j], randomly generate indices i1 and j1 and swap matrix[i][j] with matrix[i1][j1], as follows: for (int i for (int int i1 int j1
= j = =
0; i < matrix.length; i++) { = 0; j < matrix[i].length; j++) { (int)(Math.random() * matrix.length); (int)(Math.random() * matrix[i].length);
// Swap matrix[i][j] with matrix[i1][j1]
M08_LIAN9966_12_SE_C08.indd 294
21/09/19 3:47 PM
8.4 Passing Two-Dimensional Arrays to Methods 295 int temp = matrix[i][j]; matrix[i][j] = matrix[i1][j1]; matrix[i1][j1] = temp; } }
8.3.1 Show the output of the following code: int[][] array = {{1, 2}, {3, 4}, for (int i = array.length − 1; i for (int j = array[i].length − System.out.print(array[i][j] System.out.println(); }
{5, 6}}; >= 0; i— —) { 1; j >= 0; j— —) + " ");
Check Point
8.3.2 Show the output of the following code: int[][] array = {{1, 2}, {3, 4}, {5, 6}}; int sum = 0; for (int i = 0; i < array.length; i++) sum += array[i][0]; System.out.println(sum);
8.4 Passing Two-Dimensional Arrays to Methods When passing a two-dimensional array to a method, the reference of the array is passed to the method. You can pass a two-dimensional array to a method just as you pass a one-dimensional array. You can also return an array from a method. Listing 8.1 gives an example with two methods. The first method, getArray(), returns a two-dimensional array and the second method, sum(int[][] m), returns the sum of all the elements in a matrix.
Key Point
Listing 8.1 PassTwoDimensionalArray.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
import java.util.Scanner; public class PassTwoDimensionalArray { public static void main(String[] args) { int[][] m = getArray(); // Get an array // Display sum of elements System.out.println("\nSum of all elements is " + sum(m));
get array pass array
} public static int[][] getArray() { // Create a Scanner Scanner input = new Scanner(System.in);
getArray method
// Enter array values int[][] m = new int[3][4]; System.out.println("Enter " + m.length + " rows and " + m[0].length + " columns: "); for (int i = 0; i < m.length; i++) for (int j = 0; j < m[i].length; j++) m[i][j] = input.nextInt();
M08_LIAN9966_12_SE_C08.indd 295
21/09/19 3:47 PM
296 Chapter 8 Multidimensional Arrays 23 24 25 26 27 28 29 30 31 32 33 34 35 36
return array sum method
return m; } public static int sum(int[][] m) { int total = 0; for (int row = 0; row < m.length; row++) { for (int column = 0; column < m[row].length; column++) { total += m[row][column]; } } return total; } }
Enter 3 rows and 4 columns: 1 2 3 4 5 6 7 8 9 10 11 12 Sum of all elements is 78
The method getArray prompts the user to enter values for the array (lines 11–24) and returns the array (line 23). The method sum (lines 26–35) has a two-dimensional array argument. You can obtain the number of rows using m.length (line 28), and the number of columns in a specified row using m[row].length (line 29). Check Point
8.4.1 Show the output of the following code: public class Test { public static void main(String[] args) { int[][] array = {{1, 2, 3, 4}, {5, 6, 7, 8}}; System.out.println(m1(array)[0]); System.out.println(m1(array)[1]); } public static int[] m1(int[][] m) { int[] result = new int[2]; result[0] = m.length; result[1] = m[0].length; return result; } }
8.5 Case Study: Grading a Multiple-Choice Test The problem is to write a program that will grade multiple-choice tests. VideoNote
Key Point
Grade multiple-choice test
M08_LIAN9966_12_SE_C08.indd 296
Suppose you need to write a program that grades multiple-choice tests. Assume there are eight students and ten questions, and the answers are stored in a two-dimensional array. Each row records a student’s answers to the questions, as shown in the following array:
21/09/19 3:47 PM
8.5 Case Study: Grading a Multiple-Choice Test 297
Students’ Answers to the Questions: 0 1 2 3 4 5 6 7 8 9 Student Student Student Student Student Student Student Student
0 1 2 3 4 5 6 7
A D E C A B B E
B B D B B B B B
A A D A D E A E
C B A E C C C C
C C C D C C C C
D A B C D D D D
E E E E E E E E
E E E E E E E E
A A A A A A A A
D D D D D D D D
The key is stored in a one-dimensional array: Key to the Questions: 012345678 9 Key D B D C C D A E A D
Your program grades the test and displays the result. It compares each student’s answers with the key, counts the number of correct answers, and displays it. Listing 8.2 gives the program.
Listing 8.2 GradeExam.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
public class GradeExam { /** Main method */ public static void main(String[] args) { // Students' answers to the questions char[][] answers = { {'A', 'B', 'A', 'C', 'C', 'D', 'E', 'E', {'D', 'B', 'A', 'B', 'C', 'A', 'E', 'E', {'E', 'D', 'D', 'A', 'C', 'B', 'E', 'E', {'C', 'B', 'A', 'E', 'D', 'C', 'E', 'E', {'A', 'B', 'D', 'C', 'C', 'D', 'E', 'E', {'B', 'B', 'E', 'C', 'C', 'D', 'E', 'E', {'B', 'B', 'A', 'C', 'C', 'D', 'E', 'E', {'E', 'B', 'E', 'C', 'C', 'D', 'E', 'E',
2-D array 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
'D'}, 'D'}, 'D'}, 'D'}, 'D'}, 'D'}, 'D'}, 'D'}};
// Key to the questions char[] keys = {'D', 'B', 'D', 'C', 'C', 'D', 'A', 'E', 'A', 'D'}; // Grade all answers for (int i = 0; i < answers.length; i++) { // Grade one student int correctCount = 0; for (int j = 0; j < answers[i].length; j++) { if (answers[i][j] == keys[j]) correctCount++; }
1-D array
compare with key
System.out.println("Student " + i + "'s correct count is " + correctCount); } } }
M08_LIAN9966_12_SE_C08.indd 297
21/09/19 3:47 PM
298 Chapter 8 Multidimensional Arrays Student Student Student Student Student Student Student Student
0's 1's 2's 3's 4's 5's 6's 7's
correct correct correct correct correct correct correct correct
count count count count count count count count
is is is is is is is is
7 6 5 4 8 7 7 7
The statement in lines 5–13 declares, creates, and initializes a two-dimensional array of characters and assigns the reference to answers of the char[][] type. The statement in line 16 declares, creates, and initializes an array of char values and assigns the reference to keys of the char[] type. Each row in the array answers stores a student’s answer, which is graded by comparing it with the key in the array keys. The result is displayed immediately after a student's answer is graded. Check Point
8.5.1
How do you modify the code so it also displays the highest count and the student with the highest count?
8.6 Case Study: Finding the Closest Pair This section presents a geometric problem for finding the closest pair of points. Key Point
closest-pair animation on the Companion Website
Given a set of points, the closest-pair problem is to find the two points that are nearest to each other. In Figure 8.3, for example, points (1, 1) and (2, 0.5) are closest to each other. There are several ways to solve this problem. An intuitive approach is to compute the distances between all pairs of points and find the one with the minimum distance, as implemented in Listing 8.3.
(21, 3)
(3, 3) (4, 2)
(1, 1) (2, 0.5)
(21, 21)
(4, 20.5) (2, 21)
x 0 21 1 21 2 1 3 2 4 2 5 3 6 4 7 4
y 3 21 1 0.5 21 3 2 20.5
Figure 8.3 Points can be represented in a two-dimensional array.
Listing 8.3 FindNearestPoints.java
number of points
M08_LIAN9966_12_SE_C08.indd 298
1 2 3 4 5 6 7 8 9
import java.util.Scanner; public class FindNearestPoints { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Enter the number of points: "); int numberOfPoints = input.nextInt(); // Create an array to store points
21/09/19 3:47 PM
8.6 Case Study: Finding the Closest Pair 299 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
double[][] points = new double[numberOfPoints][2]; System.out.print("Enter " + numberOfPoints + " points: "); for (int i = 0; i < points.length; i++) { points[i][0] = input.nextDouble(); points[i][1] = input.nextDouble(); } // p1 and p2 are the indices in the points' array int p1 = 0, p2 = 1; // Initial two points double shortestDistance = distance(points[p1][0], points[p1][1], points[p2][0], points[p2][1]); // Initialize shortestDistance // Compute distance for every two points for (int i = 0; i < points.length; i++) { for (int j = i + 1; j < points.length; j++) { double distance = distance(points[i][0], points[i][1], points[j][0], points[j][1]); // Find distance if (shortestDistance > distance) { p1 = i; // Update p1 p2 = j; // Update p2 shortestDistance = distance; // Update shortestDistance }
2-D array read points
track two points track shortestDistance
for each point i for each point j distance between i and j distance between two points
update shortestDistance
} } // Display result System.out.println("The closest two points are " + "(" + points[p1][0] + ", " + points[p1][1] + ") and (" + points[p2][0] + ", " + points[p2][1] + ")"); } /** Compute the distance between two points (x1, y1) and (x2, y2)*/ public static double distance( double x1, double y1, double x2, double y2) { return Math.sqrt((x2 − x1) * (x2 − x1) + (y2 − y1) * (y2 − y1)); } }
Enter the number of points: 8 Enter 8 points: −1 3 −1 −1 1 1 2 0.5 2 −1 3 3 4 2 4 −0.5 The closest two points are (1, 1) and (2, 0.5)
The program prompts the user to enter the number of points (lines 6 and 7). The points are read from the console and stored in a two-dimensional array named points (lines 12–15). The program uses the variable shortestDistance (line 19) to store the distance between the two nearest points, and the indices of these two points in the points array are stored in p1 and p2 (line 18). For each point at index i, the program computes the distance between points[i] and points[j] for all j > i (lines 23–34). Whenever a shorter distance is found, the variable shortestDistance and p1 and p2 are updated (lines 28–32). The distance between two points (x1, y1) and (x2, y2) can be computed using the formula 2(x2 - x1)2 + (y2 - y1)2 (lines 43–46). The program assumes the plane has at least two points. You can easily modify the program to handle the case if the plane has zero or one point.
M08_LIAN9966_12_SE_C08.indd 299
21/09/19 3:47 PM
300 Chapter 8 Multidimensional Arrays Note that there might be more than one closest pair of points with the same minimum distance. The program finds one such pair. You may modify the program to find all closest pairs in Programming Exercise 8.8.
multiple closest pairs
Tip It is cumbersome to enter all points from the keyboard. You may store the input in a file, say FindNearestPoints.txt, and run the program using the following command:
input file
java FindNearestPoints < FindNearestPoints.txt Check Point
8.6.1
What happens if the input has only one point?
8.7 Case Study: Sudoku The problem is to check whether a given Sudoku solution is correct.
Key Point VideoNote
Sudoku
fixed cells free cells
This section presents an interesting problem of a sort that appears in the newspaper every day. It is a number-placement puzzle, commonly known as Sudoku. Writing a program to solve a Sudoku problem is very challenging. To make it accessible to the novice, this section presents a simplified version of the Sudoku problem, which is to verify whether a Sudoku solution is correct. The complete program for finding a Sudoku solution is presented in Supplement VI.C. Sudoku is a 9 * 9 grid divided into smaller 3 * 3 boxes (also called regions or blocks), as shown in Figure 8.4a. Some cells, called fixed cells, are populated with numbers from 1 to 9. The objective is to fill the empty cells, also called free cells, with the numbers 1 to 9 so every row, every column, and every 3 * 3 box contains the numbers 1 to 9, as shown in Figure 8.4b. 5
3
7
6
1 9
9
5
8
6
8
6
4
8
7
3 3
Solution
1
2
6
6 4
1
9
8
7
5
3
4
6
7
8
9
1
2
6
7
2
1
9
5
3
4
8
1
9
8
3
4
2
5
6
7
8
5
9
7
6
1
4
2
3
4
2
6
8
5
3
7
9
1
7
1
3
9
2
4
8
5
6
9
6
1
5
3
7
2
8
4
5
2
8
7
4
1
9
6
3
5
9
3
4
5
2
8
6
1
7
9
(a) Puzzle
(b) Solution
Figure 8.4 The Sudoku puzzle in (a) is solved in (b). representing a grid
For convenience, we use value 0 to indicate a free cell, as shown in Figure 8.5a. The grid can be naturally represented using a two-dimensional array, as shown in Figure 8.5b. 5
3
0
0
7
0
0
0
0
6
0
0
1
9
5
0
0
0
0
9
8
0
0
0
0
6
0
8
0
0
0
6
0
0
0
3
4
0
0
8
0
3
0
0
1
7
0
0
0
2
0
0
0
6
0
6
0
0
0
0
0
0
0
0
0
0
4
1
9
0
0
5
0
0
0
0
8
0
0
7
9
(a)
int[][] grid = {{5, 3, 0, 0, {6, 0, 0, 1, {0, 9, 8, 0, {8, 0, 0, 0, {4, 0, 0, 8, {7, 0, 0, 0, {0, 6, 0, 0, {0, 0, 0, 4, {0, 0, 0, 0, };
7, 9, 0, 6, 0, 2, 0, 1, 8,
0, 5, 0, 0, 3, 0, 0, 9, 0,
0, 0, 0, 0, 0, 0, 2, 0, 0,
0, 0, 6, 0, 0, 0, 8, 0, 7,
0}, 0}, 0}, 3}, 1}, 6}, 0}, 5}, 9}
(b)
Figure 8.5 A grid can be represented using a two-dimensional array.
M08_LIAN9966_12_SE_C08.indd 300
21/09/19 3:47 PM
8.7 Case Study: Sudoku 301 To find a solution for the puzzle, we must replace each 0 in the grid with an appropriate number from 1 to 9. For the solution to the puzzle in Figure 8.5, the grid should be as shown in Figure 8.6. Once a solution to a Sudoku puzzle is found, how do you verify that it is correct? Here are two approaches: 1. Check if every row has numbers from 1 to 9, every column has numbers from 1 to 9, and every small box has numbers from 1 to 9. 2. Check each cell. Each cell must be a number from 1 to 9 and the cell must be unique on every row, every column, and every small box.
A solution {{5, 3, {6, 7, {1, 9, {8, 5, {4, 2, {7, 1, {9, 6, {2, 8, {3, 4, };
grid is 4, 6, 7, 2, 1, 9, 8, 3, 4, 9, 7, 6, 6, 8, 5, 3, 9, 2, 1, 5, 3, 7, 4, 1, 5, 2, 8,
8, 5, 2, 1, 3, 4, 7, 9, 6,
9, 3, 5, 4, 7, 8, 2, 6, 1,
1, 4, 6, 2, 9, 5, 8, 3, 7,
2}, 8}, 7}, 3}, 1}, 6}, 4}, 5}, 9}
Figure 8.6 A solution is stored in grid. The program in Listing 8.4 prompts the user to enter a solution and reports whether it is valid. We use the second approach in the program to check whether the solution is correct.
Listing 8.4 CheckSudokuSolution.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
import java.util.Scanner; public class CheckSudokuSolution { public static void main(String[] args) { // Read a Sudoku solution int[][] grid = readASolution(); System.out.println(isValid(grid) ? "Valid solution" : "Invalid solution");
read input solution valid?
} /** Read a Sudoku solution from the console */ public static int[][] readASolution() { // Create a Scanner Scanner input = new Scanner(System.in);
read solution
System.out.println("Enter a Sudoku puzzle solution:"); int[][] grid = new int[9][9]; for (int i = 0; i < 9; i++) for (int j = 0; j < 9; j++) grid[i][j] = input.nextInt(); return grid; } /** Check whether a solution is valid */ public static boolean isValid(int[][] grid) {
M08_LIAN9966_12_SE_C08.indd 301
check solution
21/09/19 3:47 PM
302 Chapter 8 Multidimensional Arrays
check rows
check columns
check small boxes
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
for (int i = 0; i < 9; i++) for (int j = 0; j < 9; j++) if (grid[i][j] < 1 || grid[i][j] > 9 || !isValid(i, j, grid)) return false; return true; // The solution is valid } /** Check whether grid[i][j] is valid in the grid */ public static boolean isValid(int i, int j, int[][] grid) { // Check whether grid[i][j] is unique in i's row for (int column = 0; column < 9; column++) if (column != j && grid[i][column] == grid[i][j]) return false; // Check whether grid[i][j] is unique in j's column for (int row = 0; row < 9; row++) if (row != i && grid[row][j] == grid[i][j]) return false; // Check whether grid[i][j] is unique in the 3−by−3 box for (int row = (i / 3) * 3; row < (i / 3) * 3 + 3; row++) for (int col = (j / 3) * 3; col < (j / 3) * 3 + 3; col++) if (!(row == i && col == j) && grid[row][col] == grid[i][j]) return false; return true; // The current value at grid[i][j] is valid } }
Enter 9 6 3 1 7 8 2 5 4 8 2 1 4 9 6 7 3 5 5 8 9 3 1 7 6 4 2 Valid
isValid method
overloaded isValid method
M08_LIAN9966_12_SE_C08.indd 302
a Sudoku puzzle solution: 1 7 4 2 5 8 3 2 5 6 4 9 6 8 9 7 3 1 4 3 7 5 9 6 8 5 2 3 1 7 9 6 1 8 2 4 7 1 3 4 6 2 2 4 6 9 8 5 5 9 8 1 7 3 solution
The program invokes the readASolution() method (line 6) to read a Sudoku solution and return a two-dimensional array representing a Sudoku grid. The isValid(grid) method checks whether the values in the grid are valid by verifying that each value is between 1 and 9, and that each value is valid in the grid (lines 27–34). The isValid(i, j, grid) method checks whether the value at grid[i][j] is valid. It checks whether grid[i][j] appears more than once in row i (lines 39–41), in column j (lines 44–46), and in the 3 * 3 box (lines 49–52). How do you locate all the cells in the same box? For any grid[i][j], the starting cell of the 3 * 3 box that contains it is grid[(i / 3) * 3][(j / 3) * 3], as illustrated in Figure 8.7.
21/09/19 3:47 PM
8.8 Multidimensional Arrays 303 grid[0][6]
grid[0][0]
For any grid[i][j]in this 3 by 3 box, its starting cell is grid[33(i/3)][33(j/3)] (i.e., grid[0][6]). For example, for grid[2][8], i=2 and j=8, 33(i/3)=0 and 33(j/3)=6.
grid[6][3] For any grid[i][j]in this 3 by 3 box, its starting cell is grid[33(i/3)] [33(j/3)](i.e., grid[6][3]). For example, for grid[8][5], i=8 and j=5, 33(i/3)=6 and 33(j/3)=3.
Figure 8.7 The location of the first cell in a 3 * 3 box determines the locations of other cells in the box. With this observation, you can easily identify all the cells in the box. For instance, if grid[r][c] is the starting cell of a 3 * 3 box, the cells in the box can be traversed in a
nested loop as follows:
// Get all cells in a 3−by−3 box starting at grid[r][c] for (int row = r; row < r + 3; row++) for (int col = c; col < c + 3; col++) // grid[row][col] is in the box
It is cumbersome to enter 81 numbers from the console. When you test the program, you may store the input in a file, say CheckSudokuSolution.txt (see liveexample.pearsoncmg. com/data/CheckSudokuSolution.txt) and run the program using the following command:
input file
java CheckSudokuSolution < CheckSudokuSolution.txt
8.7.1
What happens if the code in line 51 in Listing 8.4 is changed to if (row != i && col != j && grid[row][col] == grid[i][j])
Check Point
8.8 Multidimensional Arrays A two-dimensional array is an array of one-dimensional arrays, and a three- dimensional array is an array of two-dimensional arrays. In the preceding section, you used a two-dimensional array to represent a matrix or a table. Occasionally, you will need to represent n-dimensional data structures. In Java, you can create n-dimensional arrays for any positive integer n. The way to declare two-dimensional array variables and create two-dimensional arrays can be generalized to declare n-dimensional array variables and create n-dimensional arrays for n 7 = 3. For example, you may use a three-dimensional array to store exam scores for a class of six students with five exams, and each exam has two parts (multiple-choice and essay type questions). The following syntax declares a three-dimensional array variable scores, creates an array, and assigns its reference to scores.
Key Point
double[][][] scores = new double[6][5][2];
You can also use the array initializer to create and initialize the array as follows: double[][][] scores = {{7.5, 20.5}, {9.0, {{4.5, 21.5}, {9.0, {{6.5, 30.5}, {9.4, {{6.5, 23.5}, {9.4, {{8.5, 26.5}, {9.4, {{9.5, 20.5}, {9.4,
M08_LIAN9966_12_SE_C08.indd 303
{ 22.5}, 22.5}, 10.5}, 32.5}, 52.5}, 42.5},
{15, {15, {11, {13, {13, {13,
33.5}, 34.5}, 33.5}, 34.5}, 36.5}, 31.5},
{13, {12, {11, {11, {13, {12,
21.5}, 20.5}, 23.5}, 20.5}, 24.5}, 20.5},
{15, {14, {10, {16, {16, {16,
2.5}}, 9.5}}, 2.5}}, 7.5}}, 2.5}}, 6.5}}};
21/09/19 3:47 PM
304 Chapter 8 Multidimensional Arrays scores[0][1][0] refers to the multiple-choice score for the first student’s second exam, which is 9.0. scores[0][1][1] refers to the essay score for the first student’s second exam, which is 22.5. This is depicted in the following figure:
Which student
Which exam
Multiple-choice or essay score
scores [i] [j] [k]
A multidimensional array is actually an array in which each element is another array. A three-dimensional array is an array of two-dimensional arrays. A two-dimensional array is an array of one-dimensional arrays. For example, suppose that x = new int[2][2][5] and x[0] and x[1] are two-dimensional arrays. x[0][0], x[0][1], x[1][0], and x[1][1] are one-dimensional arrays and each contains five elements. x.length is 2, x[0].length and x[1].length are 2, and x[0][0].length, x[0][1].length, x[1][0].length, and x[1][1].length are 5.
8.8.1 Case Study: Daily Temperature and Humidity Suppose a meteorology station records the temperature and humidity every hour of every day, and stores the data for the past 10 days in a text file named Weather.txt (see liveexample .pearsoncmg.com/data/Weather.txt). Each line of the file consists of four numbers that indicate the day, hour, temperature, and humidity. The contents of the file may look like those in (a). Day
Temperature
Day
Hour
Temperature Hour
Humidity
Humidity
1 1
1 2
76.4 77.7
0.92 0.93
10 1
24 2
98.7 77.7
0.74 0.93
... 10 10
23 24
97.7 98.7
0.71 0.74
... 10 1
23 1
97.7 76.4
0.71 0.92
(a)
(b)
Note the lines in the file are not necessarily in increasing order of day and hour. For example, the file may appear as shown in (b). Your task is to write a program that calculates the average daily temperature and humidity for the 10 days. You can use the input redirection to read the file and store the data in a three-dimensional array named data. The first index of data ranges from 0 to 9 and represents 10 days, the second index ranges from 0 to 23 and represents 24 hours, and the third index ranges from 0 to 1 and represents temperature and humidity, as depicted in the following figure: Which day
Which hour
data [i]
M08_LIAN9966_12_SE_C08.indd 304
[j]
Temperature or humidity
[k]
21/09/19 3:47 PM
8.8 Multidimensional Arrays 305 Note the days are numbered from 1 to 10 and the hours from 1 to 24 in the file. Because the array index starts from 0, data[0][0][0] stores the temperature in day 1 at hour 1 and data[9][23][1] stores the humidity in day 10 at hour 24. The program is given in Listing 8.5.
Listing 8.5 Weather.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
import java.util.Scanner; public class Weather { public static void main(String[] args) { final int NUMBER_OF_DAYS = 10; final int NUMBER_OF_HOURS = 24; double[][][] data = new double[NUMBER_OF_DAYS][NUMBER_OF_HOURS][2];
three-dimensional array
Scanner input = new Scanner(System.in); // Read input using input redirection from a file for (int k = 0; k < NUMBER_OF_DAYS * NUMBER_OF_HOURS; k++) { int day = input.nextInt(); int hour = input.nextInt(); double temperature = input.nextDouble(); double humidity = input.nextDouble(); data[day − 1][hour − 1][0] = temperature; data[day − 1][hour − 1][1] = humidity; } // Find the average daily temperature and humidity for (int i = 0; i < NUMBER_OF_DAYS; i++) { double dailyTemperatureTotal = 0, dailyHumidityTotal = 0; for (int j = 0; j < NUMBER_OF_HOURS; j++) { dailyTemperatureTotal += data[i][j][0]; dailyHumidityTotal += data[i][j][1]; } // Display result System.out.println("Day " + i + "'s average temperature is " + dailyTemperatureTotal / NUMBER_OF_HOURS); System.out.println("Day " + i + "'s average humidity is " + dailyHumidityTotal / NUMBER_OF_HOURS); } } }
Day Day Day Day ... Day Day
0's 0's 1's 1's
average average average average
temperature humidity is temperature humidity is
is 77.7708 0.929583 is 77.3125 0.929583
9's average temperature is 79.3542 9's average humidity is 0.9125
You can use the following command to run the program: java Weather < Weather.txt
A three-dimensional array for storing temperature and humidity is created in line 8. The loop in lines 12–19 reads the input to the array. You can enter the input from the keyboard, but
M08_LIAN9966_12_SE_C08.indd 305
21/09/19 3:47 PM
306 Chapter 8 Multidimensional Arrays doing so will be awkward. For convenience, we store the data in a file and use input redirection to read the data from the file. The loop in lines 24–27 adds all temperatures for each hour in a day to dailyTemperatureTotal, and all humidity for each hour to dailyHumidityTotal. The average daily temperature and humidity are displayed in lines 30–33.
8.8.2 Case Study: Guessing Birthdays Listing 4.3, GuessBirthday.java, gives a program that guesses a birthday. The program can be simplified by storing the numbers in five sets in a three-dimensional array and it prompts the user for the answers using a loop, as given in Listing 8.6. The sample run of the program can be the same as given in Listing 4.3.
Listing 8.6 GuessBirthdayUsingArray.java
three-dimensional array
Set i
add to day
M08_LIAN9966_12_SE_C08.indd 306
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
import java.util.Scanner; public class GuessBirthdayUsingArray { public static void main(String[] args) { int day = 0; // Day to be determined int answer; int[][][] dates {{ 1, 3, 5, { 9, 11, 13, {17, 19, 21, {25, 27, 29, {{ 2, 3, 6, {10, 11, 14, {18, 19, 22, {26, 27, 30, {{ 4, 5, 6, {12, 13, 14, {20, 21, 22, {28, 29, 30, {{ 8, 9, 10, {12, 13, 14, {24, 25, 26, {28, 29, 30, {{16, 17, 18, {20, 21, 22, {24, 25, 26, {28, 29, 30,
= { 7}, 15}, 23}, 31}}, 7}, 15}, 23}, 31}}, 7}, 15}}, 23}, 31}}, 11}, 15}, 27}, 31}}, 19}, 23}, 27}, 31}}};
// Create a Scanner Scanner input = new Scanner(System.in); for (int i = 0; i < 5; i++) { System.out.println("Is your birthday in Set" + (i + 1) + "?"); for (int j = 0; j < 4; j++) { for (int k = 0; k < 4; k++) System.out.printf("%4d", dates[i][j][k]); System.out.println(); } System.out.print("\nEnter 0 for No and 1 for Yes: "); answer = input.nextInt(); if (answer == 1) day += dates[i][0][0];
21/09/19 3:47 PM
Chapter Summary 307 46 47 48 49 50
} System.out.println("Your birthday is " + day); } }
A three-dimensional array dates is created in lines 8–28. This array stores five sets of numbers. Each set is a 4-by-4 two-dimensional array. The loop starting from line 33 displays the numbers in each set and prompts the user to answer whether the birthday is in the set (lines 41 and 42). If the day is in the set, the first number (dates[i][0][0]) in the set is added to variable day (line 45).
8.8.1 8.8.2 8.8.3
Declare an array variable for a three-dimensional array, create a 4 * 6 * 5 int array, and assign its reference to the variable. Assume char[][][] x = new char[12][5][2], how many elements are in the array? What are x.length, x[2].length, and x[0][0].length? Show the output of the following code:
Check Point
int[][][] array = {{{1, 2}, {3, 4}}, {{5, 6},{7, 8}}}; System.out.println(array[0][0][0]); System.out.println(array[1][1][1]);
Key Terms column index 290 multidimensional array 303 nested array 290
row index 291 two-dimensional array 290
Chapter Summary 1. A two-dimensional array can be used to store a table. 2. A variable for two-dimensional arrays can be declared using the syntax: elementType[][] arrayVar.
3. A two-dimensional array can be created using the syntax: new
elementType[ROW_SIZE]
[COLUMN_SIZE].
4. Each element in a two-dimensional array is represented using the syntax:
array-
Var[rowIndex][columnIndex].
5. You can create and initialize a two-dimensional array using an array initializer with the syntax: elementType[][] arrayVar = {{row values}, . . ., {row values}}.
6. You can use arrays of arrays to form multidimensional arrays. For example, a variable for three-dimensional arrays can be declared as elementType[][][] arrayVar and a three-dimensional array can be created using new elementType[size1][size2] [size3].
Quiz Answer the quiz for this chapter online at the book Companion Website.
M08_LIAN9966_12_SE_C08.indd 307
21/09/19 3:47 PM
308 Chapter 8 Multidimensional Arrays
Programming Exercises *8.1
(Sum elements column by column) Write a method that returns the sum of all the elements in a specified column in a matrix using the following header: public static double sumColumn(double[][] m, int columnIndex)
Write a test program that reads a 3-by-4 matrix and displays the sum of each column. Here is a sample run: Enter a 3−by−4 matrix row by row: 1.5 5.5 9.5 Sum Sum Sum Sum
*8.2
2 3 4 6 7 8 1 3 1 of the of the of the of the
elements elements elements elements
at at at at
column column column column
0 1 2 3
is is is is
16.5 9.0 13.0 13.0
(Sum the major diagonal in a matrix) Write a method that sums all the numbers in the major diagonal in an n * n matrix of double values using the following header: public static double sumMajorDiagonal(double[][] m)
Write a test program that reads a 4-by-4 matrix and displays the sum of all its elements on the major diagonal. Here is a sample run: Enter a 4−by−4 matrix row by row: 1 2 3 4.0 5 6.5 7 8 9 10 11 12 13 14 15 16 Sum of the elements in the major diagonal is 34.5
*8.3 **8.4
M08_LIAN9966_12_SE_C08.indd 308
(Sort students on grades) Rewrite Listing 8.2, GradeExam.java, to display the students in increasing order of the number of correct answers. (Compute the weekly hours for each employee) Suppose the weekly hours for all employees are stored in a two-dimensional array. Each row records an employee’s seven-day work hours with seven columns. For example, the following array stores the work hours for eight employees. Write a program that displays employees and their total hours in decreasing order of the total hours. Su
M
T
W
Th
F
Sa
Employee 0
2
4
3
4
5
8
8
Employee 1
7
3
4
3
3
4
4
Employee 2
3
3
4
3
3
2
2
Employee 3
9
3
4
7
3
4
1
Employee 4
3
5
4
3
6
3
8
Employee 5
3
4
4
6
3
4
4
Employee 6
3
7
4
8
3
8
4
Employee 7
6
3
5
9
2
7
9
21/09/19 3:47 PM
Programming Exercises 309
8.5
(Algebra: add two matrices) Write a method to add two matrices. The header of the method is as follows: public static double[][] addMatrix(double[][] a, double[][] b)
In order to be added, the two matrices must have the same dimensions and the same or compatible types of elements. Let c be the resulting matrix. Each element cij is aij + bij. For example, for two 3 * 3 matrices a and b, c is a11 £ a21 a31
a12 a22 a32
a13 b11 a23 ≥ + £ b21 a33 b31
b12 b22 b32
b13 a11 + b11 b23 ≥ = £ a21 + b21 b33 a31 + b31
a12 + b12 a22 + b22 a32 + b32
a13 + b13 a23 + b23 ≥ a33 + b33
Write a test program that prompts the user to enter two 3 * 3 matrices and displays their sum. Here is a sample run: Enter matrix1: 1 2 3 4 5 6 7 8 9 Enter matrix2: 0 2 4 1 4.5 2.2 1.1 4.3 5.2 The matrices are added as follows 1.0 2.0 3.0 0.0 2.0 4.0 4.0 5.0 6.0 + 1.0 4.5 2.2 = 7.0 8.0 9.0 1.1 4.3 5.2
**8.6
1.0 4.0 7.0 5.0 9.5 8.2 8.1 12.3 14.2
(Algebra: multiply two matrices) Write a method to multiply two matrices. The header of the method is:
Multiply two matrices
public static double[][] multiplyMatrix(double[][] a, double[][] b)
VideoNote
To multiply matrix a by matrix b, the number of columns in a must be the same as the number of rows in b, and the two matrices must have elements of the same or compatible types. Let c be the result of the multiplication. Assume the column size of matrix a is n. Each element cij is ai1 * b1j + ai2 * b2j + g + ain * bnj. For example, for two 3 * 3 matrices a and b, c is a11 £ a21 a31
a12 a22 a32
a13 b11 a23 ≥ * £ b21 a33 b31
b12 b22 b32
b13 c11 b23 ≥ = £ c21 b33 c31
c12 c22 c32
c13 c23 ≥ c33
where cij = ai1 * b1j + ai2 * b2j + ai3 * b3j. Write a test program that prompts the user to enter two 3 * 3 matrices and displays their product. Here is a sample run: Enter matrix1: 1 2 3 4 5 6 7 8 9 Enter matrix2: 0 2 4 1 4.5 2.2 1.1 4.3 5.2 The multiplication of the matrices is 1 2 3 0 2.0 4.0 5.3 23.9 24 4 5 6 * 1 4.5 2.2 = 11.6 56.3 58.2 7 8 9 1.1 4.3 5.2 17.9 88.7 92.4
*8.7
M08_LIAN9966_12_SE_C08.indd 309
(Points nearest to each other) Listing 8.3 gives a program that finds two points in a two-dimensional space nearest to each other. Revise the program so it finds two points in a three-dimensional space nearest to each other. Use a two-dimensional array to represent the points. Test the program using the following points:
21/09/19 3:47 PM
310 Chapter 8 Multidimensional Arrays double[][] points = {{−1, 0, 3}, {−1, −1, −1}, {4, 1, 1}, {2, 0.5, 9}, {3.5, 2, −1}, {3, 1.5, 3}, {−1.5, 4, 2}, {5.5, 4, −0.5}};
**8.8
The formula for computing the distance between two points (x1, y1, z1) and (x2, y2, z2) is 2(x2 - x1)2 + (y2 - y1)2 + (z2 - z1)2. (All closest pairs of points) Revise Listing 8.3, FindNearestPoints.java, to display all closest pairs of points with the same minimum distance. Here is a sample run: Enter the number of points: 8 Enter 8 points: 0 0 1 1 −1 −1 2 2 −2 −2 −3 −3 −4 −4 5 5 The closest two points are (0.0, 0.0) and (1.0, 1.0) The closest two points are (0.0, 0.0) and (−1.0, −1.0) The closest two points are (1.0, 1.0) and (2.0, 2.0) The closest two points are (−1.0, −1.0) and (−2.0, −2.0) The closest two points are (−2.0, −2.0) and (−3.0, −3.0) The closest two points are (−3.0, −3.0) and (−4.0, −4.0) Their distance is 1.4142135623730951
***8.9
(Game: play a tic-tac-toe game) In a game of tic-tac-toe, two players take turns marking an available cell in a 3 * 3 grid with their respective tokens (either X or O). When one player has placed three tokens in a horizontal, vertical, or diagonal row on the grid, the game is over and that player has won. A draw (no winner) occurs when all the cells on the grid have been filled with tokens and neither player has achieved a win. Create a program for playing a tic-tac-toe game. The program prompts two players to alternately enter an X token and O token. Whenever a token is entered, the program redisplays the board on the console and determines the status of the game (win, draw, or continue). Here is a sample run:
|
|
|
|
|
|
|
|
|
|
|
|
Enter a row (0, 1, or 2) for player X: 1 Enter a column (0, 1, or 2) for player X: 1
|
|
|
|
|
| X |
|
|
|
|
|
Enter a row (0, 1, or 2) for player O: 1 Enter a column (0, 1, or 2) for player O: 2
M08_LIAN9966_12_SE_C08.indd 310
|
|
|
|
| X | O |
|
|
|
|
|
21/09/19 3:47 PM
Programming Exercises 311 Enter a row (0, 1, or 2) for player X: . . . | X |
|
|
| O | X | O | |
|
| X |
X player won
*8.10
(Largest row and column) Write a program that randomly fills in 0s and 1s into a 4-by-4 matrix, prints the matrix, and finds the first row and column with the most 1s. Here is a sample run of the program: 0011 0011 1101 1010 The largest row index: 2 The largest column index: 2
**8.11
(Game: nine heads and tails) Nine coins are placed in a 3-by-3 matrix with some face up and some face down. You can represent the state of the coins using a 3-by-3 matrix with values 0 (heads) and 1 (tails). Here are some examples: 0 0 0 0 1 0 0 0 0
1 0 1 0 0 1 1 0 0
1 1 0 1 0 0 0 0 1
1 0 1 1 1 0 1 0 0
1 0 0 1 1 1 1 1 0
Each state can also be represented using a binary number. For example, the preceding matrices correspond to the numbers 000010000 101001100 110100001 101110100 100111110
There are a total of 512 possibilities, so you can use decimal numbers 0, 1, 2, 3, . . . , and 511 to represent all states of the matrix. Write a program that prompts the user to enter a number between 0 and 511 and displays the corresponding matrix with the characters H and T. In the following sample run, the user entered 7, which corresponds to 000000111. Since 0 stands for H and 1 for T, the output is correct. Enter a number between 0 and 511: 7 H H H H H H T T T
** 8.12
M08_LIAN9966_12_SE_C08.indd 311
(Financial application: compute tax) Rewrite Listing 3.5, ComputeTax.java, using arrays. For each filing status, there are six tax rates. Each rate is applied to a certain amount of taxable income. For example, from the taxable income of $400,000 for a single filer, $8,350 is taxed at 10%, (33,950 - 8,350) at 15%,
21/09/19 3:47 PM
312 Chapter 8 Multidimensional Arrays (82,250 - 33,950) at 25%, (171,550 - 82,550) at 28%, (372,550 - 82,250) at 33%, and (400,000 - 372,950) at 36%. The six rates are the same for all filing statuses, which can be represented in the following array: double[] rates = {0.10, 0.15, 0.25, 0.28, 0.33, 0.35};
The brackets for each rate for all the filing statuses can be represented in a two- dimensional array as follows: int[][] brackets = { {8350, 33950, 82250, 171550, 372950}, {16700, 67900, 137050, 20885, 372950}, {8350, 33950, 68525, 104425, 186475}, {11950, 45500, 117450, 190200, 372950} };
// // // // //
Single filer Married jointly −or qualifying widow(er) Married separately Head of household
Suppose the taxable income is $400,000 for single filers. The tax can be computed as follows: tax = brackets[0][0] * rates[0] + (brackets[0][1] – brackets[0][0]) * rates[1] (brackets[0][2] – brackets[0][1]) * rates[2] (brackets[0][3] – brackets[0][2]) * rates[3] (brackets[0][4] – brackets[0][3]) * rates[4] (400000 – brackets[0][4]) * rates[5];
*8.13
+ + + +
(Locate the largest element) Write the following method that returns the location of the largest element in a two-dimensional array: public static int[] locateLargest(double[][] a)
The return value is a one-dimensional array that contains two elements. These two elements indicate the row and column indices of the largest element in the two-dimensional array. If there are more than one largest element, return the smallest row index and then the smallest column index. Write a test program that prompts the user to enter a two-dimensional array and displays the location of the largest element in the array. Here is a sample run:
Enter the number of rows and columns of the array: 3 4 Enter the array: 23.5 35 2 10 4.5 3 45 3.5 35 44 5.5 9.6 The location of the largest element is at (1, 2)
** 8.14
M08_LIAN9966_12_SE_C08.indd 312
(Explore matrix) Write a program that prompts the user to enter the length of a square matrix, randomly fills in 0s and 1s into the matrix, prints the matrix, and finds the rows, columns, and diagonals with all 0s or 1s. Here is a sample run of the program:
21/09/19 3:47 PM
Programming Exercises 313 Enter the size for 0111 0000 0100 1111 All 0s on row 2 All 1s on row 4 No same numbers on No same numbers on No same numbers on
*8.15
the matrix: 4
a column the major diagonal the sub−diagonal
(Geometry: same line?) Programming Exercise 6.39 gives a method for testing whether three points are on the same line. Write the following method to test whether all the points in the array points are on the same line: public static boolean sameLine(double[][] points)
Write a program that prompts the user to enter five points and displays whether they are on the same line. Here are sample runs:
Enter five points: 3.4 2 6.5 9.5 2.3 2.3 5.5 5 −5 4 The five points are not on the same line
Enter five points: 1 1 2 2 3 3 4 4 5 5 The five points are on the same line
*8.16
(Sort two-dimensional array) Write a method to sort a two-dimensional array using the following header: public static void sort(int m[][])
The method performs a primary sort on rows, and a secondary sort on columns. For example, the following array {{4, 2},{1, 7},{4, 5},{1, 2},{1, 1},{4, 1}}
will be sorted to {{1, 1},{1, 2},{1, 7},{4, 1},{4, 2},{4, 5}}.
***8.17 (Financial tsunami) Banks lend money to each other. In tough economic times, if a
bank goes bankrupt, it may not be able to pay back the loan. A bank’s total assets are its current balance plus its loans to other banks. The diagram in Figure 8.8 shows five banks. The banks’ current balances are 25, 125, 175, 75, and 181 million dollars, respectively. The directed edge from node 1 to node 2 indicates that bank 1 lends 40 million dollars to bank 2.
M08_LIAN9966_12_SE_C08.indd 313
21/09/19 3:47 PM
314 Chapter 8 Multidimensional Arrays 125 25
1
100.5
85 75
0
3
125 40 320.5
75
125
4
125
181
2 175
Figure 8.8 Banks lend money to each other.
If a bank’s total assets are under a certain limit, the bank is unsafe. The money it borrowed cannot be returned to the lender, and the lender cannot count the loan in its total assets. Consequently, the lender may also be unsafe, if its total assets are under the limit. Write a program to find all the unsafe banks. Your program reads the input as follows. It first reads two integers n and limit, where n indicates the number of banks and limit is the minimum total assets for keeping a bank safe. It then reads n lines that describe the information for n banks with IDs from 0 to n−1. The first number in the line is the bank’s balance, the second number indicates the number of banks that borrowed money from the bank, and the rest are pairs of two numbers. Each pair describes a borrower. The first number in the pair is the borrower’s ID and the second is the amount borrowed. For example, the input for the five banks in Figure 8.8 is as follows (note the limit is 201): 5 201 25 2 1 100.5 4 320.5 125 2 2 40 3 85 175 2 0 125 3 75 75 1 0 125 181 1 2 125
The total assets of bank 3 are (75 + 125), which is under 201, so bank 3 is unsafe. After bank 3 becomes unsafe, the total assets of bank 1 fall below (125 + 40). Thus, bank 1 is also unsafe. The output of the program should be Unsafe banks are 3 1
(Hint: Use a two-dimensional array borrowers to represent loans. borrowers[i][j] indicates the loan that bank i provides to bank j. Once bank j becomes unsafe, borrowers[i][j] should be set to 0.) *8.18 (Shuffle rows) Write a method that shuffles the rows in a two-dimensional int array using the following header: public static void shuffle(int[][] m)
Write a test program that shuffles the following matrix: int[][] m = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
**8.19
(Pattern recognition: four consecutive equal numbers) Write the following method that tests whether a two-dimensional array has four consecutive numbers of the same value, either horizontally, vertically, or diagonally: public static boolean isConsecutiveFour(int[][] values)
M08_LIAN9966_12_SE_C08.indd 314
21/09/19 3:47 PM
Programming Exercises 315
Write a test program that prompts the user to enter the number of rows and columns of a two-dimensional array then the values in the array, and displays true if the array contains four consecutive numbers with the same value. Otherwise, the program displays false. Here are some examples of the true cases:
0 1 0 3 1 6 1
0 1 0 3 1 6 1
0 1 0 3 1 6 1
0 1 0 3 1 6 1
0 1 6 8 6 0 1
0 1 6 8 6 0 1
0 1 6 8 6 0 1
0 1 6 8 6 0 1
5 6 2 1 8 2 9
5 5 2 1 8 2 9
5 6 2 1 6 2 9
9 6 2 1 8 2 9
6 5 6 1 1 9 1
6 5 6 1 1 9 1
6 5 6 6 1 9 1
6 9 6 1 1 9 1
1 3 6 1 4 0 7
1 5 6 1 4 0 7
1 3 6 1 4 0 7
1 3 9 1 4 0 7
3 3 3 3 4 0 7
3 5 3 3 4 0 7
3 6 3 3 4 0 7
3 3 3 9 4 0 7
***8.20 (Game: connect four) Connect four is a two-player board game in which the players alternately drop colored disks into a seven-column, six-row vertically suspended grid, as shown below.
The objective of the game is to connect four same-colored disks in a row, a column, or a diagonal before your opponent can do likewise. The program prompts two players to drop a red or yellow disk alternately. Whenever a disk is dropped, the program redisplays the board on the console and determines the status of the game (win, draw, or continue). Here is a sample run: | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
Drop a red disk at column (0–6): 0 | | | | | | | | | | |R|
M08_LIAN9966_12_SE_C08.indd 315
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
21/09/19 3:47 PM
316 Chapter 8 Multidimensional Arrays Drop a yellow disk at column (0–6): 3 | | | | | | | | | | |R|
| | | | | |
| | | | | | | | | | |Y|
| | | | | |
| | | | | |
| | | | | |
. . . . . . . . . Drop a yellow disk at column (0–6): 6 | | | | | | | | | | | | | | | | | | | |R| | | | | | | |Y|R|Y| | | | |R|Y|Y|Y|Y| |R|Y|R|Y|R|R|R| The yellow player won
*8.21
(Central city) Given a set of cities, the central city is the city that has the shortest total distance to all other cities. Write a program that prompts the user to enter the number of cities and the locations of the cities (coordinates), and finds the central city and its total distance to all other cities. Enter the number of cities: 5 Enter the coordinates of the cities: 2.5 5 5.1 3 1 9 5.4 54 5.5 2.1 The central city is at (2.5, 5.0) The total distance to all other cities is 60.81
*8.22 VideoNote
Even number of 1s
*8.23
(Even number of 1s) Write a program that generates a 6-by-6 two-dimensional matrix filled with 0s and 1s, displays the matrix, and checks if every row and every column have an even number of 1s. (Game: find the flipped cell) Suppose you are given a 6-by-6 matrix filled with 0s and 1s. All rows and all columns have an even number of 1s. Let the user flip one cell (i.e., flip from 1 to 0 or from 0 to 1) and write a program to find which cell was flipped. Your program should prompt the user to enter a 6-by-6 array with 0s and 1s and find the first row r and first column c where the even number of the 1s property is violated (i.e., the number of 1s is not even). The flipped cell is at (r, c). Here is a sample run: Enter a 6−by−6 matrix row by row: 1 1 1 0 1 1 1 1 1 1 0 0 0 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 0 0 0 0 1 The flipped cell is at (0, 1)
M08_LIAN9966_12_SE_C08.indd 316
21/09/19 3:47 PM
Programming Exercises 317 *8.24 *8.25
(Check Sudoku solution) Listing 8.4 checks whether a solution is valid by checking whether every number is valid in the board. Rewrite the program by checking whether every row, every column, and every small box has the numbers 1 to 9. (Markov matrix) An n * n matrix is called a positive Markov matrix if each element is positive and the sum of the elements in each column is 1. Write the following method to check whether a matrix is a Markov matrix: public static boolean isMarkovMatrix(double[][] m)
Write a test program that prompts the user to enter a 3 * 3 matrix of double values and tests whether it is a Markov matrix. Here are sample runs:
Enter a 3−by−3 matrix row by row: 0.15 0.875 0.375 0.55 0.005 0.225 0.30 0.12 0.4 It is a Markov matrix
Enter a 3−by−3 matrix row by row: 0.95 −0.875 0.375 0.65 0.005 0.225 0.30 0.22 −0.4 It is not a Markov matrix
*8.26
(Row sorting) Implement the following method to sort the rows in a two- dimensional array. A new array is returned and the original array is intact. public static double[][] sortRows(double[][] m)
Write a test program that prompts the user to enter a 3 * 3 matrix of double values and displays a new row-sorted matrix. Here is a sample run:
Enter a 3−by−3 matrix row by row: 0.15 0.875 0.375 0.55 0.005 0.225 0.30 0.12 0.4 The row−sorted array is 0.15 0.375 0.875 0.005 0.225 0.55 0.12 0.30 0.4
*8.27
(Column sorting) Implement the following method to sort the columns in a two-dimensional array. A new array is returned and the original array is intact. public static double[][] sortColumns(double[][] m)
M08_LIAN9966_12_SE_C08.indd 317
21/09/19 3:47 PM
318 Chapter 8 Multidimensional Arrays
Write a test program that prompts the user to enter a 3 * 3 matrix of double values and displays a new column-sorted matrix. Here is a sample run: Enter a 3−by−3 matrix row by row: 0.15 0.875 0.375 0.55 0.005 0.225 0.30 0.12 0.4 The column−sorted array is 0.15 0.0050 0.225 0.3 0.12 0.375 0.55 0.875 0.4
8.28
(Strictly identical arrays) The two-dimensional arrays m1 and m2 are strictly identical if their corresponding elements are equal. Write a method that returns true if m1 and m2 are strictly identical, using the following header: public static boolean equals(int[][] m1, int[][] m2)
Write a test program that prompts the user to enter two 3 * 3 arrays of integers and displays whether the two are strictly identical. Here are the sample runs:
Enter list1: 51 22 25 6 1 4 24 54 6 Enter list2: 51 22 25 6 1 4 24 54 6 The two arrays are strictly identical
Enter list1: 51 25 22 6 1 4 24 54 6 Enter list2: 51 22 25 6 1 4 24 54 6 The two arrays are not strictly identical
8.29
(Identical arrays) The two-dimensional arrays m1 and m2 are identical if they have the same contents. Write a method that returns true if m1 and m2 are identical, using the following header: public static boolean equals(int[][] m1, int[][] m2)
Write a test program that prompts the user to enter two 3 * 3 arrays of integers and displays whether the two are identical. Here are the sample runs:
Enter list1: 51 25 22 6 1 4 24 54 6 Enter list2: 51 22 25 6 1 4 24 54 6 The two arrays are identical
Enter list1: 51 5 22 6 1 4 24 54 6 Enter list2: 51 22 25 6 1 4 24 54 6 The two arrays are not identical
M08_LIAN9966_12_SE_C08.indd 318
21/09/19 3:47 PM
Programming Exercises 319 *8.30
(Algebra: solve linear equations) Write a method that solves the following 2 * 2 system of linear equations: b0a11 - b1a01 a00x + a01y = b0 x = a a10x + a11y = b1 00a11 - a01a10
y =
b1a00 - b0a10 a00a11 - a01a10
The method header is: public static double[] linearEquation(double[][] a, double[] b)
*8.31
The method returns null if a00a11 - a01a10 is 0. Write a test program that prompts the user to enter a00, a01, a10, a11, b0, and b1 and displays the result. If a00a11 - a01a10 is 0, report that “The equation has no solution.” A sample run is similar to Programming Exercise 3.3. (Geometry: intersecting point) Write a method that returns the intersecting point of two lines. The intersecting point of the two lines can be found by using the formula given in Programming Exercise 3.25. Assume that (x1, y1) and (x2, y2) are the two points on line 1 and (x3, y3) and (x4, y4) are on line 2. The method header is: public static double[] getIntersectingPoint(double[][] points)
The points are stored in a 4-by-2 two-dimensional array points with (points [0][0], points[0][1]) for (x1, y1). The method returns the intersecting point or null if the two lines are parallel. Write a program that prompts the user to enter four points and displays the intersecting point. See Programming Exercise 3.25 for a sample run. *8.32 (Geometry: area of a triangle) Write a method that returns the area of a triangle using the following header: public static double getTriangleArea(double[][] points)
The points are stored in a 3-by-2 two-dimensional array points with points [0][0] and points[0][1] for (x1, y1). The triangle area can be computed using the formula in Programming Exercise 2.19. The method returns 0 if the three points are on the same line. Write a program that prompts the user to enter three points of a triangle and displays the triangle’s area. Here are the sample runs: Enter x1, y1, x2, y2, x3, y3: 2.5 2 5 −1.0 4.0 2.0 The area of the triangle is 2.25
Enter x1, y1, x2, y2, x3, y3: 2 2 4.5 4.5 6 6 The three points are on the same line
*8.33
(Geometry: polygon subareas) A convex four-vertex polygon is divided into four triangles, as shown in Figure 8.9. Write a program that prompts the user to enter the coordinates of four vertices and displays the areas of the four triangles in increasing order. Here is a sample run: Enter x1, y1, x2, y2, x3, y3, x4, y4: −2.5 2 4 4 3 −2 −2 −3.5 The areas are 6.17 7.96 8.08 10.42
M08_LIAN9966_12_SE_C08.indd 319
21/09/19 3:47 PM
320 Chapter 8 Multidimensional Arrays v2 (x2, y2) v1 (x1, y1)
v3 (x3, y3)
v4 (x4, y4)
Figure 8.9 A four-vertex polygon is defined by four vertices.
*8.34
(Geometry: rightmost lowest point) In computational geometry, often you need to find the rightmost lowest point in a set of points. Write the following method that returns the rightmost lowest point in a set of points: public static double[] getRightmostLowestPoint(double[][] points)
Write a test program that prompts the user to enter the coordinates of six points and displays the rightmost lowest point. Here is a sample run:
Enter 6 points: 1.5 2.5 −3 4.5 5.6 −7 6.5 −7 8 1 10 2.5 The rightmost lowest point is (6.5, −7.0)
**8.35
(Largest block) Given a square matrix with the elements 0 or 1, write a program to find a maximum square submatrix whose elements are all 1s. Your program should prompt the user to enter the number of rows in the matrix. The program then displays the location of the first element in the maximum square submatrix and the number of rows in the submatrix. Here is a sample run:
Enter the number of rows in the matrix: 5 Enter the matrix row by row: 1 0 1 0 1 1 1 1 0 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 The maximum square submatrix is at (2, 2) with size 3
Your program should implement and use the following method to find the maximum square submatrix: public static int[] findLargestBlock(int[][] m)
M08_LIAN9966_12_SE_C08.indd 320
The return value is an array that consists of three values. The first two values are the row and column indices for the first element in the submatrix, and the third value is the number of the rows in the submatrix. For an animation of this problem, see https://liveexample.pearsoncmg.com/dsanimation/LargestBlockeBook.html.
21/09/19 3:47 PM
Programming Exercises 321 **8.36
(Latin square) A Latin square is an n-by-n array filled with n different Latin letters, each occurring exactly once in each row and once in each column. Write a program that prompts the user to enter the number n and the array of characters, as shown in the sample output, and checks if the input array is a Latin square. The characters are the first n characters starting from A.
Enter number n: 4 Enter 4 rows of letters separated by spaces: A B C D B A D C C D B A D C A B The input array is a Latin square
Enter number n: 3 Enter 3 rows of letters separated by spaces: A F D Wrong input: the letters must be from A to C
**8.37
(Guess the capitals) Write a program that repeatedly prompts the user to enter a capital for a state. Upon receiving the user input, the program reports whether the answer is correct. Assume that 50 states and their capitals are stored in a two-dimensional array, as shown in Figure 8.10. The program prompts the user to answer all states’ capitals and displays the total correct count. The user’s answer is not case-sensitive. Alabama Alaska Arizona ... ...
Montgomery Juneau Phoenix ... ...
Figure 8.10 A two-dimensional array stores states and their capitals.
Here is a sample run:
What is the The correct What is the Your answer What is the ... The correct
M08_LIAN9966_12_SE_C08.indd 321
capital of Alabama? Montogomery answer should be Montgomery capital of Alaska? Juneau is correct capital of Arizona? ... count is 35
21/09/19 3:47 PM
M08_LIAN9966_12_SE_C08.indd 322
21/09/19 3:47 PM
CHAPTER
9 Objects and Classes Objectives ■■
To describe objects and classes, and use classes to model objects (§9.2).
■■
To use UML graphical notation to describe classes and objects (§9.2).
■■
To demonstrate how to define classes and create objects (§9.3).
■■
To create objects using constructors (§9.4).
■■
To define a reference variable using a reference type and access objects via object reference variables (§9.5).
■■
To access an object’s data and methods using the object member access operator (.) (§9.5.1).
■■
To define data fields of reference types and assign default values for an object’s data fields (§9.5.2).
■■
To distinguish between object reference variables and primitivedata-type variables (§9.5.3).
■■
To use the Java library classes Date, Random, and Point2D (§9.6).
■■
To distinguish between instance and static variables and methods (§9.7).
■■
To define private data fields with appropriate getter and setter methods (§9.8).
■■
To encapsulate data fields to make classes easy to maintain (§9.9).
■■
To develop methods with object arguments and differentiate between primitive-type arguments and object-type arguments (§9.10).
■■
To store and process objects in arrays (§9.11).
■■
To create immutable objects from immutable classes to protect the contents of objects (§9.12).
■■
To determine the scope of variables in the context of a class (§9.13).
■■
To use the keyword this to refer to the calling object itself (§9.14).
M09_LIAN9966_12_SE_C09.indd 323
16/09/19 4:58 PM
324 Chapter 9 Objects and Classes
9.1 Introduction Key Point
why OOP?
Object-oriented programming enables you to develop large-scale software and GUIs effectively. Object-oriented programming is essentially a technology for developing reusable software. Having learned the material in the preceding chapters, you are able to solve many programming problems using selections, loops, methods, and arrays. However, these Java features are not sufficient for developing graphical user interfaces and large-scale software systems. Suppose you want to develop a graphical user interface (GUI, pronounced goo-ee) as shown in Figure 9.1. How would you program it?
Button
Label
Text Field
Check Box
Radio Button
Combo Box
Figure 9.1 The GUI objects are created from classes. This chapter introduces object-oriented programming, which you can use to develop GUI and large-scale software systems.
9.2 Defining Classes for Objects A class defines the properties and behaviors for objects.
VideoNote
Key Point
Define classes and create objects object state of an object properties attributes data fields behavior actions
class contract instantiation instance
data field method constructors
M09_LIAN9966_12_SE_C09.indd 324
Object-oriented programming (OOP) involves programming using objects. An object represents an entity in the real world that can be distinctly identified. For example, a student, a desk, a circle, a button, and even a loan can all be viewed as objects. An object has a unique identity, state, and behavior. ■■
The state of an object (also known as its properties or attributes) is represented by data fields with their current values. A circle object, for example, has a data field radius, which is the property that characterizes a circle. A rectangle object, for example, has the data fields width and height, which are the properties that characterize a rectangle.
■■
The behavior of an object (also known as its actions) is defined by methods. To invoke a method on an object is to ask the object to perform an action. For example, you may define methods named getArea() and getPerimeter() for circle objects. A circle object may invoke getArea() to return its area and getPerimeter() to return its perimeter. You may also define the setRadius(radius) method. A circle object can invoke this method to change its radius.
Objects of the same type are defined using a common class. A class is a template, b lueprint, or contract that defines what an object’s data fields and methods will be. An object is an instance of a class. You can create many instances of a class. Creating an instance is referred to as instantiation. The terms object and instance are often interchangeable. The relationship between classes and objects is analogous to that between an apple-pie recipe and apple pies: You can make as many apple pies as you want from a single recipe. Figure 9.2 shows a class named Circle and its three objects. A Java class uses variables to define data fields and methods to define actions. In addition, a class provides methods of a special type, known as constructors, which are invoked to create a new object. A constructor can perform any action, but constructors are designed to perform initializing actions, such as initializing the data fields of objects. Figure 9.3 shows an example of defining the class for circle objects.
16/09/19 4:58 PM
9.2 Defining Classes for Objects 325 A class template
Class Name: Circle Data Fields: radius is ___ Methods: getArea getPerimeter setRadius Circle Object 1
Circle Object 2
Circle Object 3
Data Fields: radius is 1
Data Fields: radius is 25
Data Fields: radius is 125
Three objects of the Circle class
Figure 9.2 A class is a template for creating objects.
class Circle { /** The radius of this circle */ double radius = 1;
Data fields
/** Construct a circle object */ Circle() { } /** Construct a circle object */ Circle(double newRadius) { radius = newRadius; }
Constructors
/** Return the area of this circle */ double getArea() { return radius * radius * Math.PI; } /** Return the perimeter of this circle */ double getPerimeter() { return 2 * radius * Math.PI; }
Methods
/** Set a new radius for this circle */ void setRadius(double newRadius) { radius = newRadius; } }
Figure 9.3 A class is a construct that defines objects of the same type.
The Circle class is different from all of the other classes you have seen thus far. It does not have a main method, and therefore cannot be run; it is merely a definition for circle objects. The class that contains the main method will be referred to in this book, for convenience, as the main class. The illustration of class templates and objects in Figure 9.2 can be standardized using Unified Modeling Language (UML) notation. This notation, as shown in Figure 9.4, is called a UML class diagram, or simply a class diagram. In the class diagram, the data field is denoted as
main class Unified Modeling Language (UML) class diagram
dataFieldName: dataFieldType
The constructor is denoted as ClassName(parameterName: parameterType)
M09_LIAN9966_12_SE_C09.indd 325
16/09/19 4:58 PM
326 Chapter 9 Objects and Classes UML Class Diagram
Class name
Circle radius: double
Data fields
Circle()
Constructors and methods
Circle(newRadius: double) getArea(): double getPerimeter(): double setRadius(newRadius: double): void
UML notation for objects
circle1: Circle
circle2: Circle
circle3: Circle
radius = 1
radius = 25
radius = 125
Figure 9.4 Classes and objects can be represented using UML notation. The method is denoted as methodName(parameterName: parameterType): returnType
9.3 Example: Defining Classes and Creating Objects Classes are definitions for objects and objects are created from classes. Key Point
This section gives two examples of defining classes and uses the classes to create objects. Listing 9.1 is a program that defines the Circle class and uses it to create objects. The program constructs three circle objects with radius 1, 25, and 125 and displays the radius and area of each of the three circles. It then changes the radius of the second object to 100 and displays its new radius and area.
Listing 9.1 TestCircle.java main class main method
create object
create object
create object
M09_LIAN9966_12_SE_C09.indd 326
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
public class TestCircle { /** Main method */ public static void main(String[] args) { // Create a circle with radius 1 Circle circle1 = new Circle(); System.out.println("The area of the circle of radius " + circle1.radius + " is " + circle1.getArea()); // Create a circle with radius 25 Circle circle2 = new Circle(25); System.out.println("The area of the circle of radius " + circle2.radius + "is" + circle2.getArea()); // Create a circle with radius 125 Circle circle3 = new Circle(125); System.out.println("The area of the circle of radius " + circle3.radius + " is " + circle3.getArea()); // Modify circle radius circle2.radius = 100; // or circle2.setRadius(100) System.out.println("The area of the circle of radius " + circle2.radius + " is " + circle2.getArea()); } }
16/09/19 4:58 PM
9.3 Example: Defining Classes and Creating Objects 327 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
// Define the circle class with two constructors class Circle { double radius; /** Construct a circle with radius 1 */ Circle() { radius = 1; }
class Circle data field
no-arg constructor
/** Construct a circle with a specified radius */ Circle(double newRadius) { radius = newRadius; } /** Return the area of this circle */ double getArea() { return radius * radius * Math.PI; }
second constructor
getArea
/** Return the perimeter of this circle */ double getPerimeter() { return 2 * radius * Math.PI; }
getPerimeter
/** Set a new radius for this circle */ void setRadius(double newRadius) { radius = newRadius; }
setRadius
}
The The The The
area area area area
of of of of
the the the the
circle circle circle circle
of of of of
radius radius radius radius
1.0 is 3.141592653589793 25.0 is 1963.4954084936207 125.0 is 49087.385212340516 100.0 is 31415.926535897932
The program contains two classes. The first of these, TestCircle, is the main class. Its sole purpose is to test the second class, Circle. Such a program that uses the class is often referred to as a client of the class. When you run the program, the Java runtime system invokes the main method in the main class. You can put the two classes into one file, but only one class in the file can be a public class. Furthermore, the public class must have the same name as the file name. Therefore, the file name is TestCircle.java, since TestCircle is public. Each class in the source code is compiled into a .class file. When you compile TestCircle.java, two class files TestCircle.class and Circle.class are generated, as shown in Figure 9.5. // File TestCircle.java public class TestCircle { … } class Circle { … }
client public class
TestCircle.class compiled by
Java Compiler
generates
Circle.class
Figure 9.5 Each class in the source code file is compiled into a .class file.
M09_LIAN9966_12_SE_C09.indd 327
16/09/19 4:58 PM
328 Chapter 9 Objects and Classes The main class contains the main method (line 3) that creates three objects. As in creating an array, the new operator is used to create an object from the constructor: new Circle() creates an object with radius 1 (line 5), new Circle(25) creates an object with radius 25 (line 10), and new Circle(125) creates an object with radius 125 (line 15). These three objects (referenced by circle1, circle2, and circle3) have different data but the same methods. Therefore, you can compute their respective areas by using the getArea() method. The data fields can be accessed via the reference of the object using circle1.radius, circle2.radius, and circle3.radius, respectively. The object can invoke its method via the reference of the object using circle1.getArea(), circle2. getArea(), and circle3.getArea(), respectively. These three objects are independent. The radius of circle2 is changed to 100 in line 20. The object’s new radius and area are displayed in lines 21 and 22. There are many ways to write Java programs. For instance, you can combine the two classes in the preceding example into one, as given in Listing 9.2.
Listing 9.2 Circle.java (AlternativeCircle.java) main method
data field
no-arg constructor
second constructor
method
M09_LIAN9966_12_SE_C09.indd 328
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
public class Circle { /** Main method */ public static void main(String[] args) { // Create a circle with radius 1 Circle circle1 = new Circle(); System.out.println("The area of the circle of radius " + circle1.radius + " is " + circle1.getArea()); // Create a circle with radius 25 Circle circle2 = new Circle(25); System.out.println("The area of the circle of radius " + circle2.radius + " is " + circle2.getArea()); // Create a circle with radius 125 Circle circle3 = new Circle(125); System.out.println("The area of the circle of radius " + circle3.radius + " is " + circle3.getArea()); // Modify circle radius circle2.radius = 100; System.out.println("The area of the circle of radius " + circle2.radius + " is " + circle2.getArea()); } double radius; /** Construct a circle with radius 1 */ Circle() { radius = 1; } /** Construct a circle with a specified radius */ Circle(double newRadius) { radius = newRadius; } /** Return the area of this circle */ double getArea() { return radius * radius * Math.PI; }
16/09/19 4:58 PM
9.3 Example: Defining Classes and Creating Objects 329 42 43 44 45 46 47 48 49 50 51
/** Return the perimeter of this circle */ double getPerimeter() { return 2 * radius * Math.PI; } /** Set a new radius for this circle */ void setRadius(double newRadius) { radius = newRadius; } }
Since the combined class has a main method, it can be executed by the Java interpreter. The main method is the same as that in Listing 9.1. This demonstrates that you can test a class by simply adding a main method in the same class. As another example, consider television sets. Each TV is an object with states (current channel, current volume level, and power on or off) and behaviors (change channels, adjust volume, and turn on/off). You can use a class to model TV sets. The UML diagram for the class is shown in Figure 9.6.
TV
The + sign indicates a public modifier
channel: int volumeLevel: int on: boolean
The current channel (1–120) of this TV. The current volume level (1–7) of this TV. Indicates whether this TV is on/off.
+TV() +turnOn(): void +turnOff(): void +setChannel(newChannel: int): void +setVolume(newVolumeLevel: int): void +channelUp(): void +channelDown(): void +volumeUp(): void +volumeDown(): void
Constructs a default TV object. Turns on this TV. Turns off this TV. Sets a new channel for this TV. Sets a new volume level for this TV. Increases the channel number by 1. Decreases the channel number by 1. Increases the volume level by 1. Decreases the volume level by 1.
Figure 9.6 The TV class models TV sets.
Listing 9.3 gives a program that defines the TV class.
Listing 9.3 TV.java 1 2 3 4 5 6 7 8 9 10 11 12 13
public class TV { int channel = 1; // Default channel is 1 int volumeLevel = 1; // Default volume level is 1 boolean on = false; // TV is off
data fields
public TV() { }
constructor
public void turnOn() { on = true; }
turn on TV
public void turnOff() {
turn off TV
M09_LIAN9966_12_SE_C09.indd 329
16/09/19 4:58 PM
330 Chapter 9 Objects and Classes
set a new channel
set a new volume
increase channel
decrease channel
increase volume
decrease volume
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
on = false; } public void setChannel(int newChannel) { if (on && newChannel >= 1 && newChannel = 1 && newVolumeLevel 1) channel— –; } public void volumeUp() { if (on && volumeLevel < 7) volumeLevel++; } public void volumeDown() { if (on && volumeLevel > 1) volumeLevel— –; } }
The constructor and methods in the TV class are defined public so they can be accessed from other classes. Note the channel and volume level are not changed if the TV is not on. Before either of these is changed, its current value is checked to ensure it is within the correct range. Listing 9.4 gives a program that uses the TV class to create two objects.
Listing 9.4 TestTV.java main method
create a TV turn on set a new channel set a new volume create a TV turn on increase channel increase volume display state
M09_LIAN9966_12_SE_C09.indd 330
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
public class TestTV { public static void main(String[] args) { TV tv1 = new TV(); tv1.turnOn(); tv1.setChannel(30); tv1.setVolume(3); TV tv2 = new TV(); tv2.turnOn(); tv2.channelUp(); tv2.channelUp(); tv2.volumeUp(); System.out.println("tv1's + " and volume level is System.out.println("tv2's + " and volume level is
channel is " + tv1.channel " + tv1.volumeLevel); channel is " + tv2.channel " + tv2.volumeLevel);
} }
16/09/19 4:58 PM
9.4 Constructing Objects Using Constructors 331 tv1's channel is 30 and volume level is 3 tv2's channel is 3 and volume level is 2
The program creates two objects in lines 3 and 8 and invokes the methods on the objects to perform actions for setting channels and volume levels and for increasing channels and volumes. The program displays the state of the objects in lines 14–17. The methods are invoked using syntax such as tv1.turnOn() (line 4). The data fields are accessed using syntax such as tv1.channel (line 14). These examples have given you a glimpse of classes and objects. You may have many questions regarding constructors, objects, reference variables, accessing data fields, and invoking object’s methods. The sections that will follow discuss these issues in detail.
.3.1 9 9.3.2 9.3.3 9.3.4
Describe the relationship between an object and its defining class. How do you define a class? How do you declare an object’s reference variable?
Check Point
How do you create an object?
9.4 Constructing Objects Using Constructors A constructor is invoked to create an object using the new operator. Constructors are a special kind of method. They have three peculiarities:
Key Point
■■
A constructor must have the same name as the class itself.
constructor’s name
■■
Constructors do not have a return type—not even void.
no return type
■■
Constructors are invoked using the new operator when an object is created. Constructors play the role of initializing objects.
new operator
The constructor has exactly the same name as its defining class. Like regular methods, constructors can be overloaded (i.e., multiple constructors can have the same name but different signatures), making it easy to construct objects with different initial data values. It is a common mistake to put the void keyword in front of a constructor. For example, public void Circle() { }
In this case, Circle() is a method, not a constructor. Constructors are used to construct objects. To construct an object from a class, invoke a constructor of the class using the new operator, as follows:
overloaded constructors
no void
constructing objects
new ClassName(arguments);
For example, new Circle() creates an object of the Circle class using the first constructor defined in the Circle class, and new Circle(25) creates an object using the second constructor defined in the Circle class. A class normally provides a constructor without arguments (e.g., Circle()). Such a constructor is referred to as a no-arg or no-argument constructor. A class may be defined without constructors. In this case, a public no-arg constructor with an empty body is implicitly defined in the class. This constructor, called a default constructor, is provided automatically only if no constructors are explicitly defined in the class.
.4.1 What are the differences between constructors and methods? 9 9.4.2 When will a class have a default constructor?
M09_LIAN9966_12_SE_C09.indd 331
no-arg constructor default constructor
Check Point
16/09/19 4:58 PM
332 Chapter 9 Objects and Classes 9.4.3 What is wrong with each of the following programs? 1 public class ShowErrors { 2 public static void main(String[] args) { 3 ShowErrors t = new ShowErrors(5); 4 } 5 } (a)
1 2 3 4 5 6 7 8 9 10
public class ShowErrors { public static void main(String[] args) { C c = new C(5.0); System.out.println(c.value); } } class C { int value = 2; } (b)
9.4.4 What is wrong in the following code? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
class Test { public static void main(String[] args) { A a = new A(); a.print(); } } class A { String s; A(String newS) { s = newS; } public void print() { System.out.print(s); } }
9.5 Accessing Objects via Reference Variables Key Point
reference variable
An object’s data and methods can be accessed through the dot (.) operator via the object’s reference variable. Newly created objects are allocated in the memory. They can be accessed via reference variables. Objects are accessed via the object’s reference variables, which contain references to the objects. Such variables are declared using the following syntax: ClassName objectRefVar;
reference type
A class is essentially a programmer-defined type. A class is a reference type, which means that a variable of the class type can reference an instance of the class. The following statement declares the variable myCircle to be of the Circle type: Circle myCircle;
The variable myCircle can reference a Circle object. The next statement creates an object and assigns its reference to myCircle: myCircle = new Circle();
M09_LIAN9966_12_SE_C09.indd 332
16/09/19 4:58 PM
9.5 Accessing Objects via Reference Variables 333 You can write a single statement that combines the declaration of an object reference variable, the creation of an object, and the assigning of an object reference to the variable with the following syntax: ClassName objectRefVar = new ClassName();
Here is an example: Circle myCircle = new Circle();
The variable myCircle holds a reference to a Circle object.
Note An object reference variable that appears to hold an object actually contains a reference to that object. Strictly speaking, an object reference variable and an object are different, but most of the time the distinction can be ignored. Therefore, it is fine, for simplicity, to say that myCircle is a Circle object rather than use the long-winded description that myCircle is a variable that contains a reference to a Circle object.
object vs. object reference variable
Note Arrays are treated as objects in Java. Arrays are created using the new operator. An array variable is actually a variable that contains a reference to an array.
array object
9.5.1 Accessing an Object’s Data and Methods In OOP terminology, an object’s member refers to its data fields and methods. After an object is created, its data can be accessed and its methods can be invoked using the dot operator (.), also known as the object member access operator: ■■ objectRefVar.dataField
dot operator (.)
references a data field in the object.
■■ objectRefVar.method(arguments)
invokes a method on the object.
For example, myCircle.radius references the radius in myCircle and myCircle.getArea() invokes the getArea method on myCircle. Methods are invoked as operations on objects. The data field radius is referred to as an instance variable because it is dependent on a specific instance. For the same reason, the method getArea is referred to as an instance method because you can invoke it only on a specific instance. The object on which an instance method is invoked is called a calling object.
instance variable instance method calling object
Caution Recall that you use Math.methodName(arguments) (e.g., Math.pow(3, 2.5)) to invoke a method in the Math class. Can you invoke getArea() using Circle. getArea()? The answer is no. All the methods in the Math class are static methods, which are defined using the static keyword. However, getArea() is an instance method, and thus nonstatic. It must be invoked from an object using objectRefVar. methodName(arguments) (e.g., myCircle.getArea()). Further explanation will be given in Section 9.7, Static Variables, Constants, and Methods.
invoking methods
Note Usually you create an object and assign it to a variable, then later you can use the variable to reference the object. Occasionally, an object does not need to be referenced later. In this case, you can create an object without explicitly assigning it to a variable using the syntax: new Circle();
or System.out.println("Area is " + new Circle(5).getArea());
The former statement creates a Circle object. The latter creates a Circle object and invokes its getArea method to return its area. An object created in this way is known as an anonymous object.
M09_LIAN9966_12_SE_C09.indd 333
anonymous object
16/09/19 4:58 PM
334 Chapter 9 Objects and Classes
9.5.2 Reference Data Fields and the null Value reference data fields
The data fields can be of reference types. For example, the following Student class contains a data field name of the String type. String is a predefined Java class. class Student { String name; // name has the default value null int age; // age has the default value 0 boolean isScienceMajor; // isScienceMajor has default value false char gender; // gender has default value '\u0000' }
null value
default field values
If a data field of a reference type does not reference any object, the data field holds a special Java value, null. null is a literal just like true and false. While true and false are Boolean literals, null is a literal for a reference type. null is not a Java keyword, but it is a reserved word in Java. The default value of a data field is null for a reference type, 0 for a numeric type, false for a boolean type, and \u0000 for a char type. However, Java assigns no default value to a local variable inside a method. The following code displays the default values of the data fields name, age, isScienceMajor, and gender for a Student object: class TestStudent { public static void main(String[] args) { Student student = new Student(); System.out.println("name? " + student.name); System.out.println("age? " + student.age); System.out.println("isScienceMajor? " + student.isScienceMajor); System.out.println("gender? " + student.gender); } }
The following code has a compile error, because the local variables x and y are not initialized: class TestLocalVariables { public static void main(String[] args) { int x; // x has no default value String y; // y has no default value System.out.println("x is " + x); System.out.println("y is " + y); } }
Caution NullPointerException
NullPointerException is a common runtime error. It occurs when you invoke a method on a reference variable with a null value. Make sure you assign an object ref-
erence to the variable before invoking the method through the reference variable (see CheckPoint Question 9.5.5c).
9.5.3 Differences between Variables of Primitive Types and Reference Types Every variable represents a memory location that holds a value. When you declare a variable, you are telling the compiler what type of value the variable can hold. For a variable of a primitive type, the value is of the primitive type. For a variable of a reference type, the value is a reference to where an object is located. For example, as shown in Figure 9.7, the value of int variable i is int value 1, and the value of Circle object c holds a reference to where the contents of the Circle object are stored in memory.
M09_LIAN9966_12_SE_C09.indd 334
16/09/19 4:58 PM
9.5 Accessing Objects via Reference Variables 335 Created using new Circle() Primitive type
int i = 1 i
1
Object type
Circle c c
reference
c: Circle radius = 1
Figure 9.7 A variable of a primitive type holds a value of the primitive type, and a variable of a reference type holds a reference to where an object is stored in memory. When you assign one variable to another, the other variable is set to the same value. For a variable of a primitive type, the real value of one variable is assigned to the other variable. For a variable of a reference type, the reference of one variable is assigned to the other variable. As shown in Figure 9.8, the assignment statement i = j copies the contents of j into i for Primitive type assignment i = j; Before i = j;
After i = j;
i
1
i
2
j
2
j
2
Figure 9.8 Primitive variable j is copied to variable i. primitive variables. As shown in Figure 9.9, the assignment statement c1 = c2 copies the reference of c2 into c1 for reference variables. After the assignment, variables c1 and c2 refer to the same object. Object type assignment c1 = c2 Before c1 = c2
After c1 = c2
c1
c1
c2
c2
c2: Circle
c1: Circle
c2: Circle
c1: Circle
radius = 9
radius = 5
radius = 9
radius = 5
Figure 9.9 Reference variable c2 is copied to variable c1.
Note As illustrated in Figure 9.9, after the assignment statement c1 = c2, c1 points to the same object referenced by c2. The object previously referenced by c1 is no longer useful and therefore is now known as garbage. Garbage occupies memory space, so the Java runtime system detects garbage and automatically reclaims the space it occupies. This process is called garbage collection.
garbage garbage collection
Tip If you know that an object is no longer needed, you can explicitly assign null to a reference variable for the object. The JVM will automatically collect the space if the object is not referenced by any reference variable.
M09_LIAN9966_12_SE_C09.indd 335
16/09/19 4:58 PM
336 Chapter 9 Objects and Classes Check Point
9.5.1 Is an array an object or a primitive-type value? Can an array contain elements of an .5.2 9 9.5.3 9.5.4 9.5.5
object type? Describe the default value for the elements of an array. Which operator is used to access a data field or invoke a method from an object? What is an anonymous object? What is NullPointerException? What is wrong with each of the following programs?
1 public class ShowErrors { 2 public static void main(String[] args) { 3 ShowErrors t = new ShowErrors(); 4 t.x(); 5 } 6 } (a)
1 2 3 4 5 6 7 8
public class ShowErrors { public void method1() { Circle c; System.out.println("What is radius " + c.getRadius()); c = new Circle(); } }
(b)
9.5.6 What is the output of the following code? public class A { boolean x; public static void main(String[] args) { A a = new A(); System.out.println(a.x); } }
9.6 Using Classes from the Java Library The Java API contains a rich set of classes for developing Java programs. Key Point
Listing 9.1 defined the Circle class and created objects from the class. You will frequently use the classes in the Java library to develop programs. This section gives some examples of the classes in the Java library.
9.6.1 The Date Class
java.util.Date class
In Listing 2.7, ShowCurrentTime.java, you learned how to obtain the current time using System.currentTimeMillis(). You used the division and remainder operators to extract the current second, minute, and hour. Java provides a system-independent encapsulation of date and time in the java.util.Date class, as shown in Figure 9.10. java.util.Date +Date()
Constructs a Date object for the current time.
+Date(elapseTime: long)
Constructs a Date object for a given time in milliseconds elapsed since January 1, 1970, GMT. Returns a string representing the date and time.
+toString(): String +getTime(): long +setTime(elapseTime: long): void
Returns the number of milliseconds since January 1, 1970, GMT. Sets a new elapse time in the object.
Figure 9.10 A Date object represents a specific date and time.
M09_LIAN9966_12_SE_C09.indd 336
16/09/19 4:58 PM
9.6 Using Classes from the Java Library 337 You can use the no-arg constructor in the Date class to create an instance for the current date and time, the getTime() method to return the elapsed time in milliseconds since January 1, 1970, GMT, and the toString() method to return the date and time as a string, For example, the following code: java.util.Date date = new java.util.Date(); System.out.println("The elapsed time since Jan 1, 1970 is " + date.getTime() + " milliseconds"); System.out.println(date.toString());
create object get elapsed time invoke toString
displays the output as follows: The elapsed time since Jan 1, 1970 is 1324903419651 milliseconds Mon Dec 26 07:43:39 EST 2011
The Date class has another constructor, Date(long elapseTime), which can be used to construct a Date object for a given time in milliseconds elapsed since January 1, 1970, GMT.
9.6.2 The Random Class You have used Math.random() to obtain a random double value between 0.0 and 1.0 (excluding 1.0). Another way to generate random numbers is to use the java.util.Random class, as shown in Figure 9.11, which can generate a random int, long, double, float, and boolean value. java.util.Random +Random()
Constructs a Random object with the current time as its seed.
+Random(seed: long)
Constructs a Random object with a specified seed.
+nextInt(): int
Returns a random int value.
+nextInt(n: int): int
Returns a random int value between 0 and n (excluding n).
+nextLong(): long
Returns a random long value.
+nextDouble(): double
Returns a random double value between 0.0 and 1.0 (excluding 1.0).
+nextFloat(): float
Returns a random float value between 0.0F and 1.0F (excluding 1.0F).
+nextBoolean(): boolean
Returns a random boolean value.
Figure 9.11 A Random object can be used to generate random values. When you create a Random object, you have to specify a seed or use the default seed. A seed is a number used to initialize a random number generator. The no-arg constructor creates a Random object using the current elapsed time as its seed. If two Random objects have the same seed, they will generate identical sequences of numbers. For example, the following code creates two Random objects with the same seed, 3: Random generator1 = new Random(3); System.out.print("From generator1: "); for (int i = 0; i < 10; i++) System.out.print(generator1.nextInt(1000) + " "); Random generator2 = new Random(3); System.out.print("\nFrom generator2: "); for (int i = 0; i < 10; i++) System.out.print(generator2.nextInt(1000) + " ");
The code generates the same sequence of random int values: From generator1: 734 660 210 581 128 202 549 564 459 961 From generator2: 734 660 210 581 128 202 549 564 459 961
M09_LIAN9966_12_SE_C09.indd 337
16/09/19 4:58 PM
338 Chapter 9 Objects and Classes Note The ability to generate the same sequence of random values is useful in software testing and many other applications. In software testing, often you need to reproduce the test cases from a fixed sequence of random numbers.
same sequence
Note You can generate random numbers using the java.security.SecureRandom class rather than the Random class. The random numbers generated from the Random are deterministic and they can be predicted by hackers. The random numbers generated from the SecureRandom class are nondeterministic and are secure.
SecureRandom
9.6.3 The Point2D Class Java API has a convenient Point2D class in the javafx.geometry package for representing a point in a two-dimensional plane. The UML diagram for the class is shown in Figure 9.12. javafx.geometry.Point2D +Point2D(x: double, y: double) +distance(x: double, y: double): double +distance(p: Point2D): double +getX(): double +getY(): double +midpoint(p: Point2D): Point2D +toString(): String
Constructs a Point2D object with the specified x- and y-coordinates. Returns the distance between this point and the specified point (x, y). Returns the distance between this point and the specified point p. Returns the x-coordinate from this point. Returns the y-coordinate from this point. Returns the midpoint between this point and point p. Returns a string representation for the point.
Figure 9.12 A Point2D object represents a point with x- and y-coordinates. You can create a Point2D object for a point with the specified x- and y-coordinates, use the distance method to compute the distance from this point to another point, and use the toString() method to return a string representation of the point. Listing 9.5 gives an example of using this class.
Listing 9.5 TestPoint2D.java
create an object invoke toString()
get distance get midpoint
M09_LIAN9966_12_SE_C09.indd 338
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
import java.util.Scanner; import javafx.geometry.Point2D; public class TestPoint2D { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("Enter point1's x-, y–coordinates: "); double x1 = input.nextDouble(); double y1 = input.nextDouble(); System.out.print("Enter point2's x-, y–coordinates: "); double x2 = input.nextDouble(); double y2 = input.nextDouble(); Point2D p1 = new Point2D(x1, y1); Point2D p2 = new Point2D(x2, y2); System.out.println("p1 is " + p1.toString()); System.out.println("p2 is " + p2.toString()); System.out.println("The distance between p1 and p2 is " + p1.distance(p2)); System.out.println("The midpoint between p1 and p2 is " + p1.midpoint(p2).toString()); } }
16/09/19 4:58 PM
9.7 Static Variables, Constants, and Methods 339 Enter point1's x-, y-coordinates: 1.5 5.5 Enter point2's x-, y-coordinates: −5.3 −4.4 p1 is Point2D [x = 1.5, y = 5.5] p2 is Point2D [x = −5.3, y = −4.4] The distance between p1 and p2 is 12.010412149464313 The midpoint between p1 and p2 is Point2D [x = −1.9, y = 0.5499999999999998]
This program creates two objects of the Point2D class (lines 15 and 16). The toString() method returns a string that describes the object (lines 17 and 18). Invoking p1.distance(p2) returns the distance between the two points (line 20). Invoking p1.midpoint(p2) returns the midpoint between the two points (line 22).
Note The Point2D class is defined in the javafx.geometry package, which is in the JavaFX module. To run this program, you need to install JavaFX. See Supplement II.F for installing and using JavaFX.
.6.1 How do you create a Date for the current time? How do you display the current time? 9 9.6.2 How do you create a Point2D? Suppose p1 and p2 are two instances of Point2D, 9.6.3
Check Point
how do you obtain the distance between the two points? How do you obtain the midpoint between the two points? Which packages contain the classes Date, Random, Point2D, System, and Math?
9.7 Static Variables, Constants, and Methods A static variable is shared by all objects of the class. A static method cannot access instance members (i.e., instance data fields and methods) of the class. The data field radius in the Circle class is known as an instance variable. An instance variable is tied to a specific instance of the class; it is not shared among objects of the same class. For example, suppose that you create the following objects: Circle circle1 = new Circle(); Circle circle2 = new Circle(5);
The radius in circle1 is independent of the radius in circle2 and is stored in a different memory location. Changes made to circle1’s radius do not affect circle2’s radius, and vice versa. If you want all the instances of a class to share data, use static variables, also known as class variables. Static variables store values for the variables in a common memory location. Because of this common location, if one object changes the value of a static variable, all objects of the same class are affected. Java supports static methods as well as static variables. Static methods can be called without creating an instance of the class. Let’s modify the Circle class by adding a static variable numberOfObjects to count the number of circle objects created. When the first object of this class is created, n umberOfObjects is 1. When the second object is created, numberOfObjects becomes 2. The UML of the new circle class is shown in Figure 9.13. The Circle class defines the instance variable radius and the static variable numberOfObjects, the instance methods getRadius, s etRadius, and getArea, and the static method getNumberOfObjects. (Note static variables and methods are underlined in the UML class diagram.)
M09_LIAN9966_12_SE_C09.indd 339
Key Point Static vs. instance instance variable
VideoNote
Static vs. instance
static variable
static method
16/09/19 4:58 PM
340 Chapter 9 Objects and Classes UML Notation: underline: static variables or methods
instantiate
Circle
circle1: Circle
Memory
radius = 1 numberOfObjects = 2
1
radius
2
numberOfObjects
5
radius
radius: double numberOfObjects: int getNumberOfObjects(): int getArea(): double
instantiate
After two Circle Objects were created, numberOfObjects is 2.
circle2: Circle radius = 5 numberOfObjects = 2
Figure 9.13 Instance variables belong to the instances and have memory storage independent of one another. Static variables are shared by all the instances of the same class. To declare a static variable or define a static method, put the modifier static in the variable or method declaration. The static variable numberOfObjects and the static method getNumberOfObjects() can be declared as follows: declare static variable
static int numberOfObjects;
define static method
static int getNumberObjects() { return numberOfObjects; }
declare constant
Constants in a class are shared by all objects of the class. Thus, constants should be declared as final static. For example, the constant PI in the Math class is defined as follows: final static double PI = 3.14159265358979323846;
The new circle class is defined in Listing 9.6.
Listing 9.6 Circle.java (for CircleWithStaticMembers)
static variable
increase by 1
increase by 1
static method
M09_LIAN9966_12_SE_C09.indd 340
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
public class Circle { /** The radius of the circle */ double radius; /** The number of objects created */ static int numberOfObjects = 0; /** Construct a circle with radius 1 */ Circle() { radius = 1; numberOfObjects++; } /** Construct a circle with a specified radius */ Circle(double newRadius) { radius = newRadius; numberOfObjects++; } /** Return numberOfObjects */ static int getNumberOfObjects() { return numberOfObjects; } /** Return the area of this circle */
16/09/19 4:58 PM
9.7 Static Variables, Constants, and Methods 341 26 27 28 29
double getArea() { return radius * radius * Math.PI; } }
Method getNumberOfObjects() in Circle is a static method. All the methods in the Math class are static. The main method is static, too. Instance methods (e.g., getArea()) and instance data (e.g., radius) belong to instances and can be used only after the instances are created. They are accessed via a reference variable. Static methods (e.g., getNumberOfObjects()) and static data (e.g., numberOfObjects) can be accessed from a reference variable or from their class name. The program in Listing 9.7 demonstrates how to use instance and static variables and methods and illustrates the effects of using them.
Listing 9.7 TestCircleWithStaticMembers.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
public class TestCircleWithStaticMembers { /** Main method */ public static void main(String[] args) { System.out.println("Before creating objects"); System.out.println("The number of Circle objects is " + Circle.numberOfObjects);
static variable
// Create c1 Circle c1 = new Circle(); // Use the Circle class in Listing 9.6 // Display c1 BEFORE c2 is created System.out.println("\nAfter creating c1"); System.out.println("c1: radius (" + c1.radius + ") and number of Circle objects (" + c1.numberOfObjects + ")");
instance variable static variable
// Create c2 Circle c2 = new Circle(5); // Modify c1 c1.radius = 9; // Display c1 and c2 AFTER c2 was created System.out.println("\nAfter creating c2 and modifying c1"); System.out.println("c1: radius (" + c1.radius + ") and number of Circle objects (" + c1.numberOfObjects + ")"); System.out.println("c2: radius (" + c2.radius + ") and number of Circle objects (" + c2.numberOfObjects + ")");
instance variable
static variable
static variable
} }
Before creating objects The number of Circle objects is 0 After creating c1 c1: radius (1.0) and number of Circle objects (1) After creating c2 and modifying c1 c1: radius (9.0) and number of Circle objects (2) c2: radius (5.0) and number of Circle objects (2)
M09_LIAN9966_12_SE_C09.indd 341
16/09/19 4:58 PM
342 Chapter 9 Objects and Classes When you compile TestCircleWithStaticMembers.java, the Java compiler automatically compiles Circle.java if it has not been compiled since the last change. Static variables and methods can be accessed without creating objects. Line 6 displays the number of objects, which is 0, since no objects have been created. The main method creates two circles c1 and c2 (lines 9 and18). The instance v ariable radius in c1 is modified to become 9 (line 21). This change does not affect the instance variable radius in c2 , since these two instance variables are independent. The static variable numberOfObjects becomes 1 after c1 is created (line 9), and it becomes 2 after c2 is created (line 18). Note PI is a constant defined in Math and Math.PI references the constant. c1.numberOfObjects (line 27) and c2.numberOfObjects (line 30) are better replaced by Circle. numberOfObjects. This improves readability because other programmers can easily recognize the static variable. You can also replace Circle.numberOfObjects with Circle. getNumberOfObjects().
Tip Use ClassName.methodName(arguments) to invoke a static method and ClassName.staticVariable to access a static variable. This improves readability because this makes static methods and data easy to spot.
use class name
An instance method can invoke an instance or static method, and access an instance or static data field. A static method can invoke a static method and access a static data field. However, a static method cannot invoke an instance method or access an instance data field, since static methods and static data fields don’t belong to a particular object. The relationship between static and instance members is summarized in the following diagram: can invoke can access An instance method
cannot invoke
an instance method
cannot access
an instance data field A static method
can invoke
a static method
can access
a static data field
can invoke can access
an instance method an instance data field a static method a static data field
For example, the following code is wrong. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
M09_LIAN9966_12_SE_C09.indd 342
public class A { int i = 5; static int k = 2; public static void main(String[] args) { int j = i; // Wrong because i is an instance variable m1(); // Wrong because m1() is an instance method } public void m1() { // Correct since instance and static variables and methods // can be used in an instance method i = i + k + m2(i, k); } public static int m2(int i, int j) { return (int)(Math.pow(i, j)); } }
16/09/19 4:58 PM
9.7 Static Variables, Constants, and Methods 343 Note if you replace the preceding code with the following new code, the program would be fine, because the instance data field i and method m1 are now accessed from an object a (lines 7 and 8): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public class A { int i = 5; static int k = 2; public static void main(String[] args) { A a = new A(); int j = a.i; // OK, a.i accesses the object's instance variable a.m1(); // OK, a.m1() invokes the object's instance method } public void m1() { i = i + k + m2(i, k); } public static int m2(int i, int j) { return (int)(Math.pow(i, j)); } }
Design Guide How do you decide whether a variable or a method should be instance or static? A variable or a method that is dependent on a specific instance of the class should be an instance variable or method. A variable or a method that is not dependent on a specific instance of the class should be a static variable or method. For example, every circle has its own radius, so the radius is dependent on a specific circle. Therefore, radius is an instance variable of the Circle class. Since the getArea method is dependent on a specific circle, it is an instance method. None of the methods in the Math class, such as random, pow, sin, and cos, is dependent on a specific instance. Therefore, these methods are static methods. The main method is static and can be invoked directly from a class.
instance or static?
Caution It is a common design error to define an instance method that should have been defined as static. For example, the method factorial(int n) should be defined as static, as shown next, because it is independent of any specific instance.
public class Test { public int factorial(int n) { int result = 1; for (int i = 1; i
java.util.*?> javafx.scene.*?> javafx.scene.control.*?> javafx.scene.layout.*?>
Listing 31.17 FXMLDocumentController.java package calculator; import import import import import import
java.net.URL; java.util.ResourceBundle; javafx.event.ActionEvent; javafx.fxml.FXML; javafx.fxml.Initializable; javafx.scene.control.Label;
public class FXMLDocumentController implements Initializable { @FXML private Label label; @FXML private void handleButtonAction(ActionEvent event) { System.out.println("You clicked me!"); label.setText("Hello World!"); } @Override public void initialize(URL url, ResourceBundle rb) { // TODO } }
Figure 31.35 You can choose JavaFX in the Categories and JavaFX FXML Application in the Project to create a FXML project.
M31_LIAN0182_11_SE_C31.indd 37
5/22/17 3:10 PM
31-38 Chapter 31 Advanced JavaFX and FXML
Figure 31.36 You can enter project information in the New JavaFX Application dialog.
Figure 31.37 A FXML project is created.
31.11.3 Creating User Interfaces We now turn our attention to developing a simple calculator as shown in Figure 31.38. The Calculator program enables the user to enter numbers and perform addition, subtraction, multiplication, and division.
Figure 31.38 The application performs arithmetic operations. When you create a JavaFX FXML project, NetBeans creates a default .fxml file that contains the contents for a simple sample user interface. To view the user interface, double-click the .fxml file to open the Scene Builder, as shown in Figure 31.39. Note NetBeans can automatically detect the Scene Builder after it is installed on your machine.
M31_LIAN0182_11_SE_C31.indd 38
5/22/17 3:10 PM
31.11 Developing JavaFX Programs Using FXML 31-39
Figure 31.39 Double-click the .fxml file to open the Scene Builder.
Figure 31.40 You can open the Library pane by clicking the Library icon and choose View as List. To start a new user interface, delete the default user interface in the .fxml file from the content pane, as shown in Figure 31.41. Here are the steps to create a new user interface: 1. (Optional) On some systems, the components in the Library pane are not visible by sections. Click the Library icon to open the context menu as shown in Figure 31.40 and choose View as List. 2. Drag a BorderPane into the user interface and drag an HBox to the center of the BorderPane and another HBox to the bottom of the BorderPane. Set the alignment of both HBox to CENTER as shown in Figure 31.42. Set the Spacing property in the Layout section of the Inspector to 5. When you select a component in the visual layout, the properties of the component are displayed in the Inspector pane, where you can set the properties.
M31_LIAN0182_11_SE_C31.indd 39
5/22/17 3:10 PM
31-40 Chapter 31 Advanced JavaFX and FXML
Figure 31.41 The UI is empty after deleting the default button in the pane.
Figure 31.42 A BorderPane is dropped to the UI and an HBox is placed at the bottom of the BorderPane. 3. Drag and drop a Label, a TextField, a Label, a TextField, a Label, and a TextField and change the label’s text to Number 1, Number 2, and Result, as shown in Figure 31.43. Set the Pref Column Count property for each text field to 2 in the Layout section of the Inspector. In the Code section of the Inspector, set the id for the text fields to tfNumber1, tfNumber2, and tfResult, as shown in Figure 31.44. These ids are useful to reference the text fields and obtain their values in the controller. 4. Drag and drop four Buttons to the second HBox and set their text property to Add, Subtract, Multiply, and Divide, as shown in Figure 31.45.
Figure 31.43 The labels and text fields are dropped to the UI.
M31_LIAN0182_11_SE_C31.indd 40
5/22/17 3:10 PM
Figure 31.44 Set the appropriate id for the text fields.
Figure 31.45 The buttons are dropped to the HBox. After you create and make changes to the user interface in the content pane, you need to save the changes by choosing File, Save from the menu bar in the Scene Builder. The .fxml file is updated and synchronized with the changes in the content pane. You can view the contents in the .fxml file from NetBeans, as shown in Figure 31.46.
Figure 31.46 You can view the contents of the FXML file.
M31_LIAN0182_11_SE_C31.indd 41
31-41
5/22/17 3:10 PM
31-42 Chapter 31 Advanced JavaFX and FXML
31.11.4 Handling Events in the Controller The .fxml file describes the user interface. You write the code to implement the logic in the controller file, as shown in Listing 31.18.
Listing 31.18 FXMLDocumentController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
package calculator; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.TextField; public class FXMLDocumentController { @FXML private TextField tfNumber1, tfNumber2, tfResult; @FXML private void addButtonAction(ActionEvent event) { tfResult.setText(getResult('+') + ""); } @FXML private void subtractButtonAction(ActionEvent event) { tfResult.setText(getResult('−') + ""); } @FXML private void multiplyButtonAction(ActionEvent event) { tfResult.setText(getResult('*') + ""); } @FXML private void divideButtonAction(ActionEvent event) { tfResult.setText(getResult('/') + ""); } private double getResult(char op) { double number1 = Double.parseDouble(tfNumber1.getText()); double number2 = Double.parseDouble(tfNumber2.getText()); switch (op) { case '+': return number1 + number2; case '−': return number1 − number2; case '*': return number1 * number2; case '/': return number1 / number2; } return Double.NaN; } }
The controller class declares three TextFields, tfNumber1, tfNumber2, and tfResult (line 9). The @FXML annotation denotes that these data fields are linked to the text fields in the user interface. Recall in the user interface, we set the id for the three text fields as tfNumber1, tfNumber2, and tfResult. The codes for handling the events from the buttons are defined in the methods addButtonAction, subtractButtonAction, multiplyButtonAction, and divideButtonAction (lines 11–29). The @FXML annotation is used to denote that these methods will be tied to the button actions in the view. Through the @FXML annotation, the data fields and methods in the controller are linked to the components and actions defined in the .fxml file.
M31_LIAN0182_11_SE_C31.indd 42
5/22/17 3:10 PM
31.11 Developing JavaFX Programs Using FXML 31-43
31.11.5 Linking View with Controller You can now link the actions from the components in the view with the processing methods in the controller. Here are the steps to accomplish it: 1. Add the following attribute in the tag for using a controller with the view. fx:controller="calculator.FXMLDocumentController"
2. Double-click the .fxml file in the project to display the visual layout window. In the Inspector for the Add button, choose addButtonAction from a list of action processing methods, as shown in Figure 31.47. The complete code for the .fxml file is shown in Listing 31.19.
Listing 31.19 FXMLDocument.fxml
java.util.*?> javafx.scene.*?> javafx.scene.control.*?> javafx.scene.layout.*?>
M31_LIAN0182_11_SE_C31.indd 43
5/22/17 3:10 PM
31-44 Chapter 31 Advanced JavaFX and FXML
31.11.6 Running the Project The code in the model is automatically generated as shown in Listing 31.15. This is the main program that loads the FXML to create the user interface in a Parent object (lines 12 and 13). The parent object is then added to the scene (line 14). The scene is set to the stage (line 15). The stage is displayed in line 16.
Figure 31.47 Choosing addButtonAction to generate the code for handling action for the Add button.
Chapter Summary 1. JavaFX provides the cascading style sheets based on CSS. You can use the
etStylesheets method to load a style sheet and use the setStyle, s g etStyleClass, and setId methods to set JavaFX CSS for nodes.
2. JavaFX provides the QuadCurve, CubicCurve, and Path classes for creating advanced shapes.
3. JavaFX supports coordinate transformations using translation, rotation, and scaling. 4. You can specify the pattern for a stroke, how the lines are joined in a stroke, the width of a stroke, and the type of a stroke.
5. You can create menus using the
Menu , MenuItem , CheckMenuItem , and
RadioMenuItem classes.
6. You can create context menus using the ContextMenu class. 7. The SplitPane can be used to display multiple panes horizontally or vertically and allows the user to adjust the sizes of the panes.
8. The TabPane can be used to display multiple panes with tabs for selecting panes. 9. You can create and display tables using the TableView and TableColumn classes. 10. You can create JavaFX user interfaces using FXML. FXML is XML-based script language for describing the user interface. Using FXML enables you to separate user interface from the logic of Java code.
11. JavaFX Scene Builder is a visual tool for creating the user interface without manually writing the FXML scripts.
M31_LIAN0182_11_SE_C31.indd 44
5/22/17 3:10 PM
Programming Exercises 31-45
Quiz Answer the quiz for this chapter online at the book Companion Website.
Programming Exercises Sections 31.2
31.1 (Use JavaFX CSS) Create a CSS style sheet that defines a class for white fill and black stroke color and an id for red stroke and green color. Write a program that displays four circles and uses the style class and id. The sample run of the program is shown in Figure 31.48a.
(a)
(b)
(c)
Figure 31.48 (a) The border and the color style for the shapes are defined in a style class. (b) Exercise 31.2 displays a tic-tac-toe board with images using style sheet for border. (c) Three cards are randomly selected.
*31.2 (Tic-tac-toe board) Write a program that displays a tic-tac-toe board, as shown
*31.3
in Figure 31.48b. A cell may be X, O, or empty. What to display at each cell is randomly decided. The X and O are images in the files x.gif and o.gif. Use the style sheet for border. (Display three cards) Write a program that displays three cards randomly selected from a deck of 52, as shown in Figure 31.48c. The card image files are named 1.png, 2.png, . . ., 52.png and stored in the image/card directory. All the three cards are distinct and selected randomly. Hint: You can select random cards by storing the numbers 1–52 to an array, perform a random shuffle using Section 7.2.6, and use the first three numbers in the array as the file names for the image. Use the style sheet for border.
Sections 31.3
31.4 (Color and font) Write a program that displays five texts vertically, as shown in
Figure 31.49a. Set a random color and opacity for each text and set the font of each text to Times Roman, bold, italic, and 22 pixels.
(a)
(b)
(c)
Figure 31.49 (a) Five texts are displayed with a random color and a specified font. (b) A path is displayed inside the circle. (c) Two circles are displayed in an oval.
M31_LIAN0182_11_SE_C31.indd 45
5/22/17 3:10 PM
31-46 Chapter 31 Advanced JavaFX and FXML *31.5 (Cubic curve) Write a program that creates two shapes: a circle and a path consist *31.6
ing of two cubic curves, as shown in Figure 31.49b. (Eyes) Write a program that displays two eyes in an oval, as shown in Figure 31.49c.
Sections 31.4
*31.7 (Translation) Write a program that displays a rectangle with upper-left corner point at (40, 40), width 50, and height 40. Enter the values in the text fields x and y and press the Translate button to translate the rectangle to a new location, as shown in Figure 31.50a.
(a)
(b)
(c)
Figure 31.50 (a) Exercise 31.7 translates coordinates. (b) Exercise 31.8 rotates coordinates. (c) Exercise 31.9 scales coordinates.
*31.8 (Rotation) Write a program that displays an ellipse. The ellipse is centered in the *31.9 *31.10
pane with width 60 and height 40. Enter the value in the text field Angle and press the Rotate button to rotate the ellipse, as shown in Figure 31.50b. (Scale graphics) Write a program that displays an ellipse. The ellipse is centered in the pane with width 60 and height 40. Enter the scaling factors in the text fields and press the Scale button to scale the ellipse, as shown in Figure 31.50c. (Plot the sine function) Write a program that plots the sine function, as shown in Figure 31.51a.
(a)
(b)
Figure 31.51 (a) Exercise 31.10 displays a sine function. (b) Exercise 31.11 displays the log function.
*31.11 (Plot the log function) Write a program that plots the log function, as shown in Figure 31.51a.
*31.12 (Plot the n2 function) Write a program that plots the n2 function, as shown in Figure 31.51b 2a.
M31_LIAN0182_11_SE_C31.indd 46
5/22/17 3:10 PM
Programming Exercises 31-47
(a)
(b)
Figure 31.52 (a) Exercise 31.13 displays the n2 function. (b) Exercise 31.13 displays several functions.
*31.13 (Plot the log, n, nlogn, and n2 functions) Write a program that plots the log, n, nlogn, *31.14
and n2 functions, as shown in Figure 31.52b. (Scale and rotate graphics) Write a program that enables the user to scale and rotate the STOP sign, as shown in Figure 31.53. The user can press the UP/DOWN arrow key to increase/decrease the size and press the RIGHT/LEFT arrow key to rotate left or right.
Figure 31.53 The program can rotate and scale the painting.
Sections 31.5
*31.15 (Sunshine) Write a program that displays a circle filled with a gradient color to
animate a sun and display light rays coming out from the sun using dashed lines, as shown in Figure 31.54a.
(a)
(b)
Figure 31.54 (a) Exercise 31.15 displays the sunshine. (b) Exercise 31.16 displays a cylinder.
*31.16 (Display a cylinder) Write a program that displays a cylinder, as shown in Figure 31.54b. Use dashed strokes to draw the dashed arc.
M31_LIAN0182_11_SE_C31.indd 47
5/22/17 3:10 PM
31-48 Chapter 31 Advanced JavaFX and FXML Sections 31.6
* 31.17 (Create an investment value calculator) Write a program that calculates the future value of an investment at a given interest rate for a specified number of years. The formula for the calculation is as follows: futureValue = investmentAmount × (1 + monthlyInterestRate)years×12
Use text fields for interest rate, investment amount, and years. Display the future amount in a text field when the user clicks the Calculate button or chooses Calculate from the Operation menu (see Figure 31.55). Click the Exit menu to exit the program.
Figure 31.55 The user enters the investment amount, years, and interest rate to compute future value.
Sections 31.8
*31.18 (Use popup menus) Modify Listing 31.9, MenuDemo.java, to create a popup
menu that contains the menus Operations and Exit, as shown in Figure 31.56. The popup is displayed when you click the right mouse button on the panel that contains the labels and the text fields.
Figure 31.56 The popup menu contains the commands to perform arithmetic operations.
*31.19 (Use SplitPane) Create a program that displays four shapes in split panes, as shown in Figure 31.57a.
Sections 31.9
*31.20 (Use tab panes) Modify Listing 31.12, TabPaneDemo.java, to add a pane of radio buttons for specifying the tab placement of the tab pane, as shown in Figure 31.57b and c.
M31_LIAN0182_11_SE_C31.indd 48
5/22/17 3:10 PM
Programming Exercises 31-49
(a)
(b)
(c)
Figure 31.57 (a) Four shapes are displayed in split panes. (b and c) The radio buttons let you choose the tab placement of the tabbed pane.
*31.21 (Use tab panes) Write a program using tab panes for performing integer and rational number arithmetic as shown in Figure 31.58.
Figure 31.58 A tab pane is used to select panes that perform integer operations and rational number operations.
Sections 31.10
*31.22 (Use table view) Revise Listing 31.14 to add a button to delete the selected row from the table, as shown in Figure 31.59.
Figure 31.59 Clicking the Delete Selected Row button removes the selected row from the table.
M31_LIAN0182_11_SE_C31.indd 49
5/22/17 3:10 PM
CHAPTER
32 Multithreading and Parallel Programming Objectives ■■
To get an overview of multithreading (§32.2).
■■
To develop task classes by implementing the Runnable interface (§32.3).
■■
To create threads to run tasks using the Thread class (§32.3).
■■
To control threads using the methods in the Thread class (§32.4).
■■
To control animations using threads and use Platform.runLater to run the code in the application thread (§32.5).
■■
To execute tasks in a thread pool (§32.6).
■■
To use synchronized methods or blocks to synchronize threads to avoid race conditions (§32.7).
■■
To synchronize threads using locks (§32.8).
■■
To facilitate thread communications using conditions on locks (§§32.9 and 32.10).
■■
To use blocking queues (ArrayBlockingQueue, LinkedBlockingQueue, and PriorityBlockingQueue) to synchronize access to a queue (§32.11).
■■
To restrict the number of concurrent accesses to a shared resource using semaphores (§32.12).
■■
To use the resource-ordering technique to avoid deadlocks (§32.13).
■■
To describe the life cycle of a thread (§32.14).
■■
To create synchronized collections using the static methods in the Collections class (§32.15).
■■
To develop parallel programs using the Fork/Join Framework (§32.16).
M32_LIAN0182_11_SE_C32.indd 1
5/22/17 12:34 PM
32-2 Chapter 32 Multithreading and Parallel Programming
32.1 Introduction Multithreading enables multiple tasks in a program to be executed concurrently. multithreading
Key Point
One of the powerful features of Java is its built-in support for multithreading—the concurrent running of multiple tasks within a program. In many programming languages, you have to invoke system-dependent procedures and functions to implement multithreading. This chapter introduces the concepts of threads and how multithreading programs can be developed in Java.
32.2 Thread Concepts thread task
Key Point
A program may consist of many tasks that can run concurrently. A thread is the flow of execution, from beginning to end, of a task. A thread provides the mechanism for running a task. With Java, you can launch multiple threads from a program concurrently. These threads can be executed simultaneously in multiprocessor systems, as shown in Figure 32.1a. Thread 1
Thread 1
Thread 2
Thread 2
Thread 3
Thread 3 (a)
(b)
Figure 32.1 (a) Multiple threads running on multiple CPUs. (b) Multiple threads share a single CPU. In single-processor systems, as shown in Figure 32.1b, the multiple threads share CPU time, known as time sharing, and the operating system is responsible for scheduling and allocating resources to them. This arrangement is practical because most of the time the CPU is idle. It does nothing, for example, while waiting for the user to enter data. Multithreading can make your program more responsive and interactive as well as enhance performance. For example, a good word processor lets you print or save a file while you are typing. In some cases, multithreaded programs run faster than single-threaded programs even on single-processor systems. Java provides exceptionally good support for creating and running threads, and for locking resources to prevent conflicts. You can create additional threads to run concurrent tasks in the program. In Java, each task is an instance of the Runnable interface, also called a runnable object. A thread is essentially an object that facilitates the execution of a task.
time sharing
task runnable object thread Check Point
32.2.1 Why is multithreading needed? How can multiple threads run simultaneously in a single-processor system?
32.2.2 What is a runnable object? What is a thread?
32.3 Creating Tasks and Threads Key Point Runnable interface run() method
M32_LIAN0182_11_SE_C32.indd 2
A task class must implement the Runnable interface. A task must be run from a thread. Tasks are objects. To create tasks, you have to first define a class for tasks, which implements the Runnable interface. The Runnable interface is rather simple. All it contains is the run() method. You need to implement this method to tell the system how your thread is going to run. A template for developing a task class is shown in Figure 32.2a.
5/22/17 12:34 PM
32.3 Creating Tasks and Threads 32-3 java.lang.Runnable
TaskClass
// Custom task class public class TaskClass implements Runnable { ... public TaskClass(...) { ... }
}
// Implement the run method in Runnable public void run() { // Tell system how to run custom thread ... } ...
// Client class public class Client { ... public void someMethod() { ... // Create an instance of TaskClass TaskClass task = new TaskClass(...); // Create a thread Thread thread = new Thread(task); // Start a thread thread.start(); ...
}
} ...
(a)
(b)
Figure 32.2 Define a task class by implementing the Runnable interface. Once you have defined a TaskClass, you can create a task using its constructor. For example, TaskClass task = new TaskClass(...);
A task must be executed in a thread. The Thread class contains the constructors for creating threads and many useful methods for controlling threads. To create a thread for a task, use
Thread class
create a task
Thread thread = new Thread(task);
You can then invoke the start() method to tell the JVM that the thread is ready to run, as follows:
create a thread
thread.start();
The JVM will execute the task by invoking the task’s run() method. Figure 32.2b outlines the major steps for creating a task, a thread, and starting the thread. Listing 32.1 gives a program that creates three tasks and three threads to run them. ■■
The first task prints the letter a 100 times.
■■
The second task prints the letter b 100 times.
■■
The third task prints the integers 1 through 100.
start a thread
When you run this program, the three threads will share the CPU and take turns printing letters and numbers on the console. Figure 32.3 shows a sample run of the program.
Figure 32.3 Tasks printA, printB, and print100 are executed simultaneously to d isplay the letter a 100 times, the letter b 100 times, and the numbers from 1 to 100.
M32_LIAN0182_11_SE_C32.indd 3
5/22/17 12:34 PM
32-4 Chapter 32 Multithreading and Parallel Programming
Listing 32.1 TaskThreadDemo.java
create tasks
create threads
start threads
task class
run
task class
run
M32_LIAN0182_11_SE_C32.indd 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
public class TaskThreadDemo { public static void main(String[] args) { // Create tasks Runnable printA = new PrintChar('a', 100); Runnable printB = new PrintChar('b', 100); Runnable print100 = new PrintNum(100); // Create threads Thread thread1 = new Thread(printA); Thread thread2 = new Thread(printB); Thread thread3 = new Thread(print100); // Start threads thread1.start(); thread2.start(); thread3.start(); } } // The task for printing a character a specified number of times class PrintChar implements Runnable { private char charToPrint; // The character to print private int times; // The number of times to repeat /** Construct a task with a specified character and number of * times to print the character */ public PrintChar(char c, int t) { charToPrint = c; times = t; } @Override /** Override the run() method to tell the system * what task to perform */ public void run() { for (int i = 0; i < times; i++) { System.out.print(charToPrint); } } } // The task class for printing numbers from 1 to n for a given n class PrintNum implements Runnable { private int lastNum; /** Construct a task for printing 1, 2, ..., n */ public PrintNum(int n) { lastNum = n; } @Override /** Tell the thread how to run */ public void run() { for (int i = 1; i lblText.setText(text)); // lambda exp Thread.sleep(200); } } catch (InterruptedException ex) { } }).start();
Check Point
2.5.1 3 32.5.2 32.5.3 32.5.4
What causes the text to flash? Is an instance of FlashText a runnable object? What is the purpose of using Platform.runLater? Can you replace the code in lines 27–32 using the following code? Platform.runLater(e -> lblText.setText(text));
2.5.5 What happens if line 34 (Thread.sleep(200)) is not used? 3 32.5.6 There is an issue in Listing 16.9, ListViewDemo. If you press the CTRL key and select Canada, Demark, and China in this order, you will get an ArrayIndexOutBoundsException. What is the reason for this error and how do you fix it? (Thanks to Henri Heimonen of Finland for contributing this question).
32.6 Thread Pools Key Point
A thread pool can be used to execute tasks efficiently. In Section 32.3, Creating Tasks and Threads, you learned how to define a task class by implementing java.lang.Runnable, and how to create a thread to run a task like this: Runnable task = new TaskClass(...); new Thread(task).start();
M32_LIAN0182_11_SE_C32.indd 10
5/22/17 12:34 PM
32.6 Thread Pools 32-11 This approach is convenient for a single task execution, but it is not efficient for a large number of tasks because you have to create a thread for each task. Starting a new thread for each task could limit throughput and cause poor performance. Using a thread pool is an ideal way to manage the number of tasks executing concurrently. Java provides the E xecutor interface for executing tasks in a thread pool and the ExecutorService interface for managing and controlling tasks. ExecutorService is a subinterface of Executor, as shown in Figure 32.7.
«interface» java.util.concurrent.Executor +execute(Runnable object): void
Executes the runnable task.
«interface» java.util.concurrent.ExecutorService +shutdown(): void +shutdownNow(): List +isShutdown(): boolean +isTerminated(): boolean
Shuts down the executor, but allows the tasks in the executor to complete. Once shut down, it cannot accept new tasks. Shuts down the executor immediately even though there are unfinished threads in the pool. Returns a list of unfinished tasks. Returns true if the executor has been shut down. Returns true if all tasks in the pool are terminated.
Figure 32.7 The Executor interface executes threads and the ExecutorService subinterface manages threads. To create an Executor object, use the static methods in the Executors class, as shown in Figure 32.8. The newFixedThreadPool(int) method creates a fixed number of threads in a pool. If a thread completes executing a task, it can be reused to execute another task. If a thread terminates due to a failure prior to shutdown, a new thread will be created to replace it if all the threads in the pool are not idle and there are tasks waiting for execution. The newCachedThreadPool() method creates a new thread if all the threads in the pool are not idle and there are tasks waiting for execution. A thread in a cached pool will be terminated if it has not been used for 60 seconds. A cached pool is efficient for many short tasks.
java.util.concurrent.Executors +newFixedThreadPool(numberOfThreads: int): ExecutorService
Creates a thread pool with a fixed number of threads executing concurrently. A thread may be reused to execute another task after its current task is finished.
+newCachedThreadPool(): ExecutorService
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available.
Figure 32.8 The Executors class provides static methods for creating Executor objects. Listing 32.3 shows how to rewrite Listing 32.1 using a thread pool.
Listing 32.3 ExecutorDemo.java 1 2 3
import java.util.concurrent.*; public class ExecutorDemo {
M32_LIAN0182_11_SE_C32.indd 11
5/22/17 12:34 PM
32-12 Chapter 32 Multithreading and Parallel Programming 4 5 6 7 8 9 10 11 12 13 14 15 16
create executor
submit task
shut down executor
public static void main(String[] args) { // Create a fixed thread pool with maximum three threads ExecutorService executor = Executors.newFixedThreadPool(3); // Submit runnable tasks to the executor executor.execute(new PrintChar('a', 100)); executor.execute(new PrintChar('b', 100)); executor.execute(new PrintNum(100)); // Shut down the executor executor.shutdown(); } }
Line 6 creates a thread pool executor with a total of three threads maximum. Classes PrintChar and PrintNum are defined in Listing 32.1. Line 9 creates a task, new PrintChar('a', 100), and adds it to the pool. Similarly, another two runnable tasks are created and added to the same pool in lines 10 and 11. The executor creates three threads to execute three tasks concurrently. Suppose you replace line 6 with ExecutorService executor = Executors.newFixedThreadPool(1);
What will happen? The three runnable tasks will be executed sequentially because there is only one thread in the pool. Suppose you replace line 6 with ExecutorService executor = Executors.newCachedThreadPool();
What will happen? New threads will be created for each waiting task, so all the tasks will be executed concurrently. The shutdown() method in line 14 tells the executor to shut down. No new tasks can be accepted, but any existing tasks will continue to finish.
Tip If you need to create a thread for just one task, use the Thread class. If you need to create threads for multiple tasks, it is better to use a thread pool. Check Point
2.6.1 What are the benefits of using a thread pool? 3 32.6.2 How do you create a thread pool with three fixed threads? How do you submit a task to a thread pool? How do you know that all the tasks are finished?
32.7 Thread Synchronization Key Point
M32_LIAN0182_11_SE_C32.indd 12
Thread synchronization is to coordinate the execution of the dependent threads. A shared resource may become corrupted if it is accessed simultaneously by multiple threads. The following example demonstrates the problem. Suppose that you create and launch 100 threads, each of which adds a penny to an account. Define a class named Account to model the account, a class named AddAPennyTask to add a penny to the account, and a main class that creates and launches threads. The relationships of these classes are shown in Figure 32.9. The program is given in Listing 32.4.
5/22/17 12:34 PM
32.7 Thread Synchronization 32-13 «interface» java.lang.Runnable
AddAPennyTask
100
1
+run(): void
AccountWithoutSync
1
1
Account
-account: Account
-balance: int
+main(args: String[]): void
+getBalance(): int +deposit(amount: int): void
Figure 32.9 AccountWithoutSync contains an instance of Account and 100 threads of AddAPennyTask.
Listing 32.4 AccountWithoutSync.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
import java.util.concurrent.*; public class AccountWithoutSync { private static Account account = new Account(); public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); // Create and launch 100 threads for (int i = 0; i < 100; i++) { executor.execute(new AddAPennyTask()); }
create executor
submit task
executor.shutdown();
shut down executor
// Wait until all tasks are finished while (!executor.isTerminated()) { }
wait for all tasks to terminate
System.out.println("What is balance? " + account.getBalance()); } // A thread for adding a penny to the account private static class AddAPennyTask implements Runnable { public void run() { account.deposit(1); } } // An inner class for account private static class Account { private int balance = 0; public int getBalance() { return balance; } public void deposit(int amount) { int newBalance = balance + amount; // This delay is deliberately added to magnify the
M32_LIAN0182_11_SE_C32.indd 13
5/22/17 12:34 PM
32-14 Chapter 32 Multithreading and Parallel Programming 42 43 44 45 46 47 48 49 50 51 52
// data-corruption problem and make it easy to see. try { Thread.sleep(5); } catch (InterruptedException ex) { } balance = newBalance; } } }
The classes AddAPennyTask and Account in lines 24–51 are inner classes. Line 4 creates an Account with initial balance 0. Line 11 creates a task to add a penny to the account and submits the task to the executor. Line 11 is repeated 100 times in lines 10–12. The program repeatedly checks whether all tasks are completed in lines 17 and 18. The account balance is displayed in line 20 after all tasks are completed. The program creates 100 threads executed in a thread pool executor (lines 10–12). The isTerminated() method (line 17) is used to test whether all the threads in the pool are terminated. The balance of the account is initially 0 (line 32). When all the threads are finished, the balance should be 100 but the output is unpredictable. As can be seen in Figure 32.10, the answers are wrong in the sample run. This demonstrates the data-corruption problem that occurs when all the threads have access to the same data source simultaneously.
Figure 32.10 The AccountWithoutSync program causes data inconsistency. Lines 39–49 could be replaced by one statement: balance = balance + amount;
It is highly unlikely, although plausible, that the problem can be replicated using this s ingle statement. The statements in lines 39–49 are deliberately designed to magnify the data- corruption problem and make it easy to see. If you run the program several times but still do not see the problem, increase the sleep time in line 44. This will increase the chances for showing the problem of data inconsistency. What, then, caused the error in this program? A possible scenario is shown in Figure 32.11.
Step
Balance
Task 1
1 2 3 4
0 0 1 1
newBalance = balance + 1;
Task 2
newBalance = balance + 1; balance = newBalance; balance = newBalance;
Figure 32.11 Task 1 and Task 2 both add 1 to the same balance.
M32_LIAN0182_11_SE_C32.indd 14
5/22/17 12:34 PM
32.7 Thread Synchronization 32-15 In Step 1, Task 1 gets the balance from the account. In Step 2, Task 2 gets the same balance from the account. In Step 3, Task 1 writes a new balance to the account. In Step 4, Task 2 writes a new balance to the account. The effect of this scenario is that Task 1 does nothing because in Step 4, Task 2 overrides Task 1’s result. Obviously, the problem is that Task 1 and Task 2 are accessing a common resource in a way that causes a conflict. This is a common problem, known as a race condition, in multithreaded programs. A class is said to be thread-safe if an object of the class does not cause a race condition in the presence of multiple threads. As demonstrated in the preceding example, the Account class is not thread-safe.
race condition thread-safe
32.7.1 The synchronized Keyword To avoid race conditions, it is necessary to prevent more than one thread from simultaneously entering a certain part of the program, known as the critical region. The critical region in Listing 32.4 is the entire deposit method. You can use the keyword synchronized to synchronize the method so that only one thread can access the method at a time. There are several ways to correct the problem in Listing 32.4. One approach is to make Account thread-safe by adding the keyword synchronized in the deposit method in line 38, as follows:
critical region
public synchronized void deposit(double amount)
A synchronized method acquires a lock before it executes. A lock is a mechanism for exclusive use of a resource. In the case of an instance method, the lock is on the object for which the method was invoked. In the case of a static method, the lock is on the class. If one thread invokes a synchronized instance method (respectively, static method) on an object, the lock of that object (respectively, class) is acquired first, then the method is executed, and finally the lock is released. Another thread invoking the same method of that object (respectively, class) is blocked until the lock is released. With the deposit method synchronized, the preceding scenario cannot happen. If Task 1 enters the method, Task 2 is blocked until Task 1 finishes the method, as shown in Figure 32.12. Task 1
Task 2
Acquire a lock on the object account
Execute the deposit method Wait to acquire the lock Release the lock Acquire a lock on the object account
Execute the deposit method
Release the lock
Figure 32.12 Task 1 and Task 2 are synchronized.
32.7.2 Synchronizing Statements Invoking a synchronized instance method of an object acquires a lock on the object, and invoking a synchronized static method of a class acquires a lock on the class. A synchronized statement can be used to acquire a lock on any object, not just this object, when executing a block
M32_LIAN0182_11_SE_C32.indd 15
5/22/17 12:34 PM
32-16 Chapter 32 Multithreading and Parallel Programming of the code in a method. This block is referred to as a synchronized block. The general form of a synchronized statement is as follows:
synchronized block
synchronized (expr) { statements; }
The expression expr must evaluate to an object reference. If the object is already locked by another thread, the thread is blocked until the lock is released. When a lock is obtained on the object, the statements in the synchronized block are executed and then the lock is released. Synchronized statements enable you to synchronize part of the code in a method instead of the entire method. This increases concurrency. You can make Listing 32.4 thread-safe by placing the statement in line 26 inside a synchronized block: synchronized (account) { account.deposit(1); }
Note Any synchronized instance method can be converted into a synchronized statement. For example, the following synchronized instance method in (a) is equivalent to (b): public synchronized void xMethod() { // method body }
public void xMethod() { synchronized (this) { // method body } }
(a)
Check Point
(b)
32.7.1 Give some examples of possible resource corruption when running multiple 32.7.2
threads. How do you synchronize conflicting threads? Suppose you place the statement in line 26 of Listing 32.4 inside a synchronized block to avoid race conditions, as follows: synchronized (this) { account.deposit(1); }
Will it work?
32.8 Synchronization Using Locks Key Point
Locks and conditions can be explicitly used to synchronize threads. Recall that in Listing 32.4, 100 tasks deposit a penny to the same account concurrently, which causes conflicts. To avoid it, you use the synchronized keyword in the deposit method, as follows: public synchronized void deposit(double amount)
lock
M32_LIAN0182_11_SE_C32.indd 16
A synchronized instance method implicitly acquires a lock on the instance before it executes the method. Java enables you to acquire locks explicitly, which give you more control for coordinating threads. A lock is an instance of the Lock interface, which defines the methods for acquiring and releasing locks, as shown in Figure 32.13. A lock may also use the newCondition() method to create any number of Condition objects, which can be used for thread communications.
5/22/17 12:34 PM
32.8 Synchronization Using Locks 32-17 «interface» java.util.concurrent.locks.Lock +lock(): void +unlock(): void +newCondition(): Condition
Acquires the lock. Releases the lock. Returns a new Condition instance that is bound to this Lock instance.
java.util.concurrent.locks.ReentrantLock +ReentrantLock() +ReentrantLock(fair: boolean)
Same as ReentrantLock(false). Creates a lock with the given fairness policy. When the fairness is true, the longest-waiting thread will get the lock. Otherwise, there is no particular access order.
Figure 32.13 The ReentrantLock class implements the Lock interface to represent a lock. ReentrantLock is a concrete implementation of Lock for creating mutually exclusive locks. You can create a lock with the specified fairness policy. True fairness policies guarantee that the longest waiting thread will obtain the lock first. False fairness policies grant a lock to a waiting thread arbitrarily. Programs using fair locks accessed by many threads may have poorer overall performance than those using the default setting, but they have smaller variances in times to obtain locks and prevent starvation. Listing 32.5 revises the program in Listing 32.7 to synchronize the account modification using explicit locks.
fairness policy
Listing 32.5 AccountWithSyncUsingLock.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
import java.util.concurrent.*; import java.util.concurrent.locks.*;
package for locks
public class AccountWithSyncUsingLock { private static Account account = new Account(); public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); // Create and launch 100 threads for (int i = 0; i < 100; i++) { executor.execute(new AddAPennyTask()); } executor.shutdown(); // Wait until all tasks are finished while (!executor.isTerminated()) { } System.out.println("What is balance? " + account.getBalance()); } // A thread for adding a penny to the account public static class AddAPennyTask implements Runnable { public void run() { account.deposit(1); } }
M32_LIAN0182_11_SE_C32.indd 17
5/22/17 12:34 PM
32-18 Chapter 32 Multithreading and Parallel Programming 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
create a lock
acquire the lock
release the lock
// An inner class for Account public static class Account { private static Lock lock = new ReentrantLock(); // Create a lock private int balance = 0; public int getBalance() { return balance; } public void deposit(int amount) { lock.lock(); // Acquire the lock try { int newBalance = balance + amount; // This delay is deliberately added to magnify the // data-corruption problem and make it easy to see. Thread.sleep(5); balance = newBalance; } catch (InterruptedException ex) { } finally { lock.unlock(); // Release the lock } } } }
Line 33 creates a lock, line 41 acquires the lock, and line 55 releases the lock.
Tip It is a good practice to always immediately follow a call to lock() with a try-catch block and release the lock in the finally clause, as shown in lines 41–56, to ensure that the lock is always released.
Listing 32.5 can be implemented using a synchronize method for deposit rather than using a lock. In general, using synchronized methods or statements is simpler than using explicit locks for mutual exclusion. However, using explicit locks is more intuitive and flexible to synchronize threads with conditions, as you will see in the next section. Check Point
32.8.1 How do you create a lock object? How do you acquire a lock and release a lock?
32.9 Cooperation among Threads Key Point
condition
M32_LIAN0182_11_SE_C32.indd 18
Conditions on locks can be used to coordinate thread interactions. Thread synchronization suffices to avoid race conditions by ensuring the mutual exclusion of multiple threads in the critical region, but sometimes you also need a way for threads to cooperate. Conditions can be used to facilitate communications among threads. A thread can specify what to do under a certain condition. Conditions are objects created by invoking the newCondition() method on a Lock object. Once a condition is created, you can use its await(), signal(), and signalAll() methods for thread communications, as shown in Figure 32.14. The await() method causes the current thread to wait until the condition is signaled. The signal() method wakes up one waiting thread, and the signalAll() method wakes all waiting threads.
5/22/17 12:34 PM
32.9 Cooperation among Threads 32-19 «interface» java.util.concurrent.Condition +await(): void +signal(): void +signalAll(): Condition
Causes the current thread to wait until the condition is signaled. Wakes up one waiting thread. Wakes up all waiting threads.
Figure 32.14 The Condition interface defines the methods for performing synchronization. Let us use an example to demonstrate thread communications. Suppose you create and launch two tasks: one that deposits into an account, and one that withdraws from the same account. The withdraw task has to wait if the amount to be withdrawn is more than the current balance. Whenever new funds are deposited into the account, the deposit task notifies the withdraw thread to resume. If the amount is still not enough for a withdrawal, the withdraw thread has to continue to wait for a new deposit. To synchronize the operations, use a lock with a condition: newDeposit (i.e., new deposit added to the account). If the balance is less than the amount to be withdrawn, the withdraw task will wait for the newDeposit condition. When the deposit task adds money to the account, the task signals the waiting withdraw task to try again. The interaction between the two tasks is shown in Figure 32.15. Withdraw Task
Deposit Task
lock.lock();
lock.lock();
while (balance < withdrawAmount) newDeposit.await();
balance += depositAmount
balance – = withdrawAmount lock.unlock();
thread cooperation example
newDeposit.signalAll(); lock.unlock();
Figure 32.15 The condition newDeposit is used for communications between the two threads. You create a condition from a Lock object. To use a condition, you have to first obtain a lock. The await() method causes the thread to wait and automatically releases the lock on the condition. Once the condition is right, the thread reacquires the lock and continues executing. Assume the initial balance is 0 and the amount to deposit and withdraw are r andomly generated. Listing 32.6 gives the program. A sample run of the program is shown in Figure 32.16.
Figure 32.16 The withdraw task waits if there are not sufficient funds to withdraw.
M32_LIAN0182_11_SE_C32.indd 19
5/22/17 12:34 PM
32-20 Chapter 32 Multithreading and Parallel Programming
Listing 32.6 ThreadCooperation.java
create two threads
create a lock create a condition
acquire the lock
M32_LIAN0182_11_SE_C32.indd 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
import java.util.concurrent.*; import java.util.concurrent.locks.*; public class ThreadCooperation { private static Account account = new Account(); public static void main(String[] args) { // Create a thread pool with two threads ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new DepositTask()); executor.execute(new WithdrawTask()); executor.shutdown(); System.out.println("Thread 1\t\tThread 2\t\tBalance"); } public static class DepositTask implements Runnable { @Override // Keep adding an amount to the account public void run() { try { / / Purposely delay it to let the withdraw method proceed while (true) { account.deposit((int)(Math.random() * 10) + 1); Thread.sleep(1000); } } catch (InterruptedException ex) { ex.printStackTrace(); } } } public static class WithdrawTask implements Runnable { @Override // Keep subtracting an amount from the account public void run() { while (true) { account.withdraw((int)(Math.random() * 10) + 1); } } } // An inner class for account private static class Account { // Create a new lock private static Lock lock = new ReentrantLock(); // Create a condition private static Condition newDeposit = lock.newCondition(); private int balance = 0; public int getBalance() { return balance; } public void withdraw(int amount) { lock.lock(); // Acquire the lock try { while (balance < amount) {
5/22/17 12:34 PM
32.9 Cooperation among Threads 32-21 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
System.out.println("\t\t\tWait for a deposit"); newDeposit.await();
wait on the condition
} balance -= amount; System.out.println("\t\t\tWithdraw " + amount + "\t\t" + getBalance()); } catch (InterruptedException ex) { ex.printStackTrace(); } finally { lock.unlock(); // Release the lock }
release the lock
} public void deposit(int amount) { lock.lock(); // Acquire the lock try { balance += amount; System.out.println("Deposit " + amount + "\t\t\t\t\t" + getBalance()); // Signal thread waiting on the condition newDeposit.signalAll(); } finally { lock.unlock(); // Release the lock }
acquire the lock
signal threads
release the lock
} } }
The example creates a new inner class named Account to model the account with two methods, deposit(int) and withdraw(int), a class named DepositTask to add an amount to the balance, a class named WithdrawTask to withdraw an amount from the balance, and a main class that creates and launches two threads. The program creates and submits the deposit task (line 10) and the withdraw task (line 11). The deposit task is purposely put to sleep (line 23) to let the withdraw task run. When there are not enough funds to withdraw, the withdraw task waits (line 59) for notification of the balance change from the deposit task (line 83). A lock is created in line 44. A condition named newDeposit on the lock is created in line 47. A condition is bound to a lock. Before waiting or signaling the condition, a thread must first acquire the lock for the condition. The withdraw task acquires the lock in line 56, waits for the newDeposit condition (line 60) when there is not a sufficient amount to withdraw, and releases the lock in line 71. The deposit task acquires the lock in line 76 and signals all waiting threads (line 83) for the newDeposit condition after a new deposit is made. What will happen if you replace the while loop in lines 58–61 with the following if statement? if (balance < amount) { System.out.println("\t\t\tWait for a deposit"); newDeposit.await(); }
The deposit task will notify the withdraw task whenever the balance changes. (balance < amount) may still be true when the withdraw task is awakened. Using the if statement would
M32_LIAN0182_11_SE_C32.indd 21
5/22/17 12:34 PM
32-22 Chapter 32 Multithreading and Parallel Programming lead to incorrect withdraw. Using the loop statement, the withdraw task will have a chance to recheck the condition.
Caution Once a thread invokes await() on a condition, the thread waits for a signal to resume. If you forget to call signal() or signalAll() on the condition, the thread will wait forever.
ever-waiting threads
Caution A condition is created from a Lock object. To invoke its method (e.g., await(), signal(), and signalAll()), you must first own the lock. If you invoke these methods without acquiring the lock, an IllegalMonitorStateException will be thrown.
IllegalMonitorState Exception
Java’s built-in monitor monitor
Locks and conditions were introduced in Java 5. Prior to Java 5, thread communications were programmed using the object’s built-in monitors. Locks and conditions are more powerful and flexible than the built-in monitor, so will not need to use monitors. However, if you are working with legacy Java code, you may encounter Java’s built-in monitor. A monitor is an object with mutual exclusion and synchronization capabilities. Only one thread can execute a method at a time in the monitor. A thread enters the monitor by acquiring a lock on it and exits by releasing the lock. Any object can be a monitor. An object becomes a monitor once a thread locks it. Locking is implemented using the synchronized keyword on a method or a block. A thread must acquire a lock before executing a synchronized method or block. A thread can wait in a monitor if the condition is not right for it to continue executing in the monitor. You can invoke the wait() method on the monitor object to release the lock so some other thread can get in the monitor and perhaps change the monitor’s state. When the condition is right, the other thread can invoke the notify() or notifyAll() method to signal one or all waiting threads to regain the lock and resume execution. The template for invoking these methods is shown in Figure 32.17.
Task 1 synchronized (anObject) { try { // Wait for the condition to become true while (!condition) resume anObject.wait();
}
Task 2 synchronized (anObject) { // When condition becomes true anObject.notify(); or anObject.notifyAll(); ... }
// Do something when condition is true } catch (InterruptedException ex) { ex.printStackTrace(); }
Figure 32.17 The wait(), notify(), and notifyAll() methods coordinate thread communication. The wait(), notify(), and notifyAll() methods must be called in a synchronized method or a synchronized block on the receiving object of these methods. Otherwise, an IllegalMonitorStateException will occur. When wait() is invoked, it pauses the thread and simultaneously releases the lock on the object. When the thread is restarted after being notified, the lock is automatically reacquired. The wait(), notify(), and notifyAll() methods on an object are analogous to the await(), signal(), and signalAll() methods on a condition.
M32_LIAN0182_11_SE_C32.indd 22
5/22/17 12:34 PM
32.10 Case Study: Producer/Consumer 32-23 32.9.1 How do you create a condition on a lock? What are the await(), signal(), and signalAll() methods for?
Check Point
32.9.2 What would happen if the while loop in line 58 of Listing 32.6 was changed to an if statement?
while (balance < amount)
Replaced by
if (balance < amount)
32.9.3 Why does the following class have a syntax error? public class Test implements Runnable { public static void main(String[] args) { new Test(); } public Test() throws InterruptedException { Thread thread = new Thread(this); thread.sleep(1000); } public synchronized void run() { } }
2.9.4 What is a possible cause for IllegalMonitorStateException? 3 32.9.5 Can wait(), notify(), and notifyAll() be invoked from any object? What is 32.9.6
the purpose of these methods? What is wrong in the following code?
synchronized (object1) { try { while (!condition) object2.wait(); } catch (InterruptedException ex) { } }
32.10 Case Study: Producer/Consumer This section gives the classic Consumer/Producer example for demonstrating thread coordination.
Key Point
Suppose that you use a buffer to store integers and that the buffer size is limited. The buffer provides the method write(int) to add an int value to the buffer and the method read() to read and delete an int value from the buffer. To synchronize the operations, use a lock with two conditions: notEmpty (i.e., the buffer is not empty) and notFull (i.e., the buffer is not full). When a task adds an int to the buffer, if the buffer is full, the task will wait for the notFull condition. When a task reads an int from the buffer, if the buffer is empty, the task will wait for the notEmpty condition. The interaction between the two tasks is shown in Figure 32.18. Listing 32.7 presents the complete program. The program contains the Buffer class (lines 50–101) and two tasks for repeatedly adding and consuming numbers to and from the buffer (lines 16–47). The write(int) method (lines 62–79) adds an integer to the buffer. The read() method (lines 81–100) deletes and returns an integer from the buffer.
M32_LIAN0182_11_SE_C32.indd 23
5/22/17 12:34 PM
32-24 Chapter 32 Multithreading and Parallel Programming Task for adding an int
while (count == CAPACITY) notFull.await();
Task for deleting an int
while (count == 0) notEmpty.await();
Add an int to the buffer
Delete an int from the buffer
notEmpty.signal();
notFull.signal();
Figure 32.18 The conditions notFull and notEmpty are used to coordinate task interactions.
The buffer is actually a first-in, first-out queue (lines 52 and 53). The conditions notEmpty and notFull on the lock are created in lines 59 and 60. The conditions are bound to a lock. A lock must be acquired before a condition can be applied. If you use the wait() and notify() methods to rewrite this example, you have to designate two objects as monitors.
Listing 32.7 ConsumerProducer.java
create a buffer
create two threads
producer task
consumer task
M32_LIAN0182_11_SE_C32.indd 24
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
import java.util.concurrent.*; import java.util.concurrent.locks.*; public class ConsumerProducer { private static Buffer buffer = new Buffer(); public static void main(String[] args) { // Create a thread pool with two threads ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new ProducerTask()); executor.execute(new ConsumerTask()); executor.shutdown(); } // A task for adding an int to the buffer private static class ProducerTask implements Runnable { public void run() { try { int i = 1; while (true) { System.out.println("Producer writes " + i); buffer.write(i++); // Add a value to the buffer // Put the thread into sleep Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException ex) { ex.printStackTrace(); } } } // A task for reading and deleting an int from the buffer private static class ConsumerTask implements Runnable { public void run() {
5/22/17 12:34 PM
32.10 Case Study: Producer/Consumer 32-25 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
try { while (true) { System.out.println("\t\t\tConsumer reads " + buffer.read()); // Put the thread into sleep Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException ex) { ex.printStackTrace(); } } } // An inner class for buffer private static class Buffer { private static final int CAPACITY = 1; // buffer size private java.util.LinkedList queue = new java.util.LinkedList(); // Create a new lock private static Lock lock = new ReentrantLock();
create a lock
// Create two conditions private static Condition notEmpty = lock.newCondition(); private static Condition notFull = lock.newCondition();
create a condition create a condition
public void write(int value) { lock.lock(); // Acquire the lock try { while (queue.size() == CAPACITY) { System.out.println("Wait for notFull condition"); notFull.await(); } queue.offer(value); notEmpty.signal(); // Signal notEmpty condition } catch (InterruptedException ex) { ex.printStackTrace(); } finally { lock.unlock(); // Release the lock }
acquire the lock
wait for notFull
signal notEmpty
release the lock
} public int read() { int value = 0; lock.lock(); // Acquire the lock try { while (queue.isEmpty()) { System.out.println("\t\t\tWait for notEmpty condition"); notEmpty.await(); } value = queue.remove(); notFull.signal(); // Signal notFull condition
acquire the lock
wait for notEmpty
signal notFull
} catch (InterruptedException ex) { ex.printStackTrace(); }
M32_LIAN0182_11_SE_C32.indd 25
5/22/17 12:34 PM
32-26 Chapter 32 Multithreading and Parallel Programming 96 97 98 99 100 101 102
release the lock
finally { lock.unlock(); // Release the lock return value; } } } }
A sample run of the program is shown in Figure 32.19.
Figure 32.19 Locks and conditions are used for communications between the Producer and Consumer threads. Check Point
2.10.1 Can the read and write methods in the Buffer class be executed concurrently? 3 32.10.2 When invoking the read method, what happens if the queue is empty? 32.10.3 When invoking the write method, what happens if the queue is full?
32.11 Blocking Queues Key Point blocking queue
Java Collections Framework provides ArrayBlockingQueue, LinkedBlockingQueue, and PriorityBlockingQueue for supporting blocking queues. Queues and priority queues were introduced in Section 20.9. A blocking queue causes a thread to block when you try to add an element to a full queue or to remove an element from an empty queue. The BlockingQueue interface extends java.util.Queue and provides the synchronized put and take methods for adding an element to the tail of the queue and for removing an element from the head of the queue, as shown in Figure 32.20. «interface» java.util.Collection
«interface» java.util.Queue
«interface» java.util.concurrent.BlockingQueue +put(element: E): void
Inserts an element to the tail of the queue. Waits if the queue is full.
+take(): E
Retrieves and removes the head of this queue. Waits if the queue is empty.
Figure 32.20 BlockingQueue is a subinterface of Queue.
M32_LIAN0182_11_SE_C32.indd 26
5/22/17 12:34 PM
32.11 Blocking Queues 32-27 Three concrete blocking queues—ArrayBlockingQueue, LinkedBlockingQueue, and PriorityBlockingQueue—are provided in Java, as shown in Figure 32.21. All are in the java.util.concurrent package. ArrayBlockingQueue implements a blocking queue using an array. You have to specify a capacity or an optional fairness to construct an ArrayBlockingQueue. LinkedBlockingQueue implements a blocking queue using a linked list. You can create an unbounded or bounded LinkedBlockingQueue. PriorityBlockingQueue is a priority queue. You can create an unbounded or bounded priority queue.
«interface» java.util.concurrent.BlockingQueue
ArrayBlockingQueue
LinkedBlockingQueue
PriorityBlockingQueue
+ArrayBlockingQueue(capacity: int)
+LinkedBlockingQueue()
+PriorityBlockingQueue()
+ArrayBlockingQueue(capacity: int, fair: boolean)
+LinkedBlockingQueue(capacity: int)
+PriorityBlockingQueue(capacity: int)
Figure 32.21 ArrayBlockingQueue, LinkedBlockingQueue, and PriorityBlockingQueue are concrete blocking queues.
Note The put method will never block an unbounded LinkedBlockingQueue or PriorityBlockingQueue.
unbounded queue
Listing 32.8 gives an example of using an ArrayBlockingQueue to simplify the Consumer/Producer example in Listing 32.10. Line 5 creates an ArrayBlockingQueue to store integers. The Producer thread puts an integer into the queue (line 22) and the Consumer thread takes an integer from the queue (line 38).
Listing 32.8 ConsumerProducerUsingBlockingQueue.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
import java.util.concurrent.*; public class ConsumerProducerUsingBlockingQueue { private static ArrayBlockingQueue buffer = new ArrayBlockingQueue(2); public static void main(String[] args) { // Create a thread pool with two threads ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new ProducerTask()); executor.execute(new ConsumerTask()); executor.shutdown(); } // A task for adding an int to the buffer private static class ProducerTask implements Runnable { public void run() { try { int i = 1; while (true) { System.out.println("Producer writes " + i); buffer.put(i++); // Add any value to the buffer, say, 1 // Put the thread into sleep
M32_LIAN0182_11_SE_C32.indd 27
create a buffer
create two threads
producer task
put
5/22/17 12:34 PM
32-28 Chapter 32 Multithreading and Parallel Programming 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
Consumer task
take
Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException ex) { ex.printStackTrace(); } } } // A task for reading and deleting an int from the buffer private static class ConsumerTask implements Runnable { public void run() { try { while (true) { System.out.println("\t\t\tConsumer reads " + buffer.take()); // Put the thread into sleep Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException ex) { ex.printStackTrace(); } } } }
In Listing 32.7, you used locks and conditions to synchronize the Producer and Consumer threads. This program does not use locks and conditions because synchronization is already implemented in ArrayBlockingQueue. Check Point
2.11.1 What is a blocking queue? What blocking queues are supported in Java? 3 32.11.2 What method do you use to add an element to an ArrayBlockingQueue? What happens if the queue is full?
32.11.3 What method do you use to retrieve an element from an ArrayBlockingQueue? What happens if the queue is empty?
32.12 Semaphores semaphore
Key Point
Semaphores can be used to restrict the number of threads that access a shared resource. In computer science, a semaphore is an object that controls the access to a common resource. Before accessing the resource, a thread must acquire a permit from the semaphore. After finishing with the resource, the thread must return the permit back to the semaphore, as shown in Figure 32.22. A thread accessing a shared resource.
Acquire a permit from a semaphore. Wait if the permit is not available.
semaphore.acquire();
Access the resource
Release the permit to the semaphore.
semaphore.release();
Figure 32.22 A limited number of threads can access a shared resource controlled by a semaphore.
M32_LIAN0182_11_SE_C32.indd 28
5/22/17 12:34 PM
32.12 Semaphores 32-29 To create a semaphore, you have to specify the number of permits with an optional fairness policy, as shown in Figure 32.23. A task acquires a permit by invoking the semaphore’s acquire() method and releases the permit by invoking the semaphore’s release() method. Once a permit is acquired, the total number of available permits in a semaphore is reduced by 1. Once a permit is released, the total number of available permits in a semaphore is increased by 1. java.util.concurrent.Semaphore +Semaphore(numberOfPermits: int)
Creates a semaphore with the specified number of permits. The fairness policy is false.
+Semaphore(numberOfPermits: int, fair: boolean)
Creates a semaphore with the specified number of permits and the fairness policy.
+acquire(): void
Acquires a permit from this semaphore. If no permit is available, the thread is blocked until one is available.
+release(): void
Releases a permit back to the semaphore.
Figure 32.23 The Semaphore class contains the methods for accessing a semaphore. A semaphore with just one permit can be used to simulate a mutually exclusive lock. isting 32.9 revises the Account inner class in Listing 32.9 using a semaphore to ensure that L only one thread at a time can access the deposit method.
Listing 32.9 New Account Inner Class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
// An inner class for Account private static class Account { // Create a semaphore private static Semaphore semaphore = new Semaphore(1); private int balance = 0;
create a semaphore
public int getBalance() { return balance; } public void deposit(int amount) { try { semaphore.acquire(); // Acquire a permit int newBalance = balance + amount;
acquire a permit
// This delay is deliberately added to magnify the // data-corruption problem and make it easy to see Thread.sleep(5); balance = newBalance; } catch (InterruptedException ex) { } finally { semaphore.release(); // Release a permit }
release a permit
} }
A semaphore with one permit is created in line 4. A thread first acquires a permit when executing the deposit method in line 13. After the balance is updated, the thread releases the permit in line 25. It is a good practice to always place the release() method in the finally clause to ensure that the permit is finally released even in the case of exceptions.
M32_LIAN0182_11_SE_C32.indd 29
5/22/17 12:34 PM
32-30 Chapter 32 Multithreading and Parallel Programming Check Point
2.12.1 What are the similarities and differences between a lock and a semaphore? 3 32.12.2 How do you create a semaphore that allows three concurrent threads? How do you acquire a semaphore? How do you release a semaphore?
32.13 Avoiding Deadlocks Key Point deadlock
Deadlocks can be avoided by using a proper resource ordering. Sometimes two or more threads need to acquire the locks on several shared objects. This could cause a deadlock, in which each thread has the lock on one of the objects and is waiting for the lock on the other object. Consider the scenario with two threads and two objects, as shown in Figure 32.24. Thread 1 has acquired a lock on object1, and Thread 2 has acquired a lock on object2. Now Thread 1 is waiting for the lock on object2, and Thread 2 for the lock on object1. Each thread waits for the other to release the lock it needs and until that happens, neither can continue to run.
Step 1 2 3 4 5 6
Thread 2
Thread 1 synchronized (object1) {
synchronized (object2) { // do something here // do something here synchronized (object2) { }
synchronized (object1) { // do something here }
// do something here
} Wait for Thread 2 to release the lock on object2
} Wait for Thread 1 to release the lock on object1
Figure 32.24 Thread 1 and Thread 2 are deadlocked.
Deadlock is easily avoided by using a simple technique known as resource ordering. With this technique, you assign an order to all the objects whose locks must be acquired and ensure that each thread acquires the locks in that order. For example in Figure 32.24, suppose the objects are ordered as object1 and object2. Using the resource-ordering technique, Thread 2 must acquire a lock on object1 first, then on object2. Once Thread 1 acquires a lock on object1, Thread 2 has to wait for a lock on object1. Thus, Thread 1 will be able to acquire a lock on object2 and no deadlock will occur.
resource ordering
Check Point
32.13.1 What is a deadlock? How can you avoid deadlock?
32.14 Thread States Key Point
M32_LIAN0182_11_SE_C32.indd 30
A thread state indicates the status of thread. Tasks are executed in threads. Threads can be in one of the five states: New, Ready, Running, Blocked, or Finished (see Figure 32.25). When a thread is newly created, it enters the New state. After a thread is started by calling its start() method, it enters the Ready state. A ready thread is runnable but may not be running yet. The operating system has to allocate CPU time to it. When a ready thread begins executing, it enters the Running state. A running thread can enter the Ready state if its given CPU time expires or its yield() method is called.
5/22/17 12:34 PM
32.15 Synchronized Collections 32-31 yield(), or time out Thread created
start() New
Running run() completed
run()
Ready
Finished join() sleep()
wait()
Target finished Wait for target to finish
Wait for time out
Wait to be notified
Time out
Signaled
Blocked
Figure 32.25 A thread can be in one of the five states: New, Ready, Running, Blocked, or Finished. A thread can enter the Blocked state (i.e., become inactive) for several reasons. It may have invoked the join(), sleep(), or wait() method. It may be waiting for an I/O operation to finish. A blocked thread may be reactivated when the action inactivating it is reversed. For example, if a thread has been put to sleep and the sleep time has expired, the thread is reactivated and enters the Ready state. Finally, a thread is Finished if it completes the execution of its run() method. The isAlive() method is used to find out the state of a thread. It returns true if a thread is in the Ready, Blocked, or Running state; it returns false if a thread is new and has not started or if it is finished. The interrupt() method interrupts a thread in the following way: If a thread is currently in the Ready or Running state, its interrupted flag is set; if a thread is currently blocked, it is awakened and enters the Ready state, and a java.lang.InterruptedException is thrown.
32.14.1 What is a thread state? Describe the states for a thread.
Check Point
32.15 Synchronized Collections Java Collections Framework provides synchronized collections for lists, sets, and maps. The classes in the Java Collections Framework are not thread-safe; that is, their contents may become corrupted if they are accessed and updated concurrently by multiple threads. You can protect the data in a collection by locking the collection or by using synchronized collections. The Collections class provides six static methods for wrapping a collection into a synchronized version, as shown in Figure 32.26. The collections created using these methods are called synchronization wrappers.
Key Point
synchronized collection
synchronization wrapper
java.util.Collections +synchronizedCollection(c: Collection): Collection
Returns a synchronized collection.
+synchronizedList(list: List): List
Returns a synchronized list from the specified list.
+synchronizedMap(m: Map): Map
Returns a synchronized map from the specified map.
+synchronizedSet(s: Set): Set
Returns a synchronized set from the specified set.
+synchronizedSortedMap(s: SortedMap): SortedMap
Returns a synchronized sorted map from the specified sorted map. Returns a synchronized sorted set.
+synchronizedSortedSet(s: SortedSet): SortedSet
Figure 32.26 You can obtain synchronized collections using the methods in the Collections class.
M32_LIAN0182_11_SE_C32.indd 31
5/22/17 12:34 PM
32-32 Chapter 32 Multithreading and Parallel Programming Invoking synchronizedCollection(Collection c) returns a new C ollection object, in which all the methods that access and update the original collection c are synchronized. These methods are implemented using the synchronized keyword. For example, the add method is implemented like this: public boolean add(E o) { synchronized (this) { return c.add(o); } }
Synchronized collections can be safely accessed and modified by multiple threads concurrently.
Note The methods in java.util.Vector, java.util.Stack, and java.util. Hashtable are already synchronized. These are old classes introduced in JDK 1.0. Starting with JDK 1.5, you should use java.util.ArrayList to replace Vector, java.util.LinkedList to replace Stack , and java.util.Map to replace Hashtable. If synchronization is needed, use a synchronization wrapper.
The synchronization wrapper classes are thread-safe, but the iterator is fail-fast. This means that if you are using an iterator to traverse a collection while the underlying collection is being modified by another thread, then the iterator will immediately fail by throwing java.util. ConcurrentModificationException, which is a subclass of RuntimeException. To avoid this error, you need to create a synchronized collection object and acquire a lock on the object when traversing it. For example, to traverse a set, you have to write the code like this:
fail-fast
Set hashSet = Collections.synchronizedSet(new HashSet()); synchronized (hashSet) { // Must synchronize it Iterator iterator = hashSet.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } }
Failure to do so may result in nondeterministic behavior, such as a Conc urrentM odificationException. Check Point
32.15.1 What is a synchronized collection? Is ArrayList synchronized? How do you make it synchronized?
32.15.2 Explain why an iterator is fail-fast.
32.16 Parallel Programming Key Point
Fork/Join Framework
JDK 7 feature
M32_LIAN0182_11_SE_C32.indd 32
The Fork/Join Framework is used for parallel programming in Java. Section 7.12 introduced the Arrays.sort and Arrays.parallelSort method for sorting an array. The parallelSort method utilizes multiple processors to reduce sort time. Chapter 22 introduced parallel streams for executing stream operations in parallel to speed up processing using multiple processors. The parallel processing are implemented using the Fork/ Join Framework. This section, introduces the new Fork/Join Framework so you can write own code for parallel programming. The Fork/Join Framework is illustrated in Figure 32.27 (the diagram resembles a fork, hence its name). A problem is divided into nonoverlapping subproblems, which can be solved independently in parallel. The solutions to all subproblems are then joined to obtain an overall solution for the problem. This is the parallel implementation of the divide-and-conquer approach. In JDK 7’s Fork/Join Framework, a fork can be viewed as an independent task that runs on a thread.
5/22/17 12:34 PM
32.16 Parallel Programming 32-33 Fork
Subproblem
Join
Subproblem Problem
Solution Subproblem Subproblem
Figure 32.27 The nonoverlapping subproblems are solved in parallel. The framework defines a task using the ForkJoinTask class, as shown in Figure 32.28 and executes a task in an instance of ForkJoinPool, as shown in Figure 32.29.
ForkJoinTask ForkJoinPool
«interface» java.util.concurrent.Future +cancel(interrupt: boolean): boolean +get(): V
Attempts to cancel this task. Waits if needed for the computation to complete and returns the result. Returns true if this task is completed.
+isDone(): boolean
java.util.concurrent.ForkJoinTask +adapt(Runnable task): ForkJoinTask +fork(): ForkJoinTask +join(): V +invoke(): V +invokeAll(tasks ForkJoinTask…): void
Returns a ForkJoinTask from a runnable task. Arranges asynchronous execution of the task. Returns the result of computations when it is done. Performs the task and awaits for its completion, and returns its result. Forks the given tasks and returns when all tasks are completed.
java.util.concurrent.RecursiveAction #compute(): void
Defines how task is performed.
java.util.concurrent.RecursiveTask #compute(): V
Defines how task is performed. Returns the value after the task is completed.
Figure 32.28 The ForkJoinTask class defines a task for asynchronous execution.
«interface» java.util.concurrent.ExecutorService
See Figure 32.8
java.util.concurrent.ForkJoinPool +ForkJoinPool() +ForkJoinPool(parallelism: int) +invoke(ForkJoinTask): T
Creates a ForkJoinPool with all available processors. Creates a ForkJoinPool with the specified number of processors. Performs the task and returns its result upon completion.
Figure 32.29 The ForkJoinPool executes Fork/Join tasks.
M32_LIAN0182_11_SE_C32.indd 33
5/22/17 12:34 PM
32-34 Chapter 32 Multithreading and Parallel Programming
RecursiveAction RecursiveTask
ForkJoinTask is the abstract base class for tasks. A ForkJoinTask is a thread-like entity, but it is much lighter than a normal thread because huge numbers of tasks and subtasks can be executed by a small number of actual threads in a ForkJoinPool. The tasks are primarily coordinated using fork() and join(). Invoking fork() on a task arranges asynchronous execution and invoking join() waits until the task is completed. The invoke() and invokeAll(tasks) methods implicitly invoke fork() to execute the task and join() to wait for the tasks to complete and return the result, if any. Note the static method invokeAll takes a variable number of ForkJoinTask arguments using the ... syntax, which is introduced in Section 7.9. The Fork/Join Framework is designed to parallelize divide-and-conquer solutions, which are naturally recursive. RecursiveAction and RecursiveTask are two subclasses of ForkJoinTask. To define a concrete task class, your class should extend RecursiveAction or RecursiveTask . RecursiveAction is for a task that doesn’t return a value and RecursiveTask is for a task that does return a value. Your task class should override the c ompute() method to specify how a task is performed. We now use a merge sort to demonstrate how to develop parallel programs using the Fork/ Join Framework. The merge sort algorithm (introduced in Section 25.3) divides the array into two halves and applies a merge sort on each half recursively. After the two halves are sorted, the algorithm merges them. Listing 32.10 gives a parallel implementation of the merge sort algorithm and compares its execution time with a sequential sort.
Listing 32.10 ParallelMergeSort.java
invoke parallel sort
invoke sequential sort
create a ForkJoinTask create a ForkJoinPool execute a task
define concrete ForkJoinTask
M32_LIAN0182_11_SE_C32.indd 34
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
import java.util.concurrent.RecursiveAction; import java.util.concurrent.ForkJoinPool; public class ParallelMergeSort { public static void main(String[] args) { final int SIZE = 7000000; int[] list1 = new int[SIZE]; int[] list2 = new int[SIZE]; for (int i = 0; i < list1.length; i++) list1[i] = list2[i] = (int)(Math.random() * 10000000); long startTime = System.currentTimeMillis(); parallelMergeSort(list1); // Invoke parallel merge sort long endTime = System.currentTimeMillis(); System.out.println("\nParallel time with " + Runtime.getRuntime().availableProcessors() + " processors is " + (endTime - startTime) + " milliseconds"); startTime = System.currentTimeMillis(); MergeSort.mergeSort(list2); // MergeSort is in Listing 23.5 endTime = System.currentTimeMillis(); System.out.println("\nSequential time is " + (endTime - startTime) + " milliseconds"); } public static void parallelMergeSort(int[] list) { RecursiveAction mainTask = new SortTask(list); ForkJoinPool pool = new ForkJoinPool(); pool.invoke(mainTask); } private static class SortTask extends RecursiveAction { private final int THRESHOLD = 500;
5/22/17 12:34 PM
32.16 Parallel Programming 32-35 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
private int[] list; SortTask(int[] list) { this.list = list; } @Override protected void compute() { if (list.length < THRESHOLD) java.util.Arrays.sort(list); else { // Obtain the first half int[] firstHalf = new int[list.length / 2]; System.arraycopy(list, 0, firstHalf, 0, list.length / 2);
perform the task sort a small list
split into two parts
// Obtain the second half int secondHalfLength = list.length - list.length / 2; int[] secondHalf = new int[secondHalfLength]; System.arraycopy(list, list.length / 2, secondHalf, 0, secondHalfLength); // Recursively sort the two halves invokeAll(new SortTask(firstHalf), new SortTask(secondHalf)); // Merge firstHalf with secondHalf into list MergeSort.merge(firstHalf, secondHalf, list);
solve each part
merge two parts
} } } }
Parallel time with two processors is 2829 milliseconds Sequential time is 4751 milliseconds
Since the sort algorithm does not return a value, we define a concrete ForkJoinTask class by extending RecursiveAction (lines 33–64). The compute method is overridden to implement a recursive merge sort (lines 42–63). If the list is small, it is more efficient to be solved sequentially (line 44). For a large list, it is split into two halves (lines 47–54). The two halves are sorted concurrently (lines 57 and 58) and then merged (line 61). The program creates a main ForkJoinTask (line 28), a ForkJoinPool (line 29), and places the main task for execution in a ForkJoinPool (line 30). The invoke method will return after the main task is completed. When executing the main task, the task is split into subtasks, and the subtasks are invoked using the invokeAll method (lines 57 and 58). The invokeAll method will return after all the subtasks are completed. Note each subtask is further split into smaller tasks recursively. Huge numbers of subtasks may be created and executed in the pool. The Fork/Join Framework automatically executes and coordinates all the tasks efficiently. The MergeSort class is defined in Listing 23.5. The program invokes MergeSort.merge to merge two sorted sublists (line 61). The program also invokes MergeSort.mergeSort (line 21) to sort a list using merge sort sequentially. You can see that the parallel sort is much faster than the sequential sort. Note the loop for initializing the list can also be parallelized. However, you should avoid using Math.random() in the code because it is synchronized and cannot be executed in parallel (see Programming Exercise 32.12). The parallelMergeSort method only sorts an
M32_LIAN0182_11_SE_C32.indd 35
5/22/17 12:34 PM
32-36 Chapter 32 Multithreading and Parallel Programming array of int values, but you can modify it to become a generic method (see Programming Exercise 32.13). In general, a problem can be solved in parallel using the following pattern: if (the program is small) solve it sequentially; else { divide the problem into nonoverlapping subproblems; solve the subproblems concurrently; combine the results from subproblems to solve the whole problem; }
Listing 32.11 develops a parallel method that finds the maximal number in a list.
Listing 32.11 ParallelMax.java
invoke max
create a ForkJoinTask create a ForkJoinPool execute a task
define concrete ForkJoinTask
perform the task solve a small problem
M32_LIAN0182_11_SE_C32.indd 36
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
import java.util.concurrent.*; public class ParallelMax { public static void main(String[] args) { // Create a list final int N = 9000000; int[] list = new int[N]; for (int i = 0; i < list.length; i++) list[i] = i; long startTime = System.currentTimeMillis(); System.out.println("\nThe maximal number is " + max(list)); long endTime = System.currentTimeMillis(); System.out.println("The number of processors is " + Runtime.getRuntime().availableProcessors()); System.out.println("Time is " + (endTime − startTime) + " milliseconds"); } public static int max(int[] list) { RecursiveTask task = new MaxTask(list, 0, list.length); ForkJoinPool pool = new ForkJoinPool(); return pool.invoke(task); } private static class MaxTask extends RecursiveTask { private final static int THRESHOLD = 1000; private int[] list; private int low; private int high; public MaxTask(int[] list, int low, int high) { this.list = list; this.low = low; this.high = high; } @Override public Integer compute() { if (high − low < THRESHOLD) { int max = list[0]; for (int i = low; i < high; i++) if (list[i] > max) max = list[i]; return new Integer(max);
5/22/17 12:34 PM
Chapter Summary 32-37 46 47 48 49 50 51 52 53 54 55 56 57 58 59
} else { int mid = (low + high) / 2; RecursiveTask left = new MaxTask(list, low, mid); RecursiveTask right = new MaxTask(list, mid, high); right.fork(); left.fork(); return new Integer(Math.max(left.join().intValue(), right.join().intValue()));
split into two parts
fork right fork left join tasks
} } } }
The maximal number is 8999999 The number of processors is 2 Time is 44 milliseconds
Since the algorithm returns an integer, we define a task class for fork join by extending RecursiveTask (lines 26–58). The compute method is overridden to return the max element in a list[low..high] (lines 39–57). If the list is small, it is more efficient to be solved sequentially (lines 40–46). For a large list, it is split into two halves (lines 48–50). The tasks left and right find the maximal element in the left half and right half, respectively. Invoking fork() on the task causes the task to be executed (lines 52 and 53). The join() method awaits for the task to complete and then returns the result (lines 54 and 55).
32.16.1 How do you define a ForkJoinTask? What are the differences between RecursiveAction and RecursiveTask? 32.16.2 How do you tell the system to execute a task? 32.16.3 What method can you use to test if a task has been completed? 32.16.4 How do you create a ForkJoinPool? How do you place a task into a ForkJoinPool?
Check Point
Key Terms condition 32-18 deadlock 32-30 fail-fast 32-32 fairness policy 32-17 Fork/Join Framework 32-32 lock 32-16 monitor 32-22
multithreading 32-2 race condition 32-15 semaphore 32-28 synchronization wrapper 32-31 synchronized block 32-16 thread 32-2 thread-safe 32-15
Chapter Summary 1. Each task is an instance of the Runnable interface. A thread is an object that facilitates
the execution of a task. You can define a task class by implementing the Runnable interface and create a thread by wrapping a task using a Thread constructor.
2. After a thread object is created, use the start() method to start a thread, and the sleep(long) method to put a thread to sleep so other threads get a chance to run.
M32_LIAN0182_11_SE_C32.indd 37
5/22/17 12:34 PM
32-38 Chapter 32 Multithreading and Parallel Programming 3. A thread object never directly invokes the run method. The JVM invokes the run method when it is time to execute the thread. Your class must override the run method to tell the system what the thread will do when it runs.
4. To prevent threads from corrupting a shared resource, use synchronized methods or
blocks. A synchronized method acquires a lock before it executes. In the case of an instance method, the lock is on the object for which the method was invoked. In the case of a static method, the lock is on the class.
5. A synchronized statement can be used to acquire a lock on any object, not just this object, when executing a block of the code in a method. This block is referred to as a synchronized block.
6. You can use explicit locks and conditions to facilitate communications among threads, as well as using the built-in monitor for objects.
7. The blocking queues (ArrayBlockingQueue ,
LinkedBlockingQueue , and PriorityBlockingQueue) provided in the Java Collections Framework provide auto-
matical synchronization for the access to a queue.
8. You can use semaphores to restrict the number of concurrent accesses to a shared resource.
9. Deadlock occurs when two or more threads acquire locks on multiple objects and each has a lock on one object and is waiting for the lock on the other object. The resource ordering technique can be used to avoid deadlock.
10. The JDK 7’s Fork/Join Framework is designed for developing parallel programs. You can define a task class that extends RecursiveAction or RecursiveTask and execute the tasks concurrently in ForkJoinPool and obtain the overall solution after all tasks are completed.
Quiz Answer the quiz for this chapter online at the book Companion Website.
Programming Exercises Sections 32.1–32.5
*32.1 (Revise Listing 32.1) Rewrite Listing 32.1 to display the output in a text area, as shown in Figure 32.30.
Figure 32.30 The output from three threads is displayed in a text area.
M32_LIAN0182_11_SE_C32.indd 38
5/22/17 12:34 PM
Programming Exercises 32-39 32.2 (Racing cars) Rewrite Programming Exercise 15.29 using a thread to control car
32.3
racing. Compare the program with Programming Exercise 15.29 by setting the delay time to 10 in both the programs. Which one runs the animation faster? (Raise flags) Rewrite Listing 15.13 using a thread to animate a flag being raised. Compare the program with Listing 15.13 by setting the delay time to 10 in both programs. Which one runs the animation faster?
Sections 32.8–32.12
32.4 (Synchronize threads) Write a program that launches 1,000 threads. Each thread
32.5 32.6 32.7 32.8 32.9
*32.10
adds 1 to a variable sum that initially is 0. You need to pass sum by reference to each thread. In order to pass it by reference, define an Integer wrapper object to hold sum. Run the program with and without synchronization to see its effect. (Display a running fan) Rewrite Programming Exercise 15.28 using a thread to control the fan animation. (Bouncing balls) Rewrite Listing 15.17, BallPane.java using a thread to animate bouncing ball movements. (Control a clock) Rewrite Programming Exercise 15.32 using a thread to control the clock animation. (Account synchronization) Rewrite Listing 32.6, ThreadCooperation.java, using the object’s wait() and notifyAll() methods. (Demonstrate ConcurrentModificationException) The iterator is fail-fast. Write a program to demonstrate it by creating two threads that concurrently access and modify a set. The first thread creates a hash set filled with numbers and adds a new number to the set every second. The second thread obtains an iterator for the set and traverses the set back and forth through the iterator every second. You will receive a ConcurrentModificationException because the underlying set is being modified in the first thread while the set in the second thread is being traversed. (Use synchronized sets) Using synchronization, correct the problem in the preceding exercise so that the second thread does not throw a ConcurrentModificationException.
Section 32.15
*32.11 (Demonstrate deadlock) Write a program that demonstrates deadlock. Section 32.18
*32.12 (Parallel array initializer) Implement the following method using the Fork/Join Framework to assign random values to the list.
public static void parallelAssignValues(double[] list)
Write a test program that creates a list with 9,000,000 elements and invokes parallelAssignValues to assign random values to the list. Also implement a sequential algorithm and compare the execution time of the two. Note if you use Math.random(), your parallel code execution time will be worse than the sequential code execution time because Math.random() is synchronized and cannot be executed in parallel. To fix this problem, create a Random object for assigning random values to a small list.
M32_LIAN0182_11_SE_C32.indd 39
5/22/17 12:34 PM
32-40 Chapter 32 Multithreading and Parallel Programming 32.13 (Generic parallel merge sort) Revise Listing 32.10, ParallelMergeSort.java, to define a generic parallelMergeSort method as follows:
public static void parallelMergeSort(E[] list)
*32.14 (Parallel quick sort) Implement the following method in parallel to sort a list using quick sort (see Listing 23.7):
public static void parallelQuickSort(int[] list)
*32.15
Write a test program that times the execution time for a list of size 9,000,000 using this parallel method and a sequential method. (Parallel sum) Implement the following method using Fork/Join to find the sum of a list. public static double parallelSum(double[] list)
*32.16
Write a test program that finds the sum in a list of 9,000,000 double values. (Parallel matrix addition) Programming Exercise 8.5 describes how to perform matrix addition. Suppose you have multiple processors, so you can speed up the matrix addition. Implement the following method in parallel: public static double[][] parallelAddMatrix( double[][] a, double[][] b)
*32.17
Write a test program that measures the execution time for adding two 2,000 * 2,000 matrices using the parallel method and sequential method, respectively. (Parallel matrix multiplication) Programming Exercise 7.6 describes how to perform matrix multiplication. Suppose that you have multiple processors, so you can speed up the matrix multiplication. Implement the following method in parallel: public static double[][] parallelMultiplyMatrix( double[][] a, double[][] b)
*32.18
Write a test program that measures the execution time for multiplying two 2,000 * 2,000 matrices using the parallel method and sequential method, respectively. (Parallel Eight Queens) Revise Listing 22.11, EightQueens.java, to develop a parallel algorithm that finds all solutions for the Eight Queens problem. (Hint: Launch eight subtasks, each of which places the queen in a different column in the first row.)
Comprehensive
***32.19 (Sorting animation) Write an animation for selection sort, insertion sort, and
bubble sort, as shown in Figure 32.31. Create an array of integers 1, 2, . . . , 50. Shuffle it randomly. Create a pane to display the array in a histogram. You should invoke each sort method in a separate thread. Each algorithm uses two nested loops. When the algorithm completes an iteration in the outer loop, put the thread to sleep for 0.5 seconds and redisplay the array in the histogram. Color the last bar in the sorted subarray.
M32_LIAN0182_11_SE_C32.indd 40
5/22/17 12:34 PM
Programming Exercises 32-41
Figure 32.31 Three sorting algorithms are illustrated in the animation.
***32.20 (Sudoku search animation) Modify Programming Exercise 22.21 to display the intermediate results of the search. Figure 32.32 gives a snapshot of an animation in progress with number 2 placed in the cell in Figure 32.32a, number 3 placed in the cell in Figure 32.32b, and number 3 placed in the cell in Figure 32.32c. The animation displays all the search steps.
(a)
(b)
(c)
Figure 32.32 The intermediate search steps are displayed in the animation for the Sudoku problem.
M32_LIAN0182_11_SE_C32.indd 41
5/22/17 12:34 PM
32-42 Chapter 32 Multithreading and Parallel Programming
32.21 (Combine colliding bouncing balls) Rewrite Programming Exercise 20.5 using
***32.22
a thread to animate bouncing ball movements. (Eight Queens animation) Modify Listing 22.11, EightQueens.java, to display the intermediate results of the search. As shown in Figure 32.33, the current row being searched is highlighted. Every one second, a new state of the chess board is displayed.
Figure 32.33 The intermediate search steps are displayed in the animation for the Eight Queens problem.
M32_LIAN0182_11_SE_C32.indd 42
5/22/17 12:34 PM
CHAPTER
33 Networking Objectives ■■
To explain the terms: TCP, IP, domain name, domain name server, stream-based communications, and packet-based communications (§33.2).
■■
To create servers using server sockets (§33.2.1) and clients using client sockets (§33.2.2).
■■
To implement Java networking programs using stream sockets (§33.2.3).
■■
To develop an example of a client/server application (§33.2.4).
■■
To obtain Internet addresses using the InetAddress class (§33.3).
■■
To develop servers for multiple clients (§33.4).
■■
To send and receive objects on a network (§33.5).
■■
To develop an interactive tic-tac-toe game played on the Internet (§33.6).
M33_LIAN0182_11_SE_C33.indd 1
5/22/17 2:25 PM
33-2 Chapter 33 Networking
33.1 Introduction Computer networking is used to send and receive messages among computers on the Internet. Key Point
IP address
domain name domain name server
TCP UDP
stream-based communication packet-based communication
To browse the Web or send an email, your computer must be connected to the Internet. The Internet is the global network of millions of computers. Your computer can connect to the Internet through an Internet Service Provider (ISP) using a dialup, DSL, or cable modem, or through a local area network (LAN). When a computer needs to communicate with another computer, it needs to know the other computer’s address. An Internet Protocol (IP) address uniquely identifies the c omputer on the Internet. An IP address consists of four dotted decimal numbers between 0 and 255, such as 130.254.204.33. Since it is not easy to remember so many numbers, they are often mapped to meaningful names called domain names, such as liang.armstrong.edu. Special servers called Domain Name Servers (DNS) on the Internet translate host names into IP addresses. When a computer contacts liang.armstrong.edu, it first asks the DNS to translate this domain name into a numeric IP address then sends the request using the IP address. The Internet Protocol is a low-level protocol for delivering data from one computer to another across the Internet in packets. Two higher-level protocols used in conjunction with the IP are the Transmission Control Protocol (TCP) and the User Datagram Protocol (UDP). TCP enables two hosts to establish a connection and exchange streams of data. TCP guarantees delivery of data and also guarantees that packets will be delivered in the same order in which they were sent. UDP is a standard, low-overhead, connectionless, host-to-host protocol that is used over the IP. UDP allows an application program on one computer to send a datagram to an application program on another computer. Java supports both stream-based and packet-based communications. Stream-based communications use TCP for data transmission, whereas packet-based communications use UDP. Since TCP can detect lost transmissions and resubmit them, transmissions are lossless and reliable. UDP, in contrast, cannot guarantee lossless transmission. Stream-based c ommunications are used in most areas of Java programming and are the focus of this chapter. Packet-based communications are introduced in Supplement III.P, Networking Using Datagram Protocol.
33.2 Client/Server Computing Key Point
socket
Java provides the ServerSocket class for creating a server socket, and the Socket class for creating a client socket. Two programs on the Internet communicate through a server socket and a client socket using I/O streams. Networking is tightly integrated in Java. The Java API provides the classes for creating sockets to facilitate program communications over the Internet. Sockets are the endpoints of logical connections between two hosts and can be used to send and receive data. Java treats socket communications much as it treats I/O operations; thus, programs can read from or write to sockets as easily as they can read from or write to files. Network programming usually involves a server and one or more clients. The client sends requests to the server, and the server responds. The client begins by attempting to establish a connection to the server. The server can accept or deny the connection. Once a connection is established, the client and the server communicate through sockets. The server must be running when a client attempts to connect to the server. The server waits for a connection request from the client. The statements needed to create sockets on a server and on a client are shown in Figure 33.1.
33.2.1 Server Sockets server socket port
M33_LIAN0182_11_SE_C33.indd 2
To establish a server, you need to create a server socket and attach it to a port, which is where the server listens for connections. The port identifies the TCP service on the socket. Port numbers range from 0 to 65536, but port numbers 0 to 1024 are reserved for privileged services.
5/22/17 2:25 PM
33.2 Client/Server Computing 33-3 Server Host
Client Host
Step 1: Create a server socket on a port, e.g., 8000, using the following statement:
Step 3: A client program uses the following statement to connect to the server:
Network
ServerSocket serverSocket = new ServerSocket(8000);
Socket socket = new Socket(serverHost, 8000);
Step 2: Create a socket to connect to a client, using the following statement: Socket socket = serverSocket.accept();
I/O Stream
Figure 33.1 The server creates a server socket and, once a connection to a client is established, connects to the client with a client socket.
For instance, the email server runs on port 25, and the Web server usually runs on port 80. You can choose any port number that is not currently used by other programs. The following statement creates a server socket serverSocket: ServerSocket serverSocket = new ServerSocket(port);
Note Attempting to create a server socket on a port already in use would cause a java.net. BindException.
BindException
33.2.2 Client Sockets After a server socket is created, the server can use the following statement to listen for connections: Socket socket = serverSocket.accept();
This statement waits until a client connects to the server socket. The client issues the following statement to request a connection to a server:
connect to client
Socket socket = new Socket(serverName, port);
This statement opens a socket so that the client program can communicate with the server. serverName is the server’s Internet host name or IP address. The following statement creates a socket on the client machine to connect to the host 130.254.204.33 at port 8000:
client socket use IP address
Socket socket = new Socket("130.254.204.33", 8000);
Alternatively, you can use the domain name to create a socket, as follows:
use domain name
Socket socket = new Socket("liang.armstrong.edu", 8000);
When you create a socket with a host name, the JVM asks the DNS to translate the host name into the IP address.
Note A program can use the host name localhost or the IP address 127.0.0.1 to refer to the machine on which a client is running.
M33_LIAN0182_11_SE_C33.indd 3
localhost
5/22/17 2:25 PM
33-4 Chapter 33 Networking Note The Socket constructor throws a java.net.UnknownHostException if the host cannot be found.
UnknownHostException
33.2.3 Data Transmission through Sockets After the server accepts the connection, the communication between the server and the client is conducted in the same way as for I/O streams. The statements needed to create the streams and to exchange data between them are shown in Figure 33.2.
Server
Client
int port = 8000; DataInputStream in; DataOutputStream out; ServerSocket server; Socket socket; server = new ServerSocket(port); socket = server.accept(); in = new DataInputStream (socket.getInputStream()); out = new DataOutputStream (socket.getOutputStream()); System.out.println(in.readDouble()); out.writeDouble(aNumber);
Connection Request
I/O Streams
int port = 8000; String host = "localhost" DataInputStream in; DataOutputStream out; Socket socket; socket = new Socket(host, port); in = new DataInputStream (socket.getInputStream()); out = new DataOutputStream (socket.getOutputStream()); out.writeDouble(aNumber); System.out.println(in.readDouble());
Figure 33.2 The server and client exchange data through I/O streams on top of the socket. To get an input stream and an output stream, use the getInputStream() and g etOutputStream() methods on a socket object. For example, the following statements create an InputStream stream called input and an OutputStream stream called output from a socket: InputStream input = socket.getInputStream(); OutputStream output = socket.getOutputStream();
The InputStream and OutputStream streams are used to read or write bytes. You can use DataInputStream, DataOutputStream, BufferedReader, and PrintWriter to wrap on the InputStream and OutputStream to read or write data, such as int, double, or String. The following statements, for instance, create the DataInputStream stream input and the DataOutputstream output to read and write primitive data values: DataInputStream input = new DataInputStream (socket.getInputStream()); DataOutputStream output = new DataOutputStream (socket.getOutputStream());
The server can use input.readDouble() to receive a double value from the client, and output.writeDouble(d) to send the double value d to the client.
Tip Recall that binary I/O is more efficient than text I/O because text I/O requires encoding and decoding. Therefore, it is better to use binary I/O for transmitting data between a server and a client to improve performance.
M33_LIAN0182_11_SE_C33.indd 4
5/22/17 2:25 PM
33.2 Client/Server Computing 33-5
33.2.4 A Client/Server Example This example presents a client program and a server program. The client sends data to a server. The server receives the data, uses it to produce a result, and then sends the result back to the client. The client displays the result on the console. In this example, the data sent from the client comprise the radius of a circle, and the result produced by the server is the area of the circle (see Figure 33.3). compute area Server
radius area
Client
Figure 33.3 The client sends the radius to the server; the server computes the area and sends it to the client. The client sends the radius through a DataOutputStream on the output stream socket, and the server receives the radius through the DataInputStream on the input stream socket, as shown in Figure 33.4a. The server computes the area and sends it to the client through a DataOutputStream on the output stream socket, and the client receives the area through a DataInputStream on the input stream socket, as shown in Figure 33.4b. The server and client programs are given in Listings 33.1 and 33.2. Figure 33.5 contains a sample run of the server and the client.
Server
Client
radius
radius
Server
Client
area
area
DataInputStream
DataOutputStream
DataOutputStream
DataInputStream
socket.getInputStream
socket.getOutputStream
socket.getOutputStream
socket.getInputStream
socket
socket
socket
socket
Network
Network
(a)
(b)
Figure 33.4 (a) The client sends the radius to the server. (b) The server sends the area to the client.
Figure 33.5 The client sends the radius to the server. The server receives it, computes the area, and sends the area to the client.
Listing 33.1 Server.java 1 2 3
import java.io.*; import java.net.*; import java.util.Date;
M33_LIAN0182_11_SE_C33.indd 5
5/22/17 2:25 PM
33-6 Chapter 33 Networking
create server UI
server socket update UI
connect client
input from client output to client
read radius
write area update UI
M33_LIAN0182_11_SE_C33.indd 6
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
import import import import import import
javafx.application.Application; javafx.application.Platform; javafx.scene.Scene; javafx.scene.control.ScrollPane; javafx.scene.control.TextArea; javafx.stage.Stage;
public class Server extends Application { @Override // Override the start method in the Application class public void start(Stage primaryStage) { // Text area for displaying contents TextArea ta = new TextArea(); // Create a scene and place it in the stage Scene scene = new Scene(new ScrollPane(ta), 450, 200); primaryStage.setTitle("Server"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage new Thread(() -> { try { // Create a server socket ServerSocket serverSocket = new ServerSocket(8000); Platform.runLater(() -> ta.appendText("Server started at " + new Date() + '\n')); // Listen for a connection request Socket socket = serverSocket.accept(); // Create data input and output streams DataInputStream inputFromClient = new DataInputStream( socket.getInputStream()); DataOutputStream outputToClient = new DataOutputStream( socket.getOutputStream()); while (true) { // Receive radius from the client double radius = inputFromClient.readDouble(); // Compute area double area = radius * radius * Math.PI; // Send area back to the client outputToClient.writeDouble(area); Platform.runLater(() -> { ta.appendText("Radius received from client: " + radius + '\n'); ta.appendText("Area is: " + area + '\n'); }); } } catch(IOException ex) { ex.printStackTrace(); } }).start(); } }
5/22/17 2:25 PM
33.2 Client/Server Computing 33-7
Listing 33.2 Client.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
import import import import import import import import import import import import
java.io.*; java.net.*; javafx.application.Application; javafx.geometry.Insets; javafx.geometry.Pos; javafx.scene.Scene; javafx.scene.control.Label; javafx.scene.control.ScrollPane; javafx.scene.control.TextArea; javafx.scene.control.TextField; javafx.scene.layout.BorderPane; javafx.stage.Stage;
public class Client extends Application { // IO streams DataOutputStream toServer = null; DataInputStream fromServer = null; @Override // Override the start method in the Application class public void start(Stage primaryStage) { // Panel p to hold the label and text field BorderPane paneForTextField = new BorderPane(); paneForTextField.setPadding(new Insets(5, 5, 5, 5)); paneForTextField.setStyle("-fx-border-color: green"); paneForTextField.setLeft(new Label("Enter a radius: "));
create UI
TextField tf = new TextField(); tf.setAlignment(Pos.BOTTOM_RIGHT); paneForTextField.setCenter(tf); BorderPane mainPane = new BorderPane(); // Text area to display contents TextArea ta = new TextArea(); mainPane.setCenter(new ScrollPane(ta)); mainPane.setTop(paneForTextField); // Create a scene and place it in the stage Scene scene = new Scene(mainPane, 450, 200); primaryStage.setTitle("Client"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage tf.setOnAction(e -> { try { // Get the radius from the text field double radius = Double.parseDouble(tf.getText().trim());
M33_LIAN0182_11_SE_C33.indd 7
// Send the radius to the server toServer.writeDouble(radius); toServer.flush(); // Get area from the server double area = fromServer.readDouble();
handle action event
read radius
write radius
read area
// Display to the text area ta.appendText("Radius is " + radius + "\n"); ta.appendText("Area received from the server is " + area + '\n');
5/22/17 2:25 PM
33-8 Chapter 33 Networking
request connection
input from server
output to server
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
} catch (IOException ex) { System.err.println(ex); } }); try { // Create a socket to connect to the server Socket socket = new Socket("localhost", 8000); // Socket socket = new Socket("130.254.204.36", 8000); // Socket socket = new Socket("drake.Armstrong.edu", 8000); // Create an input stream to receive data from the server fromServer = new DataInputStream(socket.getInputStream()); // Create an output stream to send data to the server toServer = new DataOutputStream(socket.getOutputStream()); } catch (IOException ex) { ta.appendText(ex.toString() + '\n'); } } }
You start the server program first then start the client program. In the client program, enter a radius in the text field and press Enter to send the radius to the server. The server computes the area and sends it back to the client. This process is repeated until one of the two programs terminates. The networking classes are in the package java.net. You should import this package when writing Java network programs. The Server class creates a ServerSocket serverSocket and attaches it to port 8000 using this statement (line 26 in Server.java): ServerSocket serverSocket = new ServerSocket(8000);
The server then starts to listen for connection requests, using the following statement (line 31 in Server.java): Socket socket = serverSocket.accept();
The server waits until the client requests a connection. After it is connected, the server reads the radius from the client through an input stream, computes the area, and sends the result to the client through an output stream. The ServerSocket accept() method takes time to execute. It is not appropriate to run this method in the JavaFX application thread. So, we place it in a separate thread (lines 23–59). The statements for updating GUI needs to run from the JavaFX application thread using the Platform.runLater method (lines 27–28, 49–53). The Client class uses the following statement to create a socket that will request a connection to the server on the same machine (localhost) at port 8000 (line 67 in Client.java). Socket socket = new Socket("localhost", 8000);
If you run the server and the client on different machines, replace localhost with the server machine’s host name or IP address. In this example, the server and the client are running on the same machine. If the server is not running, the client program terminates with a java.net. ConnectException. After it is connected, the client gets input and output streams—wrapped by data input and output streams—in order to receive and send data to the server.
M33_LIAN0182_11_SE_C33.indd 8
5/22/17 2:25 PM
33.3 The InetAddress Class 33-9 If you receive a java.net.BindException when you start the server, the server port is currently in use. You need to terminate the process that is using the server port then restart the server.
Note When you create a server socket, you have to specify a port (e.g., 8000) for the socket. When a client connects to the server (line 67 in Client.java), a socket is created on the client. This socket has its own local port. This port number (e.g., 2047) is automatically chosen by the JVM, as shown in Figure 33.6.
client socket port
port number Server
0 1 . . . socket 8000 . . .
0 1 . . . 2047 socket
Client
. . .
Figure 33.6 The JVM automatically chooses an available port to create a socket for the client. To see the local port on the client, insert the following statement in line 70 in Client.java. System.out.println("local port: " + socket.getLocalPort());
33.2.1 How do you create a server socket? What port numbers can be used? What happens if 3.2.2 3 33.2.3 33.2.4 33.2.5
a requested port number is already in use? Can a port connect to multiple clients? What are the differences between a server socket and a client socket? How does a client program initiate a connection? How does a server accept a connection? How are data transferred between a client and a server?
Check Point
33.3 The InetAddress Class The server program can use the InetAddress class to obtain the information about the IP address and host name for the client. Occasionally, you would like to know who is connecting to the server. You can use the InetAddress class to find the client’s host name and IP address. The InetAddress class models an IP address. You can use the following statement in the server program to get an instance of InetAddress on a socket that connects to the client:
Key Point
InetAddress inetAddress = socket.getInetAddress();
Next, you can display the client’s host name and IP address, as follows: System.out.println("Client's host name is " + inetAddress.getHostName());
M33_LIAN0182_11_SE_C33.indd 9
5/22/17 2:25 PM
33-10 Chapter 33 Networking System.out.println("Client's IP Address is " + inetAddress.getHostAddress());
You can also create an instance of InetAddress from a host name or IP address using the static getByName method. For example, the following statement creates an InetAddress for the host liang.armstrong.edu. InetAddress address = InetAddress.getByName("liang.armstrong.edu");
Listing 33.3 gives a program that identifies the host name and IP address of the arguments you pass in from the command line. Line 7 creates an InetAddress using the getByName method. Lines 8 and 9 use the getHostName and getHostAddress methods to get the host’s name and IP address. Figure 33.7 shows a sample run of the program.
Figure 33.7 The program identifies host names and IP addresses.
Listing 33.3 IdentifyHostNameIP.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
get an InetAddress get host name get host IP
Check Point
import java.net.*; public class IdentifyHostNameIP { public static void main(String[] args) { for (int i = 0; i < args.length; i++) { try { InetAddress address = InetAddress.getByName(args[i]); System.out.print("Host name: " + address.getHostName() + " "); System.out.println("IP address: " + address.getHostAddress()); } catch (UnknownHostException ex) { System.err.println("Unknown host or IP address " + args[i]); } } } }
3.3.1 How do you obtain an instance of InetAddress? 3 33.3.2 What methods can you use to get the IP address and hostname from an InetAddress?
33.4 Serving Multiple Clients A server can serve multiple clients. The connection to each client is handled by one thread. Key Point
M33_LIAN0182_11_SE_C33.indd 10
Multiple clients are quite often connected to a single server at the same time. Typically, a server runs continuously on a server computer, and clients from all over the Internet can connect to it. You can use threads to handle the server’s multiple clients simultaneously—simply
5/22/17 2:25 PM
33.4 Serving Multiple Clients 33-11 create a thread for each connection. Here is how the server handles the establishment of a connection: while (true) { Socket socket = serverSocket.accept(); // Connect to a client Thread thread = new ThreadClass(socket); thread.start(); }
The server socket can have many connections. Each iteration of the while loop creates a new connection. Whenever a connection is established, a new thread is created to handle communication between the server and the new client, and this allows multiple connections to run at the same time. Listing 33.4 creates a server class that serves multiple clients simultaneously. For each connection, the server starts a new thread. This thread continuously receives input (the radius of a circle) from clients and sends the results (the area of the circle) back to them (see Figure 33.8). The client program is the same as in Listing 33.2. A sample run of the server with two clients is shown in Figure 33.9.
Server
A socket for a client
Client 1
A server socket on a port A socket for a client
...
Client n
Figure 33.8 Multithreading enables a server to handle multiple independent clients.
Figure 33.9 The server spawns a thread in order to serve a client.
Listing 33.4 MultiThreadServer.java 1 2 3 4 5 6 7 8 9 10
import import import import import import import import import
M33_LIAN0182_11_SE_C33.indd 11
java.io.*; java.net.*; java.util.Date; javafx.application.Application; javafx.application.Platform; javafx.scene.Scene; javafx.scene.control.ScrollPane; javafx.scene.control.TextArea; javafx.stage.Stage;
5/22/17 2:25 PM
33-12 Chapter 33 Networking
server socket
connect client
update GUI
network information
create task
start thread
task class
M33_LIAN0182_11_SE_C33.indd 12
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
public class MultiThreadServer extends Application { // Text area for displaying contents private TextArea ta = new TextArea(); // Number a client private int clientNo = 0; @Override // Override the start method in the Application class public void start(Stage primaryStage) { // Create a scene and place it in the stage Scene scene = new Scene(new ScrollPane(ta), 450, 200); primaryStage.setTitle("MultiThreadServer"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage new Thread( () -> { try { // Create a server socket ServerSocket serverSocket = new ServerSocket(8000); ta.appendText("MultiThreadServer started at " + new Date() + '\n'); while (true) { // Listen for a new connection request Socket socket = serverSocket.accept(); // Increment clientNo clientNo++; Platform.runLater( () -> { // Display the client number ta.appendText("Starting thread for client " + clientNo + " at " + new Date() + '\n'); // Find the client's host name, and IP address InetAddress inetAddress = socket.getInetAddress(); ta.appendText("Client " + clientNo + "'s host name is " + inetAddress.getHostName() + "\n"); ta.appendText("Client " + clientNo + "'s IP Address is" + inetAddress.getHostAddress() + "\n"); }); // Create and start a new thread for the connection new Thread(new HandleAClient(socket)).start(); } } catch(IOException ex) { System.err.println(ex); } }).start(); } // Define the thread class for handling new connection class HandleAClient implements Runnable { private Socket socket; // A connected socket /** Construct a thread */ public HandleAClient(Socket socket) { this.socket = socket; }
5/22/17 2:25 PM
33.5 Sending and Receiving Objects 33-13 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
/** Run a thread */ public void run() { try { // Create data input and output streams DataInputStream inputFromClient = new DataInputStream( socket.getInputStream()); DataOutputStream outputToClient = new DataOutputStream( socket.getOutputStream());
I/O
// Continuously serve the client while (true) { // Receive radius from the client double radius = inputFromClient.readDouble(); // Compute area double area = radius * radius * Math.PI; // Send area back to the client outputToClient.writeDouble(area); Platform.runLater(() -> { ta.appendText("radius received from client: " + radius + '\n'); ta.appendText("Area found: " + area + '\n'); });
update GUI
} } catch(IOException ex) { ex.printStackTrace(); } } } }
The server creates a server socket at port 8000 (line 29) and waits for a connection (line 35). When a connection with a client is established, the server creates a new thread to handle the communication (line 54). It then waits for another connection in an infinite while loop (lines 33–55). The threads, which run independently of one another, communicate with designated clients. Each thread creates data input and output streams that receive and send data to a client.
33.4.1 How do you make a server serve multiple clients?
Check Point
33.5 Sending and Receiving Objects A program can send and receive objects from another program. In the preceding examples, you learned how to send and receive data of primitive types. You can also send and receive objects using ObjectOutputStream and ObjectInputStream on socket streams. To enable passing, the objects must be serializable. The following example demonstrates how to send and receive objects. The example consists of three classes: StudentAddress.java (Listing 33.5), StudentClient.java (Listing 33.6), and StudentServer.java (Listing 33.7). The client program collects student information from the client and sends it to a server, as shown in Figure 33.10. The StudentAddress class contains the student information: name, street, city, state, and zip. The StudentAddress class implements the Serializable interface. Therefore, a StudentAddress object can be sent and received using the object output and input streams.
M33_LIAN0182_11_SE_C33.indd 13
Key Point
5/22/17 2:25 PM
33-14 Chapter 33 Networking
Figure 33.10 The client sends the student information in an object to the server.
Listing 33.5 StudentAddress.java serialized
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
public class StudentAddress implements java.io.Serializable { private String name; private String street; private String city; private String state; private String zip; public StudentAddress(String name, String street, String city, String state, String zip) { this.name = name; this.street = street; this.city = city; this.state = state; this.zip = zip; } public String getName() { return name; } public String getStreet() { return street; } public String getCity() { return city; } public String getState() { return state; } public String getZip() { return zip; } }
The client sends a StudentAddress object through an ObjectOutputStream on the output stream socket, and the server receives the Student object through the ObjectInputStream on the input stream socket, as shown in Figure 33.11. The c lient uses the writeObject method in the ObjectOutputStream class to send data about a student to the server, and the server receives the student’s information using the readObject method in the O bjectInputStream class. The server and client programs are given in Listings 33.6 and 33.7.
M33_LIAN0182_11_SE_C33.indd 14
5/22/17 2:25 PM
33.5 Sending and Receiving Objects 33-15 Server
Client student object
student object
in.readObject()
out.writeObject(Object)
in: ObjectInputStream
out: ObjectOutputStream
socket.getInputStream()
socket.getOutputStream()
socket
socket
Network
Figure 33.11 The client sends a StudentAddress object to the server.
Listing 33.6 StudentClient.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
import import import import import import import import import import import import import import
java.io.*; java.net.*; javafx.application.Application; javafx.event.ActionEvent; javafx.event.EventHandler; javafx.geometry.HPos; javafx.geometry.Pos; javafx.scene.Scene; javafx.scene.control.Button; javafx.scene.control.Label; javafx.scene.control.TextField; javafx.scene.layout.GridPane; javafx.scene.layout.HBox; javafx.stage.Stage;
public class StudentClient extends Application { private TextField tfName = new TextField(); private TextField tfStreet = new TextField(); private TextField tfCity = new TextField(); private TextField tfState = new TextField(); private TextField tfZip = new TextField(); // Button for sending a student to the server private Button btRegister = new Button("Register to the Server"); // Host name or ip String host = "localhost"; @Override // Override the start method in the Application class public void start(Stage primaryStage) { GridPane pane = new GridPane(); pane.add(new Label("Name"), 0, 0); pane.add(tfName, 1, 0); pane.add(new Label("Street"), 0, 1); pane.add(tfStreet, 1, 1); pane.add(new Label("City"), 0, 2);
M33_LIAN0182_11_SE_C33.indd 15
create UI
5/22/17 2:26 PM
33-16 Chapter 33 Networking
register listener
server socket
output stream
send to server
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
HBox hBox = new HBox(2); pane.add(hBox, 1, 2); hBox.getChildren().addAll(tfCity, new Label("State"), tfState, new Label("Zip"), tfZip); pane.add(btRegister, 1, 3); GridPane.setHalignment(btRegister, HPos.RIGHT); pane.setAlignment(Pos.CENTER); tfName.setPrefColumnCount(15); tfStreet.setPrefColumnCount(15); tfCity.setPrefColumnCount(10); tfState.setPrefColumnCount(2); tfZip.setPrefColumnCount(3); btRegister.setOnAction(new ButtonListener()); // Create a scene and place it in the stage Scene scene = new Scene(pane, 450, 200); primaryStage.setTitle("StudentClient"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage } /** Handle button action */ private class ButtonListener implements EventHandler { @Override public void handle(ActionEvent e) { try { // Establish connection with the server Socket socket = new Socket(host, 8000); // Create an output stream to the server ObjectOutputStream toServer = new ObjectOutputStream(socket.getOutputStream()); // Get String String String String String
text field name = tfName.getText().trim(); street = tfStreet.getText().trim(); city = tfCity.getText().trim(); state = tfState.getText().trim(); zip = tfZip.getText().trim();
// Create a Student object and send to the server StudentAddress s = new StudentAddress(name, street, city, state, zip); toServer.writeObject(s); } catch (IOException ex) { ex.printStackTrace(); } } } }
Listing 33.7 StudentServer.java 1 2 3 4
M33_LIAN0182_11_SE_C33.indd 16
import java.io.*; import java.net.*; public class StudentServer {
5/22/17 2:26 PM
33.5 Sending and Receiving Objects 33-17 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
private ObjectOutputStream outputToFile; private ObjectInputStream inputFromClient; public static void main(String[] args) { new StudentServer(); } public StudentServer() { try { // Create a server socket ServerSocket serverSocket = new ServerSocket(8000); System.out.println("Server started "); // Create an object output stream outputToFile = new ObjectOutputStream( new FileOutputStream("student.dat", true)); while (true) { // Listen for a new connection request Socket socket = serverSocket.accept(); // Create an input stream from the socket inputFromClient = new ObjectInputStream(socket.getInputStream()); // Read from input Object object = inputFromClient.readObject(); // Write to the file outputToFile.writeObject(object); System.out.println("A new student object is stored");
server socket
output to file
connect to client
input stream
get from client
write to file
} } catch(ClassNotFoundException ex) { ex.printStackTrace(); } catch(IOException ex) { ex.printStackTrace(); } finally { try { inputFromClient.close(); outputToFile.close(); } catch (Exception ex) { ex.printStackTrace(); } } } }
On the client side, when the user clicks the Register to the Server button, the client creates a socket to connect to the host (line 67), creates an ObjectOutputStream on the output stream of the socket (lines 70 and 71), and invokes the writeObject method to send the StudentAddress object to the server through the object output stream (line 83). On the server side, when a client connects to the server, the server creates an ObjectI nputStream on the input stream of the socket (lines 27 and 28), invokes the readObject method to receive the StudentAddress object through the object input stream (line 31), and writes the object to a file (line 34).
M33_LIAN0182_11_SE_C33.indd 17
5/22/17 2:26 PM
33-18 Chapter 33 Networking Check Point
33.5.1 How does a server receive connection from a client? How does a client connect to a server? How do you find the host name of a client program from the server? How do you send and receive an object?
3.5.2 3 33.5.3
33.6 Case Study: Distributed Tic-Tac-Toe Games Key Point
This section develops a program that enables two players to play the tic-tac-toe game on the Internet. In Section 16.12, Case Study: Developing a Tic-Tac-Toe Game, you developed a program for a tic-tac-toe game that enables two players to play the game on the same machine. In this section, you will learn how to develop a distributed tic-tac-toe game using multithreads and networking with socket streams. A distributed tic-tac-toe game enables users to play on different machines from anywhere on the Internet. You need to develop a server for multiple clients. The server creates a server socket and accepts connections from every two players to form a session. Each session is a thread that communicates with the two players and determines the status of the game. The server can establish any number of sessions, as shown in Figure 33.12. For each session, the first client connecting to the server is identified as player 1 with token X, and the second client connecting is identified as player 2 with token O. The server notifies the players of their respective tokens. Once two clients are connected to it, the server starts a thread to facilitate the game between the two players by performing the steps repeatedly, as shown in Figure 33.13.
Server Session 1
Player 1
Player 2
...
Session n
...
Player 1
Player 2
Figure 33.12 The server can create many sessions, each of which facilitates a tic-tac-toe game for two players. The server does not have to be a graphical component, but creating it in a GUI in which game information can be viewed is user friendly. You can create a scroll pane to hold a text area in the GUI and display game information in the text area. The server creates a thread to handle a game session when two players are connected to the server. The client is responsible for interacting with the players. It creates a user interface with nine cells and displays the game title and status to the players in the labels. The client class is very similar to the TicTacToe class presented in the case study in Listing 16.13. However, the client in this example does not determine the game status (win or draw); it simply passes the moves to the server and receives the game status from the server. Based on the foregoing analysis, you can create the following classes: ■■ TicTacToeServer
serves all the clients in Listing 33.9.
facilitates the game for two players. This class is defined in Listing 33.9, TicTacToeServer.java.
■■ HandleASession
M33_LIAN0182_11_SE_C33.indd 18
5/22/17 2:26 PM
33.6 Case Study: Distributed Tic-Tac-Toe Games 33-19 Player 1
Server
Player 2
1. Initialize user interface.
Create a server socket.
1. Initialize user interface.
2. Request connection to the server and learn which token to use from the
Accept connection from the first player and notify the player who is Player 1 with token X.
server. Accept connection from the second player and notify the player who is Player 2 with token O. Start a thread for the session.
2. Request connection to the server and learn which token to use from the server.
Handle a session:
3. Get the start signal from the server. 4. Wait for the player to mark a cell, send the cell's row and column index to the server. 5. Receive status from the server. 6. If WIN, display the winner; if Player 2 wins, receive the last move from Player 2. Break the loop. 7. If DRAW, display game is over; break the loop.
1. Tell Player 1 to start. 2. Receive row and column of the selected cell from Player 1. 3. Determine the game status (WIN, DRAW, CONTINUE). If Player 1 wins, or draws, send the status (PLAYER1_WON, DRAW) to both players and send Player 1's move to Player 2. Exit.
4. If WIN, display the winner. If Player 1 wins, receive Player 1's last move, and break the loop.
4. If CONTINUE, notify Player 2 to take the turn, and send Player 1's newly selected row and column index to Player 2.
5. If DRAW, display game is over, and receive Player 1's last move, and break
5. Receive row and column of the selected cell from Player 2.
8. If CONTINUE, receive Player 2's selected row and column index and mark the cell for Player 2.
3. Receive status from the server.
6. If Player 2 wins, send the status (PLAYER2_WON) to both players, and send Player 2's move to Player 1. Exit. 7. If CONTINUE, send the status, and send Player 2's newly selected row and column index to Player 1.
the loop. 6. If CONTINUE, receive Player 1's selected row and index and mark the cell for Player 1. 7. Wait for the player to move, and send the selected row and column to the server.
Figure 33.13 The server starts a thread to facilitate communications between the two players. ■■ TicTacToeClient ■■ Cell
models a player in Listing 33.10.
models a cell in the game. It is an inner class in TicTacToeClient.
is an interface that defines the constants shared by all the classes in the example in Listing 33.8.
■■ TicTacToeConstants
The relationships of these classes are shown in Figure 33.14.
Listing 33.8 TicTacToeConstants.java public interface TicTacToeConstants { public static int PLAYER1 = 1; // Indicate player 1 public static int PLAYER2 = 2; // Indicate player 2 public static int PLAYER1_WON = 1; // Indicate player 1 won public static int PLAYER2_WON = 2; // Indicate player 2 won public static int DRAW = 3; // Indicate a draw public static int CONTINUE = 4; // Indicate to continue }
1 2 3 4 5 6 7 8
Listing 33.9 TicTacToeServer.java 1 2
import java.io.*; import java.net.*;
M33_LIAN0182_11_SE_C33.indd 19
5/22/17 2:26 PM
33-20 Chapter 33 Networking JFrame
TicTacToeServer
HandleASession
TicTacToeConstants
Similar to Listing 18.10
JApplet
TicTacToeClient
Cell
Runnable TicTacToeServer
HandleASession
+main(args: String[]):void
«interface» TicTacToeConstants
-player1: Socket -player2: Socket -cell: char[][] -continueToPlay: boolean +run(): void -isWon(): boolean -isFull(): boolean -sendMove(out: DataOutputStream, row: int, column: int): void
+PLAYER1 = 1: int +PLAYER2 = 2: int +PLAYER1_WON = 1: int +PLAYER2_WON = 2: int +DRAW = 3: int +CONTINUE = 4: int
TicTacToeClient -myTurn: boolean -myToken: char -otherToken: char -cell: Cell[][] -continueToPlay: boolean -rowSelected: int -columnSelected: int -fromServer: DataInputStream -toServer: DataOutputStream -waiting: boolean
+run(): void -connectToServer(): void -receiveMove(): void -sendMove(): void -receiveInfoFromServer(): void -waitForPlayerAction(): void
Figure 33.14 TicTacToeServer creates an instance of HandleASession for each session of two players. TicTacToeClient creates nine cells in the UI.
create UI
M33_LIAN0182_11_SE_C33.indd 20
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
import import import import import import import
java.util.Date; javafx.application.Application; javafx.application.Platform; javafx.scene.Scene; javafx.scene.control.ScrollPane; javafx.scene.control.TextArea; javafx.stage.Stage;
public class TicTacToeServer extends Application implements TicTacToeConstants { private int sessionNo = 1; // Number a session @Override // Override the start method in the Application class public void start(Stage primaryStage) { TextArea taLog = new TextArea(); // Create a scene and place it in the stage Scene scene = new Scene(new ScrollPane(taLog), 450, 200); primaryStage.setTitle("TicTacToeServer"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage new Thread( () -> { try { // Create a server socket
5/22/17 2:26 PM
33.6 Case Study: Distributed Tic-Tac-Toe Games 33-21 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
ServerSocket serverSocket = new ServerSocket(8000); Platform.runLater(() -> taLog.appendText(new Date() + ": Server started at socket 8000\n"));
server socket
// Ready to create a session for every two players while (true) { Platform.runLater(() -> taLog.appendText(new Date() + ": Wait for players to join session " + sessionNo + '\n')); // Connect to player 1 Socket player1 = serverSocket.accept();
connect to client
Platform.runLater(() -> { taLog.appendText(new Date() + ": Player 1 joined session " + sessionNo + '\n'); taLog.appendText("Player 1's IP address" + player1.getInetAddress().getHostAddress() + '\n'); }); // Notify that the player is Player 1 new DataOutputStream( player1.getOutputStream()).writeInt(PLAYER1); // Connect to player 2 Socket player2 = serverSocket.accept();
to player1
connect to client
Platform.runLater(() -> { taLog.appendText(new Date() + ": Player 2 joined session " + sessionNo + '\n'); taLog.appendText("Player 2's IP address" + player2.getInetAddress().getHostAddress() + '\n'); }); // Notify that the player is Player 2 new DataOutputStream( player2.getOutputStream()).writeInt(PLAYER2);
to player2
// Display this session and increment session number Platform.runLater(() -> taLog.appendText(new Date() + ": Start a thread for session " + sessionNo++ + '\n')); // Launch a new thread for this session of two players new Thread(new HandleASession(player1, player2)).start();
a session for two players
} } catch(IOException ex) { ex.printStackTrace(); } }).start(); } // Define the thread class for handling a new session for two players class HandleASession implements Runnable, TicTacToeConstants { private Socket player1; private Socket player2; // Create and initialize cells private char[][] cell = new char[3][3]; private DataInputStream fromPlayer1;
M33_LIAN0182_11_SE_C33.indd 21
5/22/17 2:26 PM
33-22 Chapter 33 Networking
IO streams
X won?
Is full?
M33_LIAN0182_11_SE_C33.indd 22
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
private DataOutputStream toPlayer1; private DataInputStream fromPlayer2; private DataOutputStream toPlayer2; // Continue to play private boolean continueToPlay = true; /** Construct a thread */ public HandleASession(Socket player1, Socket player2) { this.player1 = player1; this.player2 = player2; // Initialize cells for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) cell[i][j] = ' '; } /** Implement the run() method for the thread */ public void run() { try { // Create data input and output streams DataInputStream fromPlayer1 = new DataInputStream( player1.getInputStream()); DataOutputStream toPlayer1 = new DataOutputStream( player1.getOutputStream()); DataInputStream fromPlayer2 = new DataInputStream( player2.getInputStream()); DataOutputStream toPlayer2 = new DataOutputStream( player2.getOutputStream()); // Write anything to notify player 1 to start // This is just to let player 1 know to start toPlayer1.writeInt(1); // Continuously serve the players and determine and report // the game status to the players while (true) { // Receive a move from player 1 int row = fromPlayer1.readInt(); int column = fromPlayer1.readInt(); cell[row][column] = 'X'; // Check if Player 1 wins if (isWon('X')) { toPlayer1.writeInt(PLAYER1_WON); toPlayer2.writeInt(PLAYER1_WON); sendMove(toPlayer2, row, column); break; // Break the loop } else if (isFull()) { // Check if all cells are filled toPlayer1.writeInt(DRAW); toPlayer2.writeInt(DRAW); sendMove(toPlayer2, row, column); break; } else { // Notify player 2 to take the turn toPlayer2.writeInt(CONTINUE);
5/22/17 2:26 PM
33.6 Case Study: Distributed Tic-Tac-Toe Games 33-23 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
// Send player 1's selected row and column to player 2 sendMove(toPlayer2, row, column); } // Receive a move from Player 2 row = fromPlayer2.readInt(); column = fromPlayer2.readInt(); cell[row][column] = 'O'; // Check if Player 2 wins if (isWon('O')) { toPlayer1.writeInt(PLAYER2_WON); toPlayer2.writeInt(PLAYER2_WON); sendMove(toPlayer1, row, column); break; } else { // Notify player 1 to take the turn toPlayer1.writeInt(CONTINUE);
O won?
// Send player 2's selected row and column to player 1 sendMove(toPlayer1, row, column); } } } catch(IOException ex) { ex.printStackTrace(); } } /** Send the move to other player */ private void sendMove(DataOutputStream out, int row, int column) throws IOException { out.writeInt(row); // Send row index out.writeInt(column); // Send column index }
send a move
/** Determine if the cells are all occupied */ private boolean isFull() { for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (cell[i][j] == ' ') return false; // At least one cell is not filled // All cells are filled return true; } /** Determine if the player with the specified token wins */ private boolean isWon(char token) { // Check all rows for (int i = 0; i < 3; i++) if ((cell[i][0] == token) && (cell[i][1] == token) && (cell[i][2] == token)) { return true; } /** Check all columns */ for (int j = 0; j < 3; j++)
M33_LIAN0182_11_SE_C33.indd 23
5/22/17 2:26 PM
33-24 Chapter 33 Networking 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
if ((cell[0][j] == token) && (cell[1][j] == token) && (cell[2][j] == token)) { return true; } /** Check major diagonal */ if ((cell[0][0] == token) && (cell[1][1] == token) && (cell[2][2] == token)) { return true; } /** Check subdiagonal */ if ((cell[0][2] == token) && (cell[1][1] == token) && (cell[2][0] == token)) { return true; } /** All checked, but no winner */ return false; } } }
Listing 33.10 TicTacToeClient.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
M33_LIAN0182_11_SE_C33.indd 24
import import import import import import import import import import import import import import import import
java.io.*; java.net.*; java.util.Date; javafx.application.Application; javafx.application.Platform; javafx.scene.Scene; javafx.scene.control.Label; javafx.scene.control.ScrollPane; javafx.scene.control.TextArea; javafx.scene.layout.BorderPane; javafx.scene.layout.GridPane; javafx.scene.layout.Pane; javafx.scene.paint.Color; javafx.scene.shape.Ellipse; javafx.scene.shape.Line; javafx.stage.Stage;
public class TicTacToeClient extends Application implements TicTacToeConstants { // Indicate whether the player has the turn private boolean myTurn = false; // Indicate the token for the player private char myToken = ' '; // Indicate the token for the other player private char otherToken = ' '; // Create and initialize cells private Cell[][] cell = new Cell[3][3];
5/22/17 2:26 PM
33.6 Case Study: Distributed Tic-Tac-Toe Games 33-25 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
// Create and initialize a title label private Label lblTitle = new Label(); // Create and initialize a status label private Label lblStatus = new Label(); // Indicate selected row and column by the current move private int rowSelected; private int columnSelected; // Input and output streams from/to server private DataInputStream fromServer; private DataOutputStream toServer; // Continue to play? private boolean continueToPlay = true; // Wait for the player to mark a cell private boolean waiting = true; // Host name or ip private String host = "localhost"; @Override // Override the start method in the Application class public void start(Stage primaryStage) { // Pane to hold cell GridPane pane = new GridPane(); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) pane.add(cell[i][j] = new Cell(i, j), j, i);
create UI
BorderPane borderPane = new BorderPane(); borderPane.setTop(lblTitle); borderPane.setCenter(pane); borderPane.setBottom(lblStatus); // Create a scene and place it in the stage Scene scene = new Scene(borderPane, 320, 350); primaryStage.setTitle("TicTacToeClient"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage // Connect to the server connectToServer();
connect to server
} private void connectToServer() { try { // Create a socket to connect to the server Socket socket = new Socket(host, 8000); // Create an input stream to receive data from the server fromServer = new DataInputStream(socket.getInputStream());
input from server
// Create an output stream to send data to the server toServer = new DataOutputStream(socket.getOutputStream());
output to server
} catch (Exception ex) { ex.printStackTrace(); }
M33_LIAN0182_11_SE_C33.indd 25
5/22/17 2:26 PM
33-26 Chapter 33 Networking 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
M33_LIAN0182_11_SE_C33.indd 26
// Control the game on a separate thread new Thread(() -> { try { // Get notification from the server int player = fromServer.readInt(); // Am I player 1 or 2? if (player == PLAYER1) { myToken = 'X'; otherToken = 'O'; Platform.runLater(() -> { lblTitle.setText("Player 1 with token 'X'"); lblStatus.setText("Waiting for player 2 to join"); }); // Receive startup notification from the server fromServer.readInt(); // Whatever read is ignored // The other player has joined Platform.runLater(() -> lblStatus.setText("Player 2 has joined. I start first")); // It is my turn myTurn = true; } else if (player == PLAYER2) { myToken = 'O'; otherToken = 'X'; Platform.runLater(() -> { lblTitle.setText("Player 2 with token 'O'"); lblStatus.setText("Waiting for player 1 to move"); }); } // Continue to play while (continueToPlay) { if (player == PLAYER1) { waitForPlayerAction(); // Wait for player 1 to move sendMove(); // Send the move to the server receiveInfoFromServer(); // Receive info from the server } else if (player == PLAYER2) { receiveInfoFromServer(); // Receive info from the server waitForPlayerAction(); // Wait for player 2 to move sendMove(); // Send player 2's move to the server } } } catch (Exception ex) { ex.printStackTrace(); } }).start(); } /** Wait for the player to mark a cell */ private void waitForPlayerAction() throws InterruptedException { while (waiting) { Thread.sleep(100); }
5/22/17 2:26 PM
33.6 Case Study: Distributed Tic-Tac-Toe Games 33-27 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
waiting = true; } /** Send this player's move to the server */ private void sendMove() throws IOException { toServer.writeInt(rowSelected); // Send the selected row toServer.writeInt(columnSelected); // Send the selected column } /** Receive info from the server */ private void receiveInfoFromServer() throws IOException { // Receive game status int status = fromServer.readInt(); if (status == PLAYER1_WON) { // Player 1 won, stop playing continueToPlay = false; if (myToken == 'X') { Platform.runLater(() -> lblStatus.setText("I won! (X)")); } else if (myToken == 'O') { Platform.runLater(() -> lblStatus.setText("Player 1 (X) has won!")); receiveMove(); } } else if (status == PLAYER2_WON) { // Player 2 won, stop playing continueToPlay = false; if (myToken == 'O') { Platform.runLater(() -> lblStatus.setText("I won! (O)")); } else if (myToken == 'X') { Platform.runLater(() -> lblStatus.setText("Player 2 (O) has won!")); receiveMove(); } } else if (status == DRAW) { // No winner, game is over continueToPlay = false; Platform.runLater(() -> lblStatus.setText("Game is over, no winner!")); if (myToken == 'O') { receiveMove(); } } else { receiveMove(); Platform.runLater(() -> lblStatus.setText("My turn")); myTurn = true; // It is my turn } } private void receiveMove() throws IOException { // Get the other player's move int row = fromServer.readInt(); int column = fromServer.readInt();
M33_LIAN0182_11_SE_C33.indd 27
5/22/17 2:26 PM
33-28 Chapter 33 Networking
model a cell
register listener
draw X
draw O
M33_LIAN0182_11_SE_C33.indd 28
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
Platform.runLater(() -> cell[row][column].setToken(otherToken)); } // An inner class for a cell public class Cell extends Pane { // Indicate the row and column of this cell in the board private int row; private int column; // Token used for this cell private char token = ' '; public Cell(int row, int column) { this.row = row; this.column = column; this.setPrefSize(2000, 2000); // What happens without this? setStyle("-fx-border-color: black"); // Set cell's border this.setOnMouseClicked(e -> handleMouseClick()); } /** Return token */ public char getToken() { return token; } /** Set a new token */ public void setToken(char c) { token = c; repaint(); } protected void repaint() { if (token == 'X') { Line line1 = new Line(10, 10, this.getWidth() − 10, this.getHeight() − 10); line1.endXProperty().bind(this.widthProperty().subtract(10)); line1.endYProperty().bind(this.heightProperty().subtract(10)); Line line2 = new Line(10, this.getHeight() − 10, this.getWidth() − 10, 10); line2.startYProperty().bind( this.heightProperty().subtract(10)); line2.endXProperty().bind(this.widthProperty().subtract(10)); // Add the lines to the pane this.getChildren().addAll(line1, line2); } else if (token == 'O') { Ellipse ellipse = new Ellipse(this.getWidth() / 2, this.getHeight() / 2, this.getWidth() / 2 − 10, this.getHeight() / 2 − 10); ellipse.centerXProperty().bind( this.widthProperty().divide(2)); ellipse.centerYProperty().bind( this.heightProperty().divide(2)); ellipse.radiusXProperty().bind( this.widthProperty().divide(2).subtract(10)); ellipse.radiusYProperty().bind( this.heightProperty().divide(2).subtract(10)); ellipse.setStroke(Color.BLACK); ellipse.setFill(Color.WHITE);
5/22/17 2:26 PM
33.6 Case Study: Distributed Tic-Tac-Toe Games 33-29 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
getChildren().add(ellipse); // Add the ellipse to the pane } } /* Handle a mouse click event */ private void handleMouseClick() { // If cell is not occupied and the player has the if (token == ' ' && myTurn) { setToken(myToken); // Set the player's token in myTurn = false; rowSelected = row; columnSelected = column; lblStatus.setText("Waiting for the other player waiting = false; // Just completed a successful } }
mouse clicked handler turn the cell
to move"); move
} }
The server can serve any number of sessions simultaneously. Each session takes care of two players. The client can be deployed to run as a Java applet. To run a client as a Java applet from a Web browser, the server must run from a Web server. Figures 33.15 and 33.16 show sample runs of the server and the clients.
Figure 33.15 TicTacToeServer accepts connection requests and creates sessions to serve pairs of players.
Figure 33.16 TicTacToeClient can run as an applet or standalone.
The TicTacToeConstants interface defines the constants shared by all the classes in the project. Each class that uses the constants needs to implement the interface. Centrally defining constants in an interface is a common practice in Java. Once a session is established, the server receives moves from the players in alternation. Upon receiving a move from a player, the server determines the status of the game. If the game is not finished, the server sends the status (CONTINUE) and the player’s move to the other
M33_LIAN0182_11_SE_C33.indd 29
5/22/17 2:26 PM
33-30 Chapter 33 Networking player. If the game is won or a draw, the server sends the status (PLAYER1_WON, PLAYER2_ WON, or DRAW) to both players. The implementation of Java network programs at the socket level is tightly synchronized. An operation to send data from one machine requires an operation to receive data from the other machine. As shown in this example, the server and the client are tightly synchronized to send or receive data. Check Point
33.6.1 What would happen if the preferred size for a cell is not set in line 227 in Listing 33.10?
33.6.2 If a player does not have the turn but clicks on an empty cell, what will the client program in Listing 33.10 do?
Key Terms client socket 33-3 domain name 33-2 domain name server 33-2 localhost 33-3 IP address 33-2 port 33-2
packet-based communication 33-2 server socket 33-2 socket 33-2 stream-based communication 33-2 TCP 33-2 UDP 33-2
Chapter Summary 1. Java supports stream sockets and datagram sockets. Stream sockets use TCP (Transmission Control Protocol) for data transmission, whereas datagram sockets use UDP (User Datagram Protocol). Since TCP can detect lost transmissions and resubmit them, transmissions are lossless and reliable. UDP, in contrast, cannot guarantee lossless transmission.
2. To create a server, you must first obtain a server socket, using new ServerSocket(port). After a server socket is created, the server can start to listen for connections, using the accept() method on the server socket. The client requests a connection to a server by using new Socket(serverName, port) to create a client socket.
3. Stream socket communication is very much like input/output stream communication after the connection between a server and a client is established. You can obtain an input stream using the getInputStream() method and an output stream using the getOutputStream() method on the socket.
4. A server must often work with multiple clients at the same time. You can use threads
to handle the server’s multiple clients simultaneously by creating a thread for each connection.
Quiz Answer the quiz for this chapter online at book Companion Website.
M33_LIAN0182_11_SE_C33.indd 30
5/22/17 2:26 PM
Programming Exercises 33-31
Programming Exercises Section 33.2
*33.1 (Loan server) Write a server for a client. The client sends loan information (annual
interest rate, number of years, and loan amount) to the server (see Figure 33.17a). The server computes monthly payment and total payment, and sends them back to the client (see Figure 33.17b). Name the client Exercise33_01Client and the server Exercise33_01Server.
(a)
(b)
Figure 33.17 The client in (a) sends the annual interest rate, number of years, and loan amount to the server and receives the monthly payment and total payment from the server in (b).
*33.2 (BMI server) Write a server for a client. The client sends the weight and height
for a person to the server (see Figure 33.18a). The server computes BMI (Body Mass Index) and sends back to the client a string that reports the BMI (see Figure 33.18b). See Section 3.8 for computing BMI. Name the client Exercise33_02Client and the server Exercise33_02Server.
(a)
(b)
Figure 33.18 The client in (a) sends the weight and height of a person to the server and receives the BMI from the server in (b).
Sections 33.3 and 33.4
*33.3 (Loan server for multiple clients) Revise Programming Exercise 33.1 to write a server for multiple clients.
Section 33.5
33.4 (Count clients) Write a server that tracks the number of the clients connected to
the server. When a new connection is established, the count is incremented by 1. The count is stored using a random-access file. Write a client program that receives
M33_LIAN0182_11_SE_C33.indd 31
5/22/17 2:26 PM
33-32 Chapter 33 Networking the count from the server and displays a message, such as “You are visitor number 11”, as shown in Figure 33.19. Name the client Exercise33_04Client and the server Exercise33_04Server.
Figure 33.19 The client displays how many times the server has been accessed. The server stores the count.
33.5 (Send loan information in an object) Revise Exercise 33.1 for the client to send a loan object that contains annual interest rate, number of years, and loan amount and for the server to send the monthly payment and total payment.
Section 33.6
33.6 (Display and add addresses) Develop a client/server application to view and add addresses, as shown in Figure 33.20.
Figure 33.20 You can view and add an address. ■■ ■■ ■■
*33.7
*33.8
M33_LIAN0182_11_SE_C33.indd 32
Use the StudentAddress class defined in Listing 33.5 to hold the name, street, city, state, and zip in an object. The user can use the buttons First, Next, Previous, and Last to view an address, and the Add button to add a new address. Limit the concurrent connections to two clients.
Name the client Exercise33_06Client and the server Exercise33_6Server. (Transfer last 100 numbers in an array) Programming Exercise 22.12 retrieves the last 100 prime numbers from a file PrimeNumbers.dat. Write a client program that requests the server to send the last 100 prime numbers in an array. Name the server program Exercise33_07Server and the client program Exercise33_07Client. Assume the numbers of the long type are stored in PrimeNumbers.dat in binary format. (Transfer last 100 numbers in an ArrayList) Programming Exercise 24.12 retrieves the last 100 prime numbers from a file PrimeNumbers.dat. Write a client program that requests the server to send the last 100 prime numbers in an ArrayList. Name the server program Exercise33_08Server and the client program Exercise33_08Client. Assume the numbers of the long type are stored in PrimeNumbers.dat in binary format.
5/22/17 2:26 PM
Programming Exercises 33-33 Section 33.7
**33.9 (Chat) Write a program that enables two users to chat. Implement one user as the
server (see Figure 33.21a) and the other as the client (see Figure 33.21b). The server has two text areas: one for entering text, and the other (noneditable) for displaying text received from the client. When the user presses the Enter key, the current line is sent to the client. The client has two text areas: one (noneditable) for displaying text from the server and the other for entering text. When the user presses the Enter key, the current line is sent to the server. Name the client Exercise33_09Client and the server Exercise33_09Server.
(a)
(b)
Figure 33.21 The server and client send text to and receive text from each other.
***33.10 (Multiple client chat) Write a program that enables any number of clients to chat. Implement one server that serves all the clients, as shown in Figure 33.22. Name the client Exercise33_10Client and the server Exercise33_10Server.
(a)
(b)
(c)
Figure 33.22 The server starts in (a) with three clients in (b) and (c).
M33_LIAN0182_11_SE_C33.indd 33
5/22/17 2:26 PM
CHAPTER
34 Java Database Programming Objectives ■■
To understand the concepts of databases and database management systems (§34.2).
■■
To understand the relational data model: relational data structures, constraints, and languages (§34.2).
■■
To use SQL to create and drop tables and to retrieve and modify data (§34.3).
■■
To learn how to load a driver, connect to a database, execute statements, and process result sets using JDBC (§34.4).
■■
To use prepared statements to execute precompiled SQL statements (§34.5).
■■
To use callable statements to execute stored SQL procedures and functions (§34.6).
■■
To explore database metadata using the DatabaseMetaData and ResultSetMetaData interfaces (§34.7).
M34_LIAN0182_11_SE_C34.indd 1
5/23/17 5:54 PM
34-2 Chapter 34 Java Database Programming
34.1 Introduction Key Point
Java provides the API for developing database applications that works with any relational database systems. You may have heard a lot about database systems. Database systems are everywhere. Your social security information is stored in a database by the government. If you shop online, your purchase information is stored in a database by the company. If you attend a university, your academic information is stored in a database by the university. Database s ystems not only store data, they also provide means of accessing, updating, manipulating, and analyzing data. Your social security information is updated periodically, and you can register for courses online. Database systems play an important role in society and in commerce. This chapter introduces database systems, the SQL language, and how database applications can be developed using Java. If you already know SQL, you can skip Sections 34.2 and 34.3.
34.2 Relational Database Systems SQL is the standard database language for defining and accessing databases. database system
Key Point
A database system consists of a database, the software that stores and manages data in the database, and the application programs that present data and enable the user to interact with the database system, as shown in Figure 34.1.
Application Users
Application Programs System Users Database Management System (DBMS)
database
Figure 34.1 A database system consists of data, database management software, and application programs.
DBMS
M34_LIAN0182_11_SE_C34.indd 2
A database is a repository of data that form information. When you purchase a database system—such as MySQL, Oracle, IBM’s DB2 and Informix, Microsoft SQL Server, or Sybase—from a software vendor, you actually purchase the software comprising a database management system (DBMS). Database management systems are designed for use by professional programmers and are not suitable for ordinary customers. Application programs are built on top of the DBMS for customers to access and update the database. Thus, application programs can be viewed as the interfaces between the database system and its users. Application programs may be stand-alone GUI applications or Web applications and may access several different database systems in the network, as shown in Figure 34.2. Most of today’s database systems are relational database systems. They are based on the relational data model, which has three key components: structure, integrity, and language.
5/23/17 5:54 PM
34.2 Relational Database Systems 34-3 Application Users
Application Programs
Database Management System
…
Database Management System
…
…
database
Figure 34.2 An application program can access multiple database systems. Structure defines the representation of the data. Integrity imposes constraints on the data. Language provides the means for accessing and manipulating data.
34.2.1 Relational Structures The relational model is built around a simple and natural structure. A relation is actually a table that consists of nonduplicate rows. Tables are easy to understand and use. The relational model provides a simple yet powerful way to represent data. A row of a table represents a record, and a column of a table represents the value of a single attribute of the record. In relational database theory, a row is called a tuple, and a column is called an attribute. Figure 34.3 shows a sample table that stores information about the courses offered by a university. The table has eight tuples, and each tuple has five attributes.
Tuples/ Rows
tuple attribute
Columns/Attributes
Relation/Table Name
Course Table
relational model
courseId
subjectId
courseNumber
title
numOfCredits
11111 11112 11113 11114 11115 11116 11117 11118
CSCI CSCI CSCI CSCI MATH MATH EDUC ITEC
1301 1302 3720 4750 2750 3750 1111 1344
Introduction to Java I Introduction to Java II Database Systems Rapid Java Application Calculus I Calculus II Reading Database Administration
4 3 3 3 5 5 3 3
Figure 34.3 A table has a table name, column names, and rows. Tables describe the relationship among data. Each row in a table represents a record of related data. For example, “11111,” “CSCI,” “1301,” “Introduction to Java I,” and “4” are related to form a record (the first row in Figure 34.3) in the Course table. Just as the data in the same row are related, so too data in different tables may be related through common attributes. Suppose the database has two other tables, Student and Enrollment, as shown in
M34_LIAN0182_11_SE_C34.indd 3
5/23/17 5:54 PM
34-4 Chapter 34 Java Database Programming Figures 34.4 and 34.5. The Course table and the Enrollment table are related through their common attribute courseId, and the Enrollment table and the Student table are related through ssn.
Student Table ssn 444111110 444111111 444111112 444111113 444111114 444111115 444111116 444111117 444111118 444111119 444111120
firstName
mi
lastName
phone
birthDate
Jacob John George Frank Jean Josh Josh Joy Toni Patrick Rick
R K K E K R R P R R R
Smith Stevenson Smith Jones Smith Woo Smith Kennedy Peterson Stoneman Carter
9129219434 9129219434 9129213454 9125919434 9129219434 7075989434 9129219434 9129229434 9129229434 9129229434 9125919434
1985-04-09 null 1974-10-10 1970-09-09 1970-02-09 1970-02-09 1973-02-09 1974-03-19 1964-04-29 1969-04-29 1986-04-09
street 99 100 1200 100 100 555 100 103 103 101 19
zipCode deptID
Kingston Street Main Street Abercorn St. Main Street Main Street Franklin St. Main Street Bay Street Bay Street Washington St. West Ford St.
31435 31411 31419 31411 31411 31411 31411 31412 31412 31435 31411
BIOL BIOL CS BIOL CHEM CHEM BIOL CS MATH MATH BIOL
Figure 34.4 A Student table stores student information.
Enrollment Table ssn
courseId
dateRegistered
grade
444111110 444111110 444111110 444111111 444111111 444111111 444111112 444111112 444111112 444111113 444111113 444111114 444111115 444111115 444111116 444111117 444111118 444111118 444111118
11111 11112 11113 11111 11112 11113 11114 11115 11116 11111 11113 11115 11115 11116 11111 11111 11111 11112 11113
2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19 2004-03-19
A B C D F A B C D A A B F F D D A D B
Figure 34.5 An Enrollment table stores student enrollment information.
34.2.2 Integrity Constraints integrity constraint
M34_LIAN0182_11_SE_C34.indd 4
An integrity constraint imposes a condition that all the legal values in a table must satisfy. Figure 34.6 shows an example of some integrity constraints in the Subject and Course tables. In general, there are three types of constraints: domain constraints, primary key constraints, and foreign key constraints. Domain constraints and primary key constraints are known as intrarelational constraints, meaning that a constraint involves only one relation. The foreign key constraint is interrelational, meaning that a constraint involves more than one relation.
5/23/17 5:54 PM
34.2 Relational Database Systems 34-5 ssn
courseId
dateRegistered
grade
444111110 444111110 444111110 ...
11111 11112 11113
2004-03-19 2004-03-19 2004-03-19
A B C
Enrollment Table
Each value in courseId in the Enrollment table must match a value in courseId in the Course table Course Table
courseId subjectId 11111 11112 11113 ...
CSCI CSCI CSCI
courseNumber 1301 1302 3720
title
numOfCredits
Introduction to Java I Introduction to Java II Database Systems
Each row must have a value for courseId, and the value must be unique
4 3 3
Each value in the numOfCredits column must be greater than 0 and less than 5
Figure 34.6 The Enrollment table and the Course table have integrity constraints.
Domain Constraints Domain constraints specify the permissible values for an attribute. Domains can be specified using standard data types, such as integers, floating-point numbers, fixed-length strings, and variant-length strings. The standard data type specifies a broad range of values. Additional constraints can be specified to narrow the ranges. For example, you can specify that the umOfCredits attribute (in the Course table) must be greater than 0 and less than 5. If an n attribute has different values for each tuple in a relation, you can specify the attribute to be unique. You can also specify whether an attribute can be null, which is a special value in a database meaning unknown or not applicable. As shown in the Student table, birthDate may be null.
domain constraint
Primary Key Constraints A primary key is a set of attributes that uniquely identifyies the tuples in a relations. Why is it called a primary key, rather than simply key? To understand this, it is helpful to know superkeys, keys, and candidate keys. A superkey is an attribute or a set of attributes that uniquely identifies the relation. That is, no two tuples have the same values on a superkey. By definition, a relation consists of a set of distinct tuples. The set of all attributes in the relation forms a superkey. A key K is a minimal superkey, meaning that any proper subset of K is not a superkey. A relation can have several keys. In this case, each of the keys is called a candidate key. The primary key is one of the candidate keys designated by the database designer. The primary key is often used to identify tuples in a relation. As shown in Figure 34.6, courseId is the primary key in the Course table, and ssn and courseId form a primary key in the Enrollment table.
superkey
candidate key primary key
Foreign Key Constraints In a relational database, data are related. Tuples in a relation are related, and tuples in different relations are related through their common attributes. Informally speaking, the common attributes are foreign keys. The foreign key constraints define the relationships among relations. Formally, a set of attributes FK is a foreign key in a relation R that references relation T if it satisfies the following two rules: ■■
The attributes in FK have the same domain as the primary key in T.
■■
A nonnull value on FK in R must match a primary key value in T.
M34_LIAN0182_11_SE_C34.indd 5
relational database foreign key constraint foreign key
5/23/17 5:54 PM
34-6 Chapter 34 Java Database Programming As shown in Figure 34.6, courseId is the foreign key in Enrollment that references the primary key courseId in Course. Every courseId value must match a courseId value in Course.
Enforcing Integrity Constraints The database management system enforces integrity constraints and rejects operations that would violate them. For example, if you attempt to insert the new record (“11115,” “CSCI,” “2490,” “C + + Programming,” “0”) into the Course table, it would fail because the credit hours must be greater than 0; if you attempted to insert a record with the same primary key as an existing record in the table, the DBMS would report an error and reject the operation; if you attempted to delete a record from the Course table whose primary key value is referenced by the records in the Enrollment table, the DBMS would reject this operation.
auto enforcement
Note All relational database systems support primary key constraints and foreign key c onstraints, but not all database systems support domain constraints. In the Microsoft Access database, for example, you cannot specify the constraint that numOfCredits is greater than 0 and less than 5. Check Point
4.2.1 3 34.2.2 34.2.3 34.2.4 34.2.5 34.2.6
What are superkeys, candidate keys, and primary keys? What is a foreign key? Can a relation have more than one primary key or foreign key? Does a foreign key need to be a primary key in the same relation? Does a foreign key need to have the same name as its referenced primary key? Can a foreign key value be null?
34.3 SQL Key Point SQL database language
Structured Query Language (SQL) is the language for defining tables and integrity constraints, and for accessing and manipulating data. SQL (pronounced “S-Q-L” or “sequel”) is the universal language for accessing relational database systems. Application programs may allow users to access a database without directly using SQL, but these applications themselves must use SQL to access the database. This section introduces some basic SQL commands.
Note There are many relational database management systems. They share the common SQL language but do not all support every feature of SQL. Some systems have their own extensions to SQL. This section introduces standard SQL supported by all systems.
standard SQL
SQL can be used on MySQL, Oracle, Sybase, IBM DB2, IBM Informix, MS Access, Apache Derby, or any other relational database system. Apache Derby is an open source relational database management system developed using Java. Oracle distributes Apache Derby as Java DB and bundled with Java so you can use it in any Java application without installing a database. Java DB is ideal for supporting a small database in a Java application. This chapter uses MySQL to demonstrate SQL and Java database programming. The Companion Website contains the following supplements on how to install and use three popular databases: MySQL, Oracle, and Java DB: MySQL Tutorial
■■
Supplement IV.B: Tutorial for MySQL
Oracle Tutorial
■■
Supplement IV.C: Tutorial for Oracle
Java DB Tutorial
■■
Supplement IV.D: Tutorial for Java DB
M34_LIAN0182_11_SE_C34.indd 6
5/23/17 5:54 PM
34.3 SQL 34-7
34.3.1 Creating a User Account on MySQL Assume you have installed MySQL 5 with the default configuration. To match all the examples in this book, you should create a user named scott with the password tiger. You can perform the administrative tasks using the MySQL Workbench or using the command line. MySQL Workbench is a GUI tool for managing MySQL databases. Here are the steps to create a user from the command line: 1. From the DOS command prompt, type mysql –uroot -p
You will be prompted to enter the root password, as shown in Figure 34.7. 2. At the mysql prompt, enter use mysql;
3. To create user scott with password tiger, enter create user 'scott'@'localhost' identified by 'tiger';
4. To grant privileges to scott, enter grant select, insert, update, delete, create, create view, drop, execute, references on *.* to 'scott'@'localhost'; ■■
If you want to enable remote access of the account from any IP address, enter grant all privileges on *.* to 'scott'@'%' identified by 'tiger';
■■
If you want to restrict the account’s remote access to just one particular IP address, enter grant all privileges on *.* to 'scott'@'ipAddress' identified by 'tiger';
5. Enter exit;
to exit the MySQL console.
Figure 34.7 You can access a MySQL database server from the command window.
M34_LIAN0182_11_SE_C34.indd 7
5/23/17 5:54 PM
34-8 Chapter 34 Java Database Programming Note On Windows, your MySQL database server starts every time your computer starts. You can stop it by typing the command net stop mysql and restart it by typing the command net start mysql.
stop mysql start mysql
By default, the server contains two databases named mysql and test. The mysql database contains the tables that store information about the server and its users. This database is intended for the server administrator to use. For example, the administrator can use it to create users and grant or revoke user privileges. Since you are the owner of the server installed on your system, you have full access to the mysql database. However, you should not create user tables in the mysql database. You can use the test database to store data or create new databases. You can also create a new database using the command create database d atabasename or delete an existing database using the command drop database databasename.
34.3.2 Creating a Database To match the examples in this book, you should create a database named javabook. Here are the steps to create it: 1. From the DOS command prompt, type mysql –uscott -ptiger
to login to mysql, as shown in Figure 34.8. 2. At the mysql prompt, enter create database javabook;
Figure 34.8 You can create databases in MySQL.
For your convenience, the SQL statements for creating and initializing tables used in this book are provided in Supplement IV.A. You can download the script for MySQL and save it to script.sql. To execute the script, first switch to the javabook database using the following command: use javabook;
then type run script file
source script.sql;
as shown in Figure 34.9.
M34_LIAN0182_11_SE_C34.indd 8
5/23/17 5:54 PM
34.3 SQL 34-9
Figure 34.9 You can run SQL commands in a script file.
Note You can populate the javabook database using the script from Supplement IV.A.
populating database
34.3.3 Creating and Dropping Tables Tables are the essential objects in a database. To create a table, use the create table statement to specify a table name, attributes, and types, as in the following example:
create table
create table Course ( courseId char(5), subjectId char(4) not null, courseNumber integer, title varchar(50) not null, numOfCredits integer, primary key (courseId) );
This statement creates the Course table with attributes courseId , subjectId , ourseNumber, title, and numOfCredits. Each attribute has a data type that specifies the c type of data stored in the attribute. char(5) specifies that courseId consists of five characters. varchar(50) specifies that title is a variant-length string with a maximum of 50 characters. integer specifies that courseNumber is an integer. The primary key is courseId. The tables Student and Enrollment can be created as follows: create table Student ( ssn char(9), firstName varchar(25), mi char(1), lastName varchar(25), birthDate date, street varchar(25), phone char(11), zipCode char(5), deptId char(4), primary key (ssn) );
create table Enrollment ( ssn char(9), courseId char(5), dateRegistered date, grade char(1), primary key (ssn, courseId), foreign key (ssn) references Student(ssn), foreign key (courseId) references Course(courseId) );
Note SQL keywords are not case sensitive. This book adopts the following naming conventions: tables are named in the same way as Java classes, and attributes are named in the same way as Java variables. SQL keywords are named in the same way as Java keywords.
M34_LIAN0182_11_SE_C34.indd 9
naming convention
5/23/17 5:54 PM
34-10 Chapter 34 Java Database Programming drop table
If a table is no longer needed, it can be dropped permanently using the drop table command. For example, the following statement drops the Course table: drop table Course;
If a table to be dropped is referenced by other tables, you have to drop the other tables first. For example, if you have created the tables Course, Student, and Enrollment and want to drop Course, you have to first drop Enrollment, because Course is referenced by Enrollment. Figure 34.10 shows how to enter the create table statement from the MySQL console.
Figure 34.10 A table is created using the create table statement.
If you make typing errors, you have to retype the whole command. To avoid retyping, you can save the command in a file, then run the command from the file. To do so, create a text file to contain commands, named, for example, test.sql. You can create the text file using any text editor, such as Notepad, as shown in Figure 34.11a. To comment a line, precede it with two dashes. You can now run the script file by typing source test.sql from the SQL command prompt, as shown in Figure 34.11b.
(a)
(b)
Figure 34.11 (a) You can use Notepad to create a text file for SQL commands. (b) You can run the SQL commands in a script file from MySQL.
34.3.4 Simple Insert, Update, and Delete Once a table is created, you can insert data into it. You can also update and delete records. This section introduces simple insert, update, and delete statements. The syntax to insert a record into a table is: insert into tableName [(column1, column2, ..., column)] values (value1, value2, ..., valuen);
M34_LIAN0182_11_SE_C34.indd 10
5/23/17 5:54 PM
34.3 SQL 34-11 For example, the following statement inserts a record into the Course table. The new record has the courseId ‘11113’, subjectId ‘CSCI’, courseNumber ‘3720’, title ‘Database Systems’, and creditHours 3. insert into Course (courseId, subjectId, courseNumber, title, numOfCredits) values ('11113', 'CSCI', '3720', 'Database Systems', 3);
The column names are optional. If they are omitted, all the column values for the record must be entered, even though the columns have default values. String values are case sensitive and enclosed inside single quotation marks in SQL. The syntax to update a table is: update tableName set column1 = newValue1 [, column2 = newValue2, ...] [where condition];
For example, the following statement changes the numOfCredits for the course whose title is Database Systems to 4. update Course set numOfCredits = 4 where title = 'Database Systems';
The syntax to delete records from a table is: delete from tableName [where condition];
For example, the following statement deletes the Database Systems course from the Course table: delete from Course where title = 'Database Systems';
The following statement deletes all the records from the Course table: delete from Course;
34.3.5 Simple Queries To retrieve information from tables, use a select statement with the following syntax: select column-list from table-list [where condition];
The select clause lists the columns to be selected. The from clause refers to the tables involved in the query. The optional where clause specifies the conditions for the selected rows. Query 1: Select all the students in the CS department, as shown in Figure 34.12. select firstName, mi, lastName from Student where deptId = 'CS';
M34_LIAN0182_11_SE_C34.indd 11
5/23/17 5:54 PM
34-12 Chapter 34 Java Database Programming
Figure 34.12 The result of the select statement is displayed in the MySQL console.
34.3.6 Comparison and Boolean Operators SQL has six comparison operators, as shown in Table 34.1, and three Boolean operators, as shown in Table 34.2.
Table 34.1 Comparison Operators
Table 34.2 Boolean Operators
Operator
Description
Operator
Description
=
Equal to
not
Logical negation
or !=
Not equal to
and
Logical conjunction
=
Greater than or equal to
Note The comparison and Boolean operators in SQL have the same meanings as in Java. In SQL the equal to operator is =, but in Java it is ==. In SQL the not equal to operator is or !=, but in Java it is !=. The not, and, and or operators are !, && (&), and || (|) in Java.
Query 2: Get the names of the students who are in the CS dept and live in the ZIP code 31411. select firstName, mi, lastName from Student where deptId = 'CS' and zipCode = '31411';
Note To select all the attributes from a table, you don’t have to list all the attribute names in the select clause. Instead, you can just use an asterisk (*), which stands for all the attributes. For example, the following query displays all the attributes of the students who are in the CS dept and live in ZIP code 31411. select * from Student where deptId = 'CS' and zipCode = '31411';
M34_LIAN0182_11_SE_C34.indd 12
5/23/17 5:54 PM
34.3 SQL 34-13
34.3.7 The like, between-and, and is null Operators SQL has a like operator that can be used for pattern matching. The syntax to check whether a string s has a pattern p is s like p or s not like p
You can use the wildcard characters % (percent symbol) and _ (underline symbol) in the pattern p. % matches zero or more characters, and _ matches any single character in s. For example, lastName like '_mi%' matches any string whose second and third letters are m and i. lastName not like '_mi%' excludes any string whose second and third letters are m and i.
Note In earlier versions of MS Access, the wildcard character is *, and the character ? matches any single character.
The between-and operator checks whether a value v is between two other values, v1 and v2, using the following syntax: v between v1 and v2 or v not between v1 and v2 v between v1 and v2 is equivalent to v >= v1 and v v2.
The is null operator checks whether a value v is null using the following syntax: v is null or v is not null
Query 3: Get the Social Security numbers of the students whose grades are between ‘C’ and ‘A’. select ssn from Enrollment where grade between 'C' and 'A';
34.3.8 Column Alias When a query result is displayed, SQL uses the column names as column headings. Usually the user gives abbreviated names for the columns, and the columns cannot have spaces when the table is created. Sometimes it is desirable to give more descriptive names in the result heading. You can use the column aliases with the following syntax: select columnName [as] alias
Query 4: Get the last name and ZIP code of the students in the CS department. Display the column headings as “Last Name” for lastName and “Zip Code” for zipCode. The query result is shown in Figure 34.13.
Figure 34.13 You can use a column alias in the display.
M34_LIAN0182_11_SE_C34.indd 13
5/23/17 5:54 PM
34-14 Chapter 34 Java Database Programming select lastName as "Last Name", zipCode as "Zip Code" from Student where deptId = 'CS';
Note The as keyword is optional in MySQL and Oracle, but it is required in MS Access.
34.3.9 The Arithmetic Operators You can use the arithmetic operators * (multiplication), / (division), + (addition), and − (subtraction) in SQL. Query 5: Assume a credit hour is 50 minutes of lectures and get the total minutes for each course with the subject CSCI. The query result is shown in Figure 34.14. select title, 50 * numOfCredits as "Lecture Minutes Per Week" from Course where subjectId = 'CSCI';
Figure 34.14 You can use arithmetic operators in SQL.
34.3.10 Displaying Distinct Tuples SQL provides the distinct keyword, which can be used to eliminate duplicate tuples in the result. Figure 34.15a displays all the subject IDs used by the courses, and Figure 34.15b displays all the distinct subject IDs used by the courses using the following statement: select distinct subjectId as "Subject ID" from Course;
(a)
(b)
Figure 34.15 (a) The duplicate tuples are displayed. (b) The distinct tuples are displayed.
M34_LIAN0182_11_SE_C34.indd 14
5/23/17 5:54 PM
34.3 SQL 34-15 When there is more than one column in the select clause, the distinct keyword applies to the whole tuple in the result. For example, the following statement displays all tuples with distinct subjectId and title, as shown in Figure 34.16. Note some tuples may have the same subjectId but different title. These tuples are distinct. select distinct subjectId, title from Course;
Figure 34.16 The keyword distinct applies to the entire tuple.
34.3.11 Displaying Sorted Tuples SQL provides the order by clause to sort the output using the following syntax: select column-list from table-list [where condition] [order by columns-to-be-sorted];
In the syntax, columns-to-be-sorted specifies a column or a list of columns to be sorted. By default, the order is ascending. To sort in a descending order, append the desc keyword. You could also append the asc keyword after columns-to-be-sorted, but it is not necessary. When multiple columns are specified, the rows are sorted based on the first column, then the rows with the same values on the first column are sorted based on the second column, and so on. Query 6: List the full names of the students in the CS department, ordered primarily on their last names in descending order and secondarily on their first names in ascending order. The query result is shown in Figure 34.17.
Figure 34.17 You can sort results using the order by clause.
M34_LIAN0182_11_SE_C34.indd 15
5/23/17 5:54 PM
34-16 Chapter 34 Java Database Programming select lastName, firstName, deptId from Student where deptId = 'CS' order by lastName desc, firstName asc;
34.3.12 Joining Tables Often you need to get information from multiple tables, as demonstrated in the next query. Query 7: List the courses taken by the student Jacob Smith. To solve this query, you need to join tables Student and Enrollment, as shown in Figure 34.18.
Enrollment Table
Student Table ssn
lastName
mi
firstName …
ssn
courseId …
A tuple
Equal
Figure 34.18 Student and Enrollment are joined on ssn. You can write the query in SQL as follows: select distinct lastName, firstName, courseId from Student, Enrollment where Student.ssn = Enrollment.ssn and lastName = 'Smith' and firstName = 'Jacob';
The tables Student and Enrollment are listed in the from clause. The query examines every pair of rows, each made of one item from Student and another from Enrollment and selects the pairs that satisfy the condition in the where clause. The rows in Student have the last name, Smith, and the first name, Jacob, and both rows from Student and Enrollment have the same ssn values. For each pair selected, lastName and firstName from Student and courseId from Enrollment are used to produce the result, as shown in Figure 34.19. Student and Enrollment have the same attribute ssn. To distinguish them in a query, use Student.ssn and Enrollment.ssn.
Figure 34.19 Query 7 demonstrates queries involving multiple tables.
M34_LIAN0182_11_SE_C34.indd 16
5/23/17 5:54 PM
34.4 JDBC 34-17 For more features of SQL, see Supplements IV.H and IV.I.
34.3.1 Create the tables Course, Student, and Enrollment using the create 4.3.2 3 34.3.3 34.3.4 34.3.5 34.3.6 34.3.7
table
statements in Section 34.3.3, Creating and Dropping Tables. Insert rows into the Course, Student, and Enrollment tables using the data in Figures 34.3–34.5. List all CSCI courses with at least four credit hours. List all students whose last names contain the letter e two times. List all students whose birthdays are null. List all students who take Math courses. List the number of courses in each subject. Assume each credit hour is 50 minutes of lectures. Get the total minutes for the courses that each student takes.
Check Point
34.4 JDBC JDBC is the Java API for accessing relational database. The Java API for developing Java database applications is called JDBC. JDBC is the trademarked name of a Java API that supports Java programs that access relational databases. JDBC is not an acronym, but it is often thought to stand for Java Database Connectivity. JDBC provides Java programmers with a uniform interface for accessing and manipulating relational databases. Using the JDBC API, applications written in the Java programming language can execute SQL statements, retrieve results, present data in a user-friendly interface, and propagate changes back to the database. The JDBC API can also be used to interact with multiple data sources in a distributed, heterogeneous environment. The relationships among Java programs, JDBC API, JDBC drivers, and relational databases are shown in Figure 34.20. The JDBC API is a set of Java interfaces and classes used to write Java programs for accessing and manipulating relational databases. Since a JDBC driver serves as the interface to facilitate communications between JDBC and a proprietary database, JDBC drivers are database specific and are normally provided by the database vendors. You need
Key Point
Java Programs
JDBC API
MySQL JDBC Driver
Oracle JDBC Driver
DB2 JDBC Driver
Local or remote MySQL DB
Local or remote ORACLE DB
Local or remote DB2 DB
Figure 34.20 Java programs access and manipulate databases through JDBC drivers.
M34_LIAN0182_11_SE_C34.indd 17
5/23/17 5:54 PM
34-18 Chapter 34 Java Database Programming MySQL JDBC drivers to access the MySQL database, Oracle JDBC drivers to access the Oracle database, and DB2 JDBC driver to access the DB2 database.
34.4.1 Developing Database Applications Using JDBC The JDBC API is a Java application program interface to generic SQL databases that enables Java developers to develop DBMS-independent Java applications using a uniform interface. The JDBC API consists of classes and interfaces for establishing connections with databases, sending SQL statements to databases, processing the results of SQL statements, and obtaining database metadata. Four key interfaces are needed to develop any database application using Java: Driver, Connection, Statement, and ResultSet. These interfaces define a framework for generic SQL database access. The JDBC API defines these interfaces, and the JDBC driver vendors provide the implementation for the interfaces. Programmers use these interfaces. The relationship of these interfaces is shown in Figure 34.21. A JDBC application loads an appropriate driver using the Driver interface, connects to the database using the Connection interface, creates and executes SQL statements using the Statement interface, and processes the result using the ResultSet interface if the statements return results. Note some statements, such as SQL data definition statements and SQL data modification statements, do not return results.
Driver
Connection
Connection
Statement
Statement
Statement
Statement
ResultSet
ResultSet
ResultSet
ResultSet
Figure 34.21 JDBC classes enable Java programs to connect to the database, send SQL statements, and process results. The JDBC interfaces and classes are the building blocks in the development of Java database programs. A typical Java program takes the following steps to access a database. 1. Loading drivers. An appropriate driver must be loaded using the statement shown below before connecting to a database. Class.forName("JDBCDriverClass");
A driver is a concrete class that implements the java.sql.Driver interface. The drivers for MySQL, Oracle, and Java DB are listed in Table 34.3. If your program accesses several different databases, all their respective drivers must be loaded. The most recent platform independent version of MySQL JDBC driver is mysql-connectormysql-connector-java-5.1.26.jar java-5.1.26.jar. This file is contained in a ZIP file downloadable from dev.mysql.com/downojdbc6.jar loads/connector/j/. The most recent version of Oracle JDBC driver is ojdbc6.jar (downloadable from www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html).
M34_LIAN0182_11_SE_C34.indd 18
5/23/17 5:54 PM
34.4 JDBC 34-19 Table 34.3 JDBC Drivers Database
Driver Class
Source
MySQL
com.mysql.jdbc.Driver
mysql-connector-java-5.1.26.jar
Oracle
oracle.jdbc.driver.OracleDriver
ojdbc6.jar
Java DB (embedded)
org.apache.derby.jdbc.EmbeddedDriver
derby.jar
Java DB (network)
org.apache.derby.jdbc.ClientDriver
derbynet.jar
Java DB has two versions: embedded and networked. Embedded version is used when you access Java DB locally, while the network version enables you to access Java DB on the network. To use these drivers, you have to add their jar files in the classpath using the following DOS command on Windows: set classpath=%classpath%;c:\book\lib\mysql-connector-java-5.1.26. jar;c:\book\lib\ojdbc6.jar;c:\program files\jdk1.8.0\db\lib\derby. jar
If you use an IDE such as Eclipse or NetBeans, you need to add these jar files into the library in the IDE.
Note com.mysql.jdbc.Driver is a class in mysql-connector-java-5.1.26.jar, and oracle.jdbc.driver.OracleDriver is a class in ojdbc6.jar. mysqlconnector-java-5.1.26.jar, ojdbc6.jar, and derby.jar contains many classes to support the driver. These classes are used by JDBC but not directly by JDBC programmers. When you use a class explicitly in the program, it is automatically loaded by the JVM. The driver classes, however, are not used explicitly in the program, so you have to write the code to tell the JVM to load them.
why load a driver?
Note Java supports automatic driver discovery, so you don’t have to load the driver explicitly. At the time of this writing, however, this feature is not supported for all database drivers. To be safe, load the driver explicitly.
automatic driver discovery
2. Establishing connections. To connect to a database, use the static method getConnection(databaseURL) in the DriverManager class, as follows: Connection connection = DriverManager.getConnection(databaseURL);
where databaseURL is the unique identifier of the database on the Internet. Table 34.4 lists the URL patterns for the MySQL, Oracle, and Java DB.
Table 34.4 JDBC URLs Database
URL Pattern
MySQL
jdbc:mysql://hostname/dbname
Oracle
jdbc:oracle:thin:@hostname:port#:oracleDBSID
Java DB (embedded)
jdbc:derby:dbname
Java DB (network)
jdbc:derby://hostname/dbname
M34_LIAN0182_11_SE_C34.indd 19
5/23/17 5:54 PM
34-20 Chapter 34 Java Database Programming
connect MySQL DB
The databaseURL for a MySQL database specifies the host name and database name to locate a database. For example, the following statement creates a Connection object for the local MySQL database javabook with username scott and password tiger: Connection connection = DriverManager.getConnection ("jdbc:mysql://localhost/javabook", "scott", "tiger");
connect Oracle DB
Recall that by default, MySQL contains two databases named mysql and test. Section 34.3.2, Creating a Database, created a custom database named javabook. We will use javabook in the examples. The databaseURL for an Oracle database specifies the hostname, the port# where the database listens for incoming connection requests, and the oracleDBSID database name to locate a database. For example, the following statement creates a Connection object for the Oracle database on liang.armstrong.edu with the username scott and password tiger: Connection connection = DriverManager.getConnection ("jdbc:oracle:thin:@liang.armstrong.edu:1521:orcl", "scott", "tiger");
3. Creating statements. If a Connection object can be envisioned as a cable linking your program to a database, an object of Statement can be viewed as a cart that delivers SQL statements for execution by the database and brings the result back to the program. Once a Connection object is created, you can create statements for executing SQL statements as follows: Statement statement = connection.createStatement();
4. Executing statements. SQL data definition language (DDL) and update statements can be executed using executeUpdate(String sql) , and an SQL query statement can be executed using executeQuery(String sql). The result of the query is returned in ResultSet. For example, the following code executes the SQL statement create table Temp (col1 char(5), col2 char(5)): statement.executeUpdate ("create table Temp (col1 char(5), col2 char(5))");
This next code executes the SQL query select firstName, mi, lastName from Student where lastName = 'Smith': // Select the columns from the Student table ResultSet resultSet = statement.executeQuery ("select firstName, mi, lastName from Student where lastName " + " = 'Smith'");
5. Processing ResultSet. The ResultSet maintains a table whose current row can be retrieved. The initial row position is null. You can use the next method to move to the next row and the various getter methods to retrieve values from a current row. For example, the following code displays all the results from the preceding SQL query: // Iterate through the result and print the student names while (resultSet.next()) System.out.println(resultSet.getString(1) + " " + resultSet.getString(2) + " " + resultSet.getString(3));
M34_LIAN0182_11_SE_C34.indd 20
5/23/17 5:54 PM
34.4 JDBC 34-21 The getString(1) , getString(2) , and getString(3) methods retrieve the c olumn values for firstName, mi, and lastName, respectively. Alternatively, you can use getString("firstName"), getString("mi"), and getString("lastName") to retrieve the same three column values. The first execution of the next() method sets the current row to the first row in the result set, and subsequent invocations of the next() method set the current row to the second row, third row, and so on, to the last row. Listing 34.1 is a complete example that demonstrates connecting to a database, executing a simple query, and processing the query result with JDBC. The program connects to a local MySQL database and displays the students whose last name is Smith.
Listing 34.1 SimpleJdbc.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
import java.sql.*; public class SimpleJdbc { public static void main(String[] args) throws SQLException, ClassNotFoundException { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); System.out.println("Driver loaded"); // Connect to a database Connection connection = DriverManager.getConnection ("jdbc:mysql://localhost/javabook", "scott", "tiger"); System.out.println("Database connected"); // Create a statement Statement statement = connection.createStatement(); // Execute a statement ResultSet resultSet = statement.executeQuery ("select firstName, mi, lastName from Student where lastName " + " = 'Smith'"); // Iterate through the result and print the student names while (resultSet.next()) System.out.println(resultSet.getString(1) + "\t" + resultSet.getString(2) + "\t" + resultSet.getString(3)); // Close the connection connection.close();
load driver
connect database
create statement
execute statement
get result
close connection
} }
The statement in line 7 loads a JDBC driver for MySQL, and the statement in lines 11–13 connects to a local MySQL database. You can change them to connect to an Oracle or other databases. The program creates a Statement object (line 16), executes an SQL statement and returns a ResultSet object (lines 19–21), and retrieves the query result from the ResultSet object (lines 24–26). The last statement (line 29) closes the connection and releases resources related to the connection. You can rewrite this program using the try-with-resources syntax. See www.cs.armstrong.edu/liang/intro11e/html/SimpleJdbcWithAutoClose.html.
Note If you run this program from the DOS prompt, specify the appropriate driver in the classpath, as shown in Figure 34.22.
M34_LIAN0182_11_SE_C34.indd 21
run from DOS prompt
5/23/17 5:54 PM
34-22 Chapter 34 Java Database Programming
Figure 34.22 You must include the driver file to run Java database programs. The classpath directory and jar files are separated by commas. The period (.) represents the current directory. For convenience, the driver files are placed under the lib directory.
Caution Do not use a semicolon (;) to end the Oracle SQL command in a Java program. The semicolon may not work with the Oracle JDBC drivers. It does work, however, with the other drivers used in this book.
the semicolon issue
Note The Connection interface handles transactions and specifies how they are processed. By default, a new connection is in autocommit mode, and all its SQL statements are executed and committed as individual transactions. The commit occurs when the statement completes or the next execute occurs, whichever comes first. In the case of statements returning a result set, the statement completes when the last row of the result set has been retrieved or the result set has been closed. If a single statement returns multiple results, the commit occurs when all the results have been retrieved. You can use the setAutoCommit(false) method to disable autocommit, so all SQL statements are grouped into one transaction that is terminated by a call to either the commit() or the rollback() method. The rollback() method undoes all the changes made by the transaction.
autocommit
34.4.2 Accessing a Database from JavaFX This section gives an example that demonstrates connecting to a database from a JavaFX program. The program lets the user enter the SSN and the course ID to find a student’s grade, as shown in Figure 34.23. The code in Listing 34.2 uses the MySQL database on the localhost.
Figure 34.23 A JavaFX client can access the database on the server.
Listing 34.2 FindGrade.java 1 2 3 4 5 6 7 8 9
M34_LIAN0182_11_SE_C34.indd 22
import import import import import import import import import
javafx.application.Application; javafx.scene.Scene; javafx.scene.control.Button; javafx.scene.control.Label; javafx.scene.control.TextField; javafx.scene.layout.HBox; javafx.scene.layout.VBox; javafx.stage.Stage; java.sql.*;
5/23/17 5:54 PM
34.4 JDBC 34-23 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
public class FindGrade extends Application { // Statement for executing queries private Statement stmt; private TextField tfSSN = new TextField(); private TextField tfCourseId = new TextField(); private Label lblStatus = new Label(); @Override // Override the start method in the Application class public void start(Stage primaryStage) { // Initialize database connection and create a Statement object initializeDB(); Button btShowGrade = new Button("Show Grade"); HBox hBox = new HBox(5); hBox.getChildren().addAll(new Label("SSN"), tfSSN, new Label("Course ID"), tfCourseId, (btShowGrade)); VBox vBox = new VBox(10); vBox.getChildren().addAll(hBox, lblStatus); tfSSN.setPrefColumnCount(6); tfCourseId.setPrefColumnCount(6); btShowGrade.setOnAction(e -> showGrade());
button listener
// Create a scene and place it in the stage Scene scene = new Scene(vBox, 420, 80); primaryStage.setTitle("FindGrade"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage } private void initializeDB() { try { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); // Class.forName("oracle.jdbc.driver.OracleDriver"); System.out.println("Driver loaded"); // Establish a connection Connection connection = DriverManager.getConnection ("jdbc:mysql://localhost/javabook", "scott", "tiger"); ("jdbc:oracle:thin:@liang.armstrong.edu:1521:orcl", "scott", "tiger"); System.out.println("Database connected");
// //
// Create a statement stmt = connection.createStatement();
load driver Oracle driver commented
connect to MySQL database connect to Oracle commented
execute statement
} catch (Exception ex) { ex.printStackTrace(); } } private void showGrade() { String ssn = tfSSN.getText(); String courseId = tfCourseId.getText(); try { String queryString = "select firstName, mi, " + "lastName, title, grade from Student, Enrollment, Course " +
M34_LIAN0182_11_SE_C34.indd 23
show result
create statement
5/23/17 5:54 PM
34-24 Chapter 34 Java Database Programming 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
"where Student.ssn = '" + ssn + "' and Enrollment.courseId " + "= '" + courseId + "' and Enrollment.courseId = Course.courseId " + " and Enrollment.ssn = Student.ssn"; ResultSet rset = stmt.executeQuery(queryString); if (rset.next()) { String lastName = rset.getString(1); String mi = rset.getString(2); String firstName = rset.getString(3); String title = rset.getString(4); String grade = rset.getString(5); // Display result in a label lblStatus.setText(firstName + " " + mi + " " + lastName + "'s grade on course " + title + " is " + grade); } else { lblStatus.setText("Not found"); } } catch (SQLException ex) { ex.printStackTrace(); } } }
The initializeDB() method (lines 42–62) loads the MySQL driver (line 45), connects to the MySQL database on host liang.armstrong.edu (lines 50–55), and creates a statement (line 57).
Note There is a security hole in this program. If you enter 1' or true or '1 in the SSN field, you will get the first student’s score, because the query string now becomes
security hole
select firstName, mi, lastName, title, grade from Student, Enrollment, Course where Student.ssn = '1' or true or '1' and Enrollment.courseId = ' ' and Enrollment.courseId = Course.courseId and Enrollment.ssn = Student.ssn;
You can avoid this problem by using the PreparedStatement interface, which will be discussed in the next section. Check Point
4.4.1 What are the advantages of developing database applications using Java? 3 34.4.2 Describe the following JDBC interfaces: Driver, Connection, Statement, and ResultSet.
34.4.3 How do you load a JDBC driver? What are the driver classes for MySQL, Oracle, 34.4.4 4.4.5 3 34.4.6 34.4.7
M34_LIAN0182_11_SE_C34.indd 24
and Java DB? How do you create a database connection? What are the URLs for MySQL, Oracle, and Java DB? How do you create a Statement and execute an SQL statement? How do you retrieve values in a ResultSet? Does JDBC automatically commit a transaction? How do you set autocommit to false?
5/23/17 5:54 PM
34.5 PreparedStatement 34-25
34.5 PreparedStatement PreparedStatement enables you to create parameterized SQL statements.
Key Point
Once a connection to a particular database is established, it can be used to send SQL statements from your program to the database. The Statement interface is used to execute static SQL statements that don’t contain any parameters. The PreparedStatement interface, extending Statement, is used to execute a precompiled SQL statement with or without parameters. Since the SQL statements are precompiled, they are efficient for repeated executions. A PreparedStatement object is created using the prepareStatement method in the Connection interface. For example, the following code creates a PreparedStatement for an SQL insert statement: PreparedStatement preparedStatement = connection.prepareStatement ("insert into Student (firstName, mi, lastName) " + "values (?, ?, ?)");
This insert statement has three question marks as placeholders for parameters representing values for firstName, mi, and lastName in a record of the Student table. As a subinterface of Statement, the PreparedStatement interface inherits all the methods defined in Statement. It also provides the methods for setting parameters in the object of PreparedStatement. These methods are used to set the values for the parameters before executing statements or procedures. In general, the setter methods have the following name and signature: setX(int parameterIndex, X value);
where X is the type of the parameter, and parameterIndex is the index of the parameter in the statement. The index starts from 1 . For example, the method setString(int parameterIndex, String value) sets a String value to the specified parameter. The following statements pass the parameters "Jack", "A", and "Ryan" to the placeholders for firstName, mi, and lastName in preparedStatement: preparedStatement.setString(1, "Jack"); preparedStatement.setString(2, "A"); preparedStatement.setString(3, "Ryan");
After setting the parameters, you can execute the prepared statement by invoking executeQuery() for a SELECT statement and executeUpdate() for a DDL or update statement. The executeQuery() and executeUpdate() methods are similar to the ones defined in the Statement interface except that they don’t have any parameters, because the SQL statements are already specified in the prepareStatement method when the object of PreparedStatement is created. Using a prepared SQL statement, Listing 34.2 can be improved as in Listing 34.3.
Listing 34.3 FindGradeUsingPreparedStatement.java 1 2 3 4 5 6 7 8 9 10
import import import import import import import import import
M34_LIAN0182_11_SE_C34.indd 25
javafx.application.Application; javafx.scene.Scene; javafx.scene.control.Button; javafx.scene.control.Label; javafx.scene.control.TextField; javafx.scene.layout.HBox; javafx.scene.layout.VBox; javafx.stage.Stage; java.sql.*;
5/23/17 5:54 PM
34-26 Chapter 34 Java Database Programming
prepare statement
load driver
connect database
placeholder
M34_LIAN0182_11_SE_C34.indd 26
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
public class FindGradeUsingPreparedStatement extends Application { // PreparedStatement for executing queries private PreparedStatement preparedStatement; private TextField tfSSN = new TextField(); private TextField tfCourseId = new TextField(); private Label lblStatus = new Label(); @Override // Override the start method in the Application class public void start(Stage primaryStage) { // Initialize database connection and create a Statement object initializeDB(); Button btShowGrade = new Button("Show Grade"); HBox hBox = new HBox(5); hBox.getChildren().addAll(new Label("SSN"), tfSSN, new Label("Course ID"), tfCourseId, (btShowGrade)); VBox vBox = new VBox(10); vBox.getChildren().addAll(hBox, lblStatus); tfSSN.setPrefColumnCount(6); tfCourseId.setPrefColumnCount(6); btShowGrade.setOnAction(e -> showGrade()); // Create a scene and place it in the stage Scene scene = new Scene(vBox, 420, 80); primaryStage.setTitle("FindGrade"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage } private void initializeDB() { try { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); // Class.forName("oracle.jdbc.driver.OracleDriver"); System.out.println("Driver loaded"); // Establish a connection Connection connection = DriverManager.getConnection ("jdbc:mysql://localhost/javabook", "scott", "tiger"); ("jdbc:oracle:thin:@liang.armstrong.edu:1521:orcl", "scott", "tiger"); System.out.println("Database connected");
// //
String queryString = "select firstName, mi, " + "lastName, title, grade from Student, Enrollment, Course " + "where Student.ssn = ? and Enrollment.courseId = ? " + "and Enrollment.courseId = Course.courseId"; // Create a statement preparedStatement = connection.prepareStatement(queryString); } catch (Exception ex) { ex.printStackTrace(); } } private void showGrade() { String ssn = tfSSN.getText();
5/23/17 5:54 PM
34.6 CallableStatement 34-27 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
String courseId = tfCourseId.getText(); try { preparedStatement.setString(1, ssn); preparedStatement.setString(2, courseId); ResultSet rset = preparedStatement.executeQuery();
execute statement
if (rset.next()) { String lastName = rset.getString(1); String mi = rset.getString(2); String firstName = rset.getString(3); String title = rset.getString(4); String grade = rset.getString(5); // Display result in a label lblStatus.setText(firstName + " " + mi + " " + lastName + "'s grade on course " + title + " is " + grade); } else { lblStatus.setText("Not found"); }
show result
} catch (SQLException ex) { ex.printStackTrace(); } } }
This example does exactly the same thing as Listing 34.2 except that it uses the prepared statement to dynamically set the parameters. The code in this example is almost the same as in the preceding example. The new code is highlighted. A prepared query string is defined in lines 56–59 with ssn and courseId as parameters. An SQL prepared statement is obtained in line 62. Before executing the query, the actual values of ssn and courseId are set to the parameters in lines 73–74. Line 75 executes the prepared statement.
34.5.1 Describe prepared statements. How do you create instances of Prepared
Statement? How do you execute a PreparedStatement? How do you set parameter values in a PreparedStatement?
Check Point
34.5.2 What are the benefits of using prepared statements?
34.6 CallableStatement CallableStatement enables you to execute SQL stored procedures.
The CallableStatement interface is designed to execute SQL-stored procedures. The procedures may have IN, OUT, or IN OUT parameters. An IN parameter receives a value passed to the procedure when it is called. An OUT parameter returns a value after the procedure is completed, but it doesn’t contain any value when the procedure is called. An IN OUT parameter contains a value passed to the procedure when it is called and returns a value after it is completed. For example, the following procedure in Oracle PL/SQL has IN parameter p1, OUT parameter p2, and IN OUT parameter p3:
Key Point IN parameter OUT parameter IN OUT parameter
create or replace procedure sampleProcedure (p1 in varchar, p2 out number, p3 in out integer) is begin /* do something */ end sampleProcedure; /
M34_LIAN0182_11_SE_C34.indd 27
5/23/17 5:54 PM
34-28 Chapter 34 Java Database Programming Note The syntax of stored procedures is vendor specific. We use both Oracle and MySQL for demonstrations of stored procedures in this book.
A CallableStatement object can be created using the prepareCall(String call) method in the Connection interface. For example, the following code c reates a C allableS tatement cstmt on Connection connection for the procedure sampleProcedure: CallableStatement callableStatement = connection.prepareCall( "{call sampleProcedure(?, ?, ?)}");
{call sampleProcedure(?, ?, ...)} is referred to as the SQL escape syntax, which signals the driver that the code within it should be handled differently. The driver parses the escape syntax and translates it into code that the database understands. In this example, sampleProcedure is an Oracle procedure. The call is translated to the string begin sampleProcedure(?, ?, ?); end and passed to an Oracle database for execution. You can call procedures as well as functions. The syntax to create an SQL callable statement for a function is: {? = call functionName(?, ?, ...)}
CallableStatement inherits PreparedStatement. Additionally, the C allableStatement interface provides methods for registering the OUT parameters and for getting values from the OUT parameters.
Before calling an SQL procedure, you need to use appropriate setter methods to pass values to IN and IN OUT parameters, and use registerOutParameter to register OUT and IN OUT parameters. For example, before calling procedure sampleProcedure, the following statements pass values to parameters p1 (IN) and p3 (IN OUT) and register parameters p2 (OUT) and p3 (IN OUT): callableStatement.setString(1, "Dallas"); callableStatement.setLong(3, 1); // Set 1 // Register OUT parameters callableStatement.registerOutParameter(2, callableStatement.registerOutParameter(3,
// Set Dallas to p1 to p3 java.sql.Types.DOUBLE); java.sql.Types.INTEGER);
You can use execute() or executeUpdate() to execute the procedure depending on the type of SQL statement, then use getter methods to retrieve values from the OUT parameters. For example, the next statements retrieve the values from parameters p2 and p3: double d = callableStatement.getDouble(2); int i = callableStatement.getInt(3);
Let us define a MySQL function that returns the number of the records in the table that match the specified firstName and lastName in the Student table. /* For the callable statement example. Use MySQL version 5 */ drop function if exists studentFound; delimiter // create function studentFound(first varchar(20), last varchar(20)) returns int begin declare result int; select count(*) into result
M34_LIAN0182_11_SE_C34.indd 28
5/23/17 5:54 PM
34.6 CallableStatement 34-29 from Student where Student.firstName = first and Student.lastName = last; return result; end; // delimiter ; /* Please note that there is a space between delimiter and ; */
If you use an Oracle database, the function can be defined as follows: create or replace function studentFound (first varchar2, last varchar2) /* Do not name firstName and lastName. */ return number is numberOfSelectedRows number := 0; begin select count(*) into numberOfSelectedRows from Student where Student.firstName = first and Student.lastName = last; return numberOfSelectedRows; end studentFound; /
Suppose the function studentFound is already created in the database. Listing 34.4 gives an example that tests this function using callable statements.
Listing 34.4 TestCallableStatement.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
import java.sql.*; public class TestCallableStatement { /** Creates new form TestTableEditor */ public static void main(String[] args) throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection( "jdbc:mysql://localhost/javabook", "scott", "tiger"); // Connection connection = DriverManager.getConnection( // ("jdbc:oracle:thin:@liang.armstrong.edu:1521:orcl", // "scott", "tiger");
load driver connect database
// Create a callable statement CallableStatement callableStatement = connection.prepareCall( "{? = call studentFound(?, ?)}");
create callable statement
java.util.Scanner input = new java.util.Scanner(System.in); System.out.print("Enter student's first name: "); String firstName = input.nextLine(); System.out.print("Enter student's last name: "); String lastName = input.nextLine();
enter firstName enter lastName
callableStatement.setString(2, firstName); callableStatement.setString(3, lastName); callableStatement.registerOutParameter(1, Types.INTEGER); callableStatement.execute();
set IN parameter set IN parameter register OUT parameter execute statement
M34_LIAN0182_11_SE_C34.indd 29
5/23/17 5:54 PM
34-30 Chapter 34 Java Database Programming 28 29 30 31 32 33 34 35 36
get OUT parameter
if (callableStatement.getInt(1) >= 1) System.out.println(firstName + " " + lastName + " is in the database"); else System.out.println(firstName + " " + lastName + " is not in the database"); } }
Enter student's first name: Jacob Enter student's last name: Smith Jacob Smith is in the database
Enter student's first name: John Enter student's last name: Smith John Smith is not in the database
The program loads a MySQL driver (line 6), connects to a MySQL database (lines 7–9), and creates a callable statement for executing the function studentFound (lines 15–16). The function’s first parameter is the return value; its second and third parameters correspond to the first and last names. Before executing the callable statement, the program sets the first name and last name (lines 24–25) and registers the OUT parameter (line 26). The statement is executed in line 27. The function’s return value is obtained in line 29. If the value is greater than or equal to 1, the student with the specified first and last name is found in the table. Check Point
34.6.1 Describe callable statements. How do you create instances of CallableStatement? How do you execute a CallableStatement? How do you register OUT parameters in a CallableStatement?
34.7 Retrieving Metadata Key Point
database metadata
The database metadata such as database URL, username, and JDBC driver name can be obtained using the DatabaseMetaData interface and result set metadata such as table column count and column names can be obtained using the ResultSetMetaData interface. JDBC provides the DatabaseMetaData interface for obtaining database-wide information, and the ResultSetMetaData interface for obtaining information on a specific ResultSet.
34.7.1 Database Metadata The Connection interface establishes a connection to a database. It is within the context of a connection that SQL statements are executed and results are returned. A connection also provides access to database metadata information that describes the capabilities of the database, supported SQL grammar, stored procedures, and so on. To obtain an instance of DatabaseMetaData for a database, use the getMetaData method on a Connection object like this: DatabaseMetaData dbMetaData = connection.getMetaData();
If your program connects to a local MySQL database, the program in Listing 34.5 displays the database information statements shown in Figure 34.24.
M34_LIAN0182_11_SE_C34.indd 30
5/23/17 5:54 PM
34.7 Retrieving Metadata 34-31
Listing 34.5 TestDatabaseMetaData.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
import java.sql.*; public class TestDatabaseMetaData { public static void main(String[] args) throws SQLException, ClassNotFoundException { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); System.out.println("Driver loaded"); // Connect to a database Connection connection = DriverManager.getConnection ("jdbc:mysql://localhost/javabook", "scott", "tiger"); System.out.println("Database connected"); DatabaseMetaData dbMetaData = connection.getMetaData(); System.out.println("database URL: " + dbMetaData.getURL()); System.out.println("database username: " + dbMetaData.getUserName()); System.out.println("database product name: " + dbMetaData.getDatabaseProductName()); System.out.println("database product version: " + dbMetaData.getDatabaseProductVersion()); System.out.println("JDBC driver name: " + dbMetaData.getDriverName()); System.out.println("JDBC driver version: " + dbMetaData.getDriverVersion()); System.out.println("JDBC driver major version: " + dbMetaData.getDriverMajorVersion()); System.out.println("JDBC driver minor version: " + dbMetaData.getDriverMinorVersion()); System.out.println("Max number of connections: " + dbMetaData.getMaxConnections()); System.out.println("MaxTableNameLength: " + dbMetaData.getMaxTableNameLength()); System.out.println("MaxColumnsInTable: " + dbMetaData.getMaxColumnsInTable());
load driver
connect database
database metadata get metadata
// Close the connection connection.close(); } }
Figure 34.24 The DatabaseMetaData interface enables you to obtain database information.
M34_LIAN0182_11_SE_C34.indd 31
5/23/17 5:54 PM
34-32 Chapter 34 Java Database Programming
34.7.2 Obtaining Database Tables You can identify the tables in the database through database metadata using the getTables method. Listing 34.6 displays all the user tables in the javabook database on a local MySQL database. Figure 34.25 shows a sample output of the program.
Listing 34.6 FindUserTables.java
load driver
connect database
database metadata obtain tables
get table names
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
import java.sql.*; public class FindUserTables { public static void main(String[] args) throws SQLException, ClassNotFoundException { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); System.out.println("Driver loaded"); // Connect to a database Connection connection = DriverManager.getConnection ("jdbc:mysql://localhost/javabook", "scott", "tiger"); System.out.println("Database connected"); DatabaseMetaData dbMetaData = connection.getMetaData(); ResultSet rsTables = dbMetaData.getTables(null, null, null, new String[] {"TABLE"}); System.out.print("User tables: "); while (rsTables.next()) System.out.print(rsTables.getString("TABLE_NAME") + " "); // Close the connection connection.close(); } }
Figure 34.25 You can find all the tables in the database. Line 17 obtains table information in a result set using the getTables method. One of the columns in the result set is TABLE_NAME. Line 21 retrieves the table name from this result set column.
34.7.3 Result Set Metadata The ResultSetMetaData interface describes information pertaining to the result set. A ResultSetMetaData object can be used to find the types and properties of the columns in a ResultSet. To obtain an instance of ResultSetMetaData, use the getMetaData method on a result set like this: ResultSetMetaData rsMetaData = resultSet.getMetaData();
M34_LIAN0182_11_SE_C34.indd 32
5/23/17 5:54 PM
34.7 Retrieving Metadata 34-33 You can use the getColumnCount() method to find the number of columns in the result and the getColumnName(int) method to get the column names. For example, Listing 34.7 displays all the column names and contents resulting from the SQL SELECT statement select * from Enrollment. The output is shown in Figure 34.26.
Listing 34.7 TestResultSetMetaData.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
import java.sql.*; public class TestResultSetMetaData { public static void main(String[] args) throws SQLException, ClassNotFoundException { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); System.out.println("Driver loaded"); // Connect to a database Connection connection = DriverManager.getConnection ("jdbc:mysql://localhost/javabook", "scott", "tiger"); System.out.println("Database connected"); // Create a statement Statement statement = connection.createStatement(); // Execute a statement ResultSet resultSet = statement.executeQuery ("select * from Enrollment"); ResultSetMetaData rsMetaData = resultSet.getMetaData(); for (int i = 1; i connectToDB()); btExecuteSQL.setOnAction(e -> executeSQL()); btClearSQLCommand.setOnAction(e -> tasqlCommand.setText(null)); btClearSQLResult.setOnAction(e -> taSQLResult.setText(null)); } /** Connect to DB */ private void connectToDB() { // Get database information from the user input String driver = cboDriver .getSelectionModel().getSelectedItem(); String url = cboURL.getSelectionModel().getSelectedItem(); String username = tfUsername.getText().trim(); String password = pfPassword.getText().trim(); // Connection to the database try { Class.forName(driver); connection = DriverManager.getConnection( url, username, password); lblConnectionStatus.setText("Connected to " + url); } catch (java.lang.Exception ex) { ex.printStackTrace();
5/23/17 5:59 PM
35.2 A Universal SQL Client 35-5 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
} } /** Execute SQL commands */ private void executeSQL() { if (connection == null) { taSQLResult.setText("Please connect to a database first"); return; } else { String sqlCommands = tasqlCommand.getText().trim(); String[] commands = sqlCommands.replace('\n', ' ').split(";"); for (String aCommand: commands) { if (aCommand.trim().toUpperCase().startsWith("SELECT")) { processSQLSelect(aCommand); } else { processSQLNonSelect(aCommand); } } } } /** Execute SQL SELECT commands */ private void processSQLSelect(String sqlCommand) { try { // Get a new statement for the current connection statement = connection.createStatement(); // Execute a SELECT SQL command ResultSet resultSet = statement.executeQuery(sqlCommand); // Find the number of columns in the result set int columnCount = resultSet.getMetaData().getColumnCount(); String row = ""; // Display column names for (int i = 1; i { try { copyFile(); } catch (Exception ex) { lblStatus.setText(ex.toString()); } }); } /** Display the file in the text area */ private void showFile() { Scanner input = null; try { // Use a Scanner to read text from the file input = new Scanner(new File(tfFilename.getText().trim())); // Read a line and append the line to the text area while (input.hasNext()) taFile.appendText(input.nextLine() + '\n'); } catch (FileNotFoundException ex) { System.out.println("File not found: " + tfFilename.getText()); } catch (IOException ex) { ex.printStackTrace(); } finally { if (input != null) input.close(); } } private void copyFile() throws Exception { // Load the JDBC driver Class.forName(cboDriver.getSelectionModel() .getSelectedItem().trim()); System.out.println("Driver loaded");
M35_LIAN0182_11_SE_C35.indd 9
5/23/17 5:59 PM
35-10 Chapter 35 Advanced Java Database Programming 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
M35_LIAN0182_11_SE_C35.indd 10
// Establish a connection Connection conn = DriverManager.getConnection( cboURL.getSelectionModel().getSelectedItem().trim(), tfUsername.getText().trim(), String.valueOf(pfPassword.getText()).trim()); System.out.println("Database connected"); // Read each line from the text file and insert it to the table insertRows(conn); } private void insertRows(Connection connection) { // Build the SQL INSERT statement String sqlInsert = "insert into " + tfTableName.getText() + " values ("; // Use a Scanner to read text from the file Scanner input = null; // Get file name from the text field String filename = tfFilename.getText().trim(); try { // Create a scanner input = new Scanner(new File(filename)); // Create a statement Statement statement = connection.createStatement(); System.out.println("Driver major version? " + connection.getMetaData().getDriverMajorVersion()); // Determine if batchUpdatesSupported is supported boolean batchUpdatesSupported = false; try { if (connection.getMetaData().supportsBatchUpdates()) { batchUpdatesSupported = true; System.out.println("batch updates supported"); } else { System.out.println("The driver " + "does not support batch updates"); } } catch (UnsupportedOperationException ex) { System.out.println("The operation is not supported"); } // Determine if the driver is capable of batch updates if (batchUpdatesSupported) { // Read a line and add the insert table command to the batch while (input.hasNext()) { statement.addBatch(sqlInsert + input.nextLine() + ")"); } statement.executeBatch(); lblStatus.setText("Batch updates completed"); }
5/23/17 5:59 PM
35.4 Scrollable and Updatable Result Set 35-11 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
else { // Read a line and execute insert table command while (input.hasNext()) { statement.executeUpdate(sqlInsert + input.nextLine() + ")"); } lblStatus.setText("Single row update completed"); } } catch (SQLException ex) { System.out.println(ex); } catch (FileNotFoundException ex) { System.out.println("File not found: " + filename); } finally { if (input != null) input.close(); } } }
The insertRows method (lines 149–216) uses the batch updates to submit SQL INSERT commands to the database for execution, if the driver supports batch updates. Lines 174–181 check whether the driver supports batch updates. If the driver does not support the operation, an UnsupportedOperationException exception will be thrown (line 183) when the s upportsBatchUpdates() method is invoked. The tables must already be created in the database. The file format and contents must match the database table specification. Otherwise, the SQL INSERT command will fail. In Exercise 35.1, you will write a program to insert a thousand records to a database and compare the performance with and without batch updates.
5.3.1 3 35.3.2 35.3.3 35.3.4
What is batch processing in JDBC? What are the benefits of using batch processing? How do you add an SQL statement to a batch? How do you execute a batch? Can you execute a SELECT statement in a batch? How do you know whether a JDBC driver supports batch updates?
Check Point
35.4 Scrollable and Updatable Result Set You can use scrollable and updatable result set to move the cursor anywhere in the result set to perform insertion, deletion, and update. The result sets used in the preceding examples are read sequentially. A result set maintains a cursor pointing to its current row of data. Initially the cursor is positioned before the first row. The next() method moves the cursor forward to the next row. This is known as sequential forward reading. A more powerful way of accessing database is to use a scrollable and updatable result, which enables you to scroll the rows both forward and backward and move the cursor to a desired location using the first, last, next, previous, absolute, or relative method. Additionally, you can insert, delete, or update a row in the result set and have the changes automatically reflected in the database. To obtain a scrollable or updatable result set, you must first create a statement with an appropriate type and concurrency mode. For a static statement, use
Key Point
Statement statement = connection.createStatement (int resultSetType, int resultSetConcurrency);
M35_LIAN0182_11_SE_C35.indd 11
5/23/17 5:59 PM
35-12 Chapter 35 Advanced Java Database Programming For a prepared statement, use PreparedStatement statement = connection.prepareStatement (String sql, int resultSetType, int resultSetConcurrency);
The possible values of resultSetType are the constants defined in the ResultSet: ■■ TYPE_FORWARD_ONLY:
The result set is accessed forward sequentially.
■■ TYPE_SCROLL_INSENSITIVE :
The result set is scrollable, but not sensitive to
changes in the database. ■■ TYPE_SCROLL_SENSITIVE:
The result set is scrollable and sensitive to changes made by others. Use this type if you want the result set to be scrollable and updatable.
The possible values of resultSetConcurrency are the constants defined in the ResultSet: ■■ CONCUR_READ_ONLY:
The result set cannot be used to update the database.
■■ CONCUR_UPDATABLE:
The result set can be used to update the database.
For example, if you want the result set to be scrollable and updatable, you can create a statement, as follows: Statement statement = connection.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)
You use the executeQuery method in a Statement object to execute an SQL query that returns a result set as follows: ResultSet resultSet = statement.executeQuery(query);
You can now use the methods first(), next(), previous(), and last() to move the cursor to the first row, next row, previous row, and last row. The absolute(int row) method moves the cursor to the specified row; and the getXxx(int columnIndex) or getXxx(String columnName) method is used to retrieve the value of a specified field at the current row. The methods insertRow(), deleteRow(), and updateRow() can also be used to insert, delete, and update the current row. Before applying insertRow or updateRow, you need to use the method updateXxx(int columnIndex, Xxx value) or update(String columnName, Xxx value) to write a new value to the field at the current row. The cancelRowUpdates() method cancels the updates made to a row. The close() method closes the result set and releases its resource. The wasNull() method returns true if the last column read had a value of SQL NULL. Listing 35.3 gives an example that demonstrates how to create a scrollable and updatable result set. The program creates a result set for the StateCapital table. The StateCapital table is defined as follows: create table StateCapital ( state varchar(40), capital varchar(40) );
Listing 35.3 ScrollUpdateResultSet.java 1 2 3 4 5
M35_LIAN0182_11_SE_C35.indd 12
import java.sql.*; public class ScrollUpdateResultSet { public static void main(String[] args) throws SQLException, ClassNotFoundException {
5/23/17 5:59 PM
35.4 Scrollable and Updatable Result Set 35-13 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
// Load the JDBC driver Class.forName("oracle.jdbc.driver.OracleDriver"); System.out.println("Driver loaded"); // Connect to a database Connection connection = DriverManager.getConnection ("jdbc:oracle:thin:@liang.armstrong.edu:1521:orcl", "scott", "tiger"); connection.setAutoCommit(true); System.out.println("Database connected"); // Get a new statement for the current connection Statement statement = connection.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); // Get ResultSet ResultSet resultSet = statement.executeQuery ("select state, capital from StateCapital"); System.out.println("Before update "); displayResultSet(resultSet); // Update the second row resultSet.absolute(2); // Move cursor to the second row resultSet.updateString("state", "New S"); // Update the column resultSet.updateString("capital", "New C"); // Update the column resultSet.updateRow(); // Update the row in the data source // Insert after the last row resultSet.last(); resultSet.moveToInsertRow(); // Move cursor to the insert row resultSet.updateString("state", "Florida"); resultSet.updateString("capital", "Tallahassee"); resultSet.insertRow(); // Insert the row resultSet.moveToCurrentRow(); // Move the cursor to the current row // Delete fourth row resultSet.absolute(4); // Move cursor to the 5th row resultSet.deleteRow(); // Delete the second row System.out.println("After update "); resultSet = statement.executeQuery ("select state, capital from StateCapital"); displayResultSet(resultSet); // Close the connection resultSet.close(); } private static void displayResultSet(ResultSet resultSet) throws SQLException { ResultSetMetaData rsMetaData = resultSet.getMetaData(); resultSet.beforeFirst(); while (resultSet.next()) { for (int i = 1; i { locale = locales[cboLocale .getSelectionModel().getSelectedIndex()]; updateStrings(); computeLoan(); }); btCompute.setOnAction(e -> computeLoan()); } /** Compute payments and display results locale-sensitive format */ private void computeLoan() { // Retrieve input from user double loan = new Double(tfLoanAmount.getText()).doubleValue(); double interestRate = new Double(tfInterestRate.getText()).doubleValue() / 1240; int numberOfYears = new Integer(tfNumberOfYears.getText()).intValue(); // Calculate payments double monthlyPayment = loan * interestRate/ (1 - (Math.pow(1 / (1 + interestRate), numberOfYears * 12))); double totalPayment = monthlyPayment * numberOfYears * 12;
5/22/17 5:30 PM
36.5 Resource Bundles 36-27 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
// Get formatters NumberFormat percentFormatter = NumberFormat.getPercentInstance(locale); NumberFormat currencyForm = NumberFormat.getCurrencyInstance(locale); NumberFormat numberForm = NumberFormat.getNumberInstance(locale); percentFormatter.setMinimumFractionDigits(2); // Display formatted input tfFormattedInterestRate.setText( percentFormatter.format(interestRate * 12)); tfFormattedNumberOfYears.setText (numberForm.format(numberOfYears)); tfFormattedLoanAmount.setText(currencyForm.format(loan)); // Display results in currency format tfMonthlyPayment.setText(currencyForm.format(monthlyPayment)); tfTotalPayment.setText(currencyForm.format(totalPayment)); } /** Update resource strings */ private void updateStrings() { res = ResourceBundle.getBundle("MyResource", locale); lblInterestRate.setText(res.getString("Annual_Interest_Rate")); lblNumberOfYears.setText(res.getString("Number_Of_Years")); lblLoanAmount.setText(res.getString("Loan_Amount")); lblTotalPayment.setText(res.getString("Total_Payment")); lblMonthlyPayment.setText(res.getString("Monthly_Payment")); btCompute.setText(res.getString("Compute")); lblChooseALocale.setText(res.getString("Choose_a_Locale")); lblEnterInterestRate.setText( res.getString("Enter_Interest_Rate")); lblPayment.setText(res.getString("Payment")); } }
Property resource bundles are implemented as text files with a .properties extension, and are placed in the same location as the class files for the program. ListResourceBundles are provided as Java class files. Because they are implemented using Java source code, new and modified ListResourceBundles need to be recompiled for deployment. With Property ResourceBundles, there is no need for recompilation when translations are modified or added to the application. Nevertheless, ListResourceBundles provide considerably better performance than PropertyResourceBundles. If the resource bundle is not found or a resource object is not found in the resource bundle, a MissingResourceException is raised. Since MissingResourceException is a subclass of RuntimeException, you do not need to catch the exception explicitly in the code. This example is the same as Listing 36.6, NumberFormatDemo.java, except that the program contains the code for handling resource strings. The updateString method (lines 165–177) is responsible for displaying the locale-sensitive strings. This method is invoked when a new locale is selected in the combo box.
6.5.1 How does the getBundle method locate a resource bundle? 3 36.5.2 How does the getObject method locate a resource?
M36_LIAN0182_11_SE_C36.indd 27
Check Point
5/22/17 5:30 PM
36-28 Chapter 36 Internationalization
36.6 Character Encoding You can specify an encoding scheme for file IO to read and write Unicode characters. Key Point
Java programs use Unicode. When you read a character using text I/O, the Unicode code of the character is returned. The encoding of the character in the file may be different from the Unicode encoding. Java automatically converts it to the Unicode. When you write a character using text I/O, Java automatically converts the Unicode of the character to the encoding specified for the file. This is pictured in Figure 36.11. A character is converted into Unicode
Program The Unicode of the character is returned The Unicode of the character is sent out
A character stored in a specified encoding
A character is converted into the code for the specified encoding
Figure 36.11 The encoding of the file may be different from the encoding used in the program. You can specify an encoding scheme using a constructor of Scanner/PrintWriter for text I/O, as follows: public Scanner(File file, String encodingName) public PrintWriter(File file, String encodingName)
For a list of encoding schemes supported in Java, see http://download.oracle.com/javase/1.5.0/ docs/guide/intl/encoding.doc.html and mindprod.com/jgloss/encoding.html. For example, you may use the encoding name GB18030 for simplified Chinese characters, Big5 for traditional Chinese characters, Cp939 for Japanese characters, Cp933 for Korean characters, and Cp838 for Thai characters. The following code in Listing 36.8 creates a file using the GB18030 encoding (line 8). You have to read the text using the same encoding (line 12). The output is shown in Figure 36.12a.
Listing 36.8 EncodingDemo.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
M36_LIAN0182_11_SE_C36.indd 28
import import import import import import import
java.util.*; java.io.*; javafx.application.Application; javafx.scene.Scene; javafx.scene.layout.StackPane; javafx.stage.Stage; javafx.scene.text.Text;
public class EncodingDemo extends Application { @Override // Override the start method in the Application class public void start(Stage primaryStage) throws Exception { try ( PrintWriter output = new PrintWriter("temp.txt", "GB18030"); ) { output.print("\u6B22\u8FCE Welcome \u03b1\u03b2\u03b3"); }
5/22/17 5:30 PM
Chapter Summary 36-29 18 19 20 21 22 23 24 25 26 27 28 29 30 31
try ( Scanner input = new Scanner(new File("temp.txt"), "GB18030"); ) { StackPane pane = new StackPane(); pane.getChildren().add(new Text(input.nextLine())); // Create a scene and place it in the stage Scene scene = new Scene(pane, 200, 200); primaryStage.setTitle("EncodingDemo"); // Set the stage title primaryStage.setScene(scene); // Place the scene in the stage primaryStage.show(); // Display the stage } } }
(a) Using GB18030 encoding
(b) Using default encoding
Figure 36.12 You can specify an encoding scheme for a text file. If you don’t specify an encoding in lines 13 and 19, the system’s default encoding scheme is used. The US default encoding is ASCII. ASCII code uses 8 bits. Java uses the 16-bit Unicode. If a Unicode is not an ASCII code, the character '?' is written to the file. Thus, when you write \u6B22 to an ASCII file, the ? character is written to the file. When you read it back, you will see the ? character, as shown in Figure 36.12b. To find out the default encoding on your system, use System.out.println(System.getProperty("file.encoding"));
The default encoding name is Cp1252 on Windows, which is a variation of ASCII.
6.6.1 How do you specify an encoding scheme for a text file? 3 36.6.2 What would happen if you wrote a Unicode character to an ASCII text file? 36.6.3 How do you find the default encoding name on your system?
Check Point
Key Terms locale 36-2 resource bundle 36-21
file encoding scheme 36-28
Chapter Summary 1. Java is the first language designed from the ground up to support internationalization.
In consequence, it allows your programs to be customized for any number of countries or languages without requiring cumbersome changes in the code.
2. Java characters use Unicode in the program. The use of Unicode encoding makes it easy to write Java programs that can manipulate strings in any international language.
M36_LIAN0182_11_SE_C36.indd 29
5/22/17 5:30 PM
36-30 Chapter 36 Internationalization 3. Java provides the Locale class to encapsulate information about a specific locale. A
Locale object determines how locale-sensitive information, such as date, time, and
number, is displayed, and how locale-sensitive operations, such as sorting strings, are performed. The classes for formatting date, time, and numbers, and for sorting strings are grouped in the java.text package.
4. Different locales have different conventions for displaying date and time. The java. text.DateFormat class and its subclasses can be used to format date and time in a locale-sensitive way for display to the user.
5. To format a number for the default or a specified locale, use one of the factory class methods in the NumberFormat class to get a formatter. Use getInstance or getNumberInstance to get the normal number format. Use getCurrencyInstance to get the currency number format. Use getPercentInstance to get a format for displaying
percentages.
6. Java uses the ResourceBundle class to separate locale-specific information, such as
status messages and GUI component labels, from the program. The information is stored outside the source code and can be accessed and loaded dynamically at runtime from a ResourceBundle, rather than hard-coded into the program.
7. You can specify an encoding for a text file when constructing a PrintWriter or a Scanner.
Quiz Answer the quiz for this chapter online at the book Companion Website.
Programming Exercises Sections 36.1–36.2
*36.1 (Unicode viewer) Develop a GUI application that displays Unicode characters, as
shown in Figure 36.13. The user specifies a Unicode in the text field and presses the Enter key to display a sequence of Unicode characters starting with the specified Unicode. The Unicode characters are displayed in a scrollable text area of 20 lines. Each line contains 16 characters preceded by the Unicode that is the code for the first character on the line.
Figure 36.13 The program displays the Unicode characters.
M36_LIAN0182_11_SE_C36.indd 30
5/22/17 5:30 PM
Programming Exercises 36-31 **36.2 (Display date and time) Write a program that displays the current date and time as shown in Figure 36.14. The program enables the user to select a locale, time zone, date style, and time style from the combo boxes.
Figure 36.14 The program displays the current date and time.
Section 36.3
36.3 (Place the calendar and clock in a panel) Write a program that displays the current
date in a calendar and current time in a clock, as shown in Figure 36.15. Enable the program to run standalone.
Figure 36.15 The calendar and clock display the current date and time.
36.4 (Find the available locales and time zone IDs) Write two programs to display the available locales and time zone IDs using buttons, as shown in Figure 36.16.
Figure 36.16 The program displays available locales and time zones using buttons.
Section 36.4
*36.5 (Compute loan amortization schedule) Rewrite Exercise 4.22 using JavaFX, as
shown in Figure 36.17. The program allows the user to set the loan amount, loan
M36_LIAN0182_11_SE_C36.indd 31
5/22/17 5:30 PM
36-32 Chapter 36 Internationalization
Figure 36.17 The program displays the loan payment schedule. period, and interest rate, and displays the corresponding interest, principal, and balance in the currency format.
36.6 (Convert dollars to other currencies) Write a program that converts U.S. dollars to
Canadian dollars, German marks, and British pounds, as shown in Figure 36.18. The user enters the U.S. dollar amount and the conversion rate, and clicks the Convert button to display the converted amount.
Figure 36.18 The program converts U.S. dollars to Canadian dollars, German marks, and British pounds.
36.7 (Compute loan payments) Rewrite Listing 2.8, ComputeLoan.java, to display the monthly payment and total payment in currency.
36.8 (Use the DecimalFormat class) Rewrite Exercise 5.8 to display at most two digits after the decimal point for the temperature using the DecimalFormat class.
Section 36.5
*36.9 (Use resource bundle) Modify the example for displaying a calendar in Section 36.3.6,
“Example: Displaying a Calendar,” to localize the labels “Choose a locale” and “Calendar Demo” in French, German, Chinese, or a language of your choice. **36.10 (Flag and anthem) Rewrite Listing 16.13, ImageAudioAnimation.java, to use the resource bundle to retrieve image and audio files. (Hint: When a new country is selected, set an appropriate locale for it. Have your program look for the flag and audio file from the resource file for the locale.)
Section 36.6
**36.11 (Specify file encodings) Write a program named
Exercise36_11Writer
that writes 1307 * 16 Chinese Unicode characters starting from \u0E00 to a file named Exercise36_11.gb using the GBK encoding scheme. Output 16
M36_LIAN0182_11_SE_C36.indd 32
5/22/17 5:30 PM
Programming Exercises 36-33 characters per line and separate the characters with spaces. Write a program named Exercise36_11Reader that reads all the characters from a file using a specified encoding. Figure 36.19 displays the file using the GBK encoding scheme.
Figure 36.19 The program displays the file using the specified encoding scheme.
M36_LIAN0182_11_SE_C36.indd 33
5/22/17 5:30 PM
CHAPTER
37 Servlets Objectives ■■
To explain how a servlet works (§37.2).
■■
To create/develop/run servlets (§37.3).
■■
To deploy servlets on application servers such as Tomcat and GlassFish (§37.3).
■■
To describe the servlets API (§37.4).
■■
To create simple servlets (§37.5).
■■
To create and process HTML forms (§37.6).
■■
To develop servlets to access databases (§37.7).
■■
To use hidden fields, cookies, and HttpSession to track sessions (§37.8).
M37_LIAN0182_11_SE_C37.indd 1
5/23/17 6:04 PM
37-2 Chapter 37 Servlets
37.1 Introduction Java Servlets is the foundation for developing Web applications using Java. Key Point
Servlets are Java programs that run on a Web server. They can be used to process client requests or produce dynamic webpages. For example, you can write servlets to generate dynamic webpages that display stock quotes or process client registration forms and store registration data in a database. This chapter introduces the concept of Java servlets. You will learn how to develop Java servlets using NetBeans.
Note You can develop servlets without using an IDE. However, using an IDE such as NetBeans can greatly simplify the development task. The tool can automatically create the supporting directories and files. We choose NetBeans because it has the best support for Java Web development. You can still use your favorite IDE or no IDE for this chapter.
Note Servlets are the foundation of Java Web technologies. JSP, JSF, and Java Web services are based on servlets. A good understanding of servlets helps you see the big picture of Java Web technology and learn JSP, JSF, and Web services.
37.2 HTML and Common Gateway Interface Key Point
Java servlets are Java programs that function like CGI programs. They are executed upon request from a Web browser. Java servlets run in the Web environment. To understand Java servlets, let us review HTML and the Common Gateway Interface (CGI).
37.2.1 Static Web Contents You create webpages using HTML. Your webpages are stored as files on the Web server. The files are usually stored in the /htdocs directory on Unix, as shown in Figure 37.1. A user types a URL for the file from a Web browser. The browser contacts the Web server and requests the file. The server finds the file and returns it to the browser. The browser then displays the file to the user. This works fine for static information that does not change regardless of who requests it or when it is requested. Static information is stored in files. The information in the files can be updated, but at any given time every request for the same document returns exactly the same result.
Web Server Host Host Machine File System http://www.webserverhost.com/index.html Web Server
Web Browser
/htdocs/index.html
HTML Page
Figure 37.1 A Web browser requests a static HTML page from a Web server.
M37_LIAN0182_11_SE_C37.indd 2
5/23/17 6:04 PM
37.2 HTML and Common Gateway Interface 37-3
37.2.2 Dynamic Web Contents and Common Gateway Interface Not all information, however, is static in nature. Stock quotes are updated whenever a trade takes place. Election vote counts are updated constantly on Election Day. Weather reports are frequently updated. The balance in a customer’s bank account is updated whenever a transaction takes place. To view up-to-date information on the Web, the HTML pages for displaying this information must be generated dynamically. Dynamic Web pages are generated by Web servers. The Web server needs to run certain programs to process user requests from Web browsers in order to produce a customized response. The Common Gateway Interface, or CGI, was proposed to generate dynamic Web content. The interface provides a standard framework for Web servers to interact with external programs, known as CGI programs. As shown in Figure 37.2, the Web server receives a request from a Web browser and passes it to the CGI program. The CGI program processes the request and generates a response at runtime. CGI programs can be written in any language, but the Perl language is the most popular choice. CGI programs are typically stored in the /cgi-bin directory. Here is a pseudocode example of a CGI program for displaying a customer’s bank account balance: 1. Obtain account ID and password. 2. Verify account ID and password. If it fails, generate an HTML page to report incorrect account ID and password, and exit. 3. Retrieve account balance from the database; generate an HTML page to display the account ID and balance. URL Example http://www.server.com/cgi-bin/getBalance.cgi? accountId=scott&password=tiger
Web Server Host Host Machine File System
Send a request URL Web Browser HTML Page returned
/htdocs/index.html
Web Server
Spawn CGI Process
Generate Response
Execute CGI Program Get CGI Code
Figure 37.2 A Web browser requests a dynamic HTML page from a Web server.
37.2.3 The GET and POST Methods The two most common HTTP requests, also known as methods, are GET and POST. The Web browser issues a request using a URL or an HTML form to trigger the Web server to execute a CGI program. HTML forms will be introduced in §37.6, “HTML Forms.” When issuing a CGI request directly from a URL, the GET method is used. This URL is known as a query string. The URL query string consists of the location of the CGI program, the parameters, and their values. For example, the following URL causes the CGI program getBalance to be invoked on the server side: http://www.webserverhost.com/cgi-bin/ getBalance.cgi?accountId=scott+smith&password=tiger
M37_LIAN0182_11_SE_C37.indd 3
5/23/17 6:04 PM
37-4 Chapter 37 Servlets The ? symbol separates the program from the parameters. The parameter name and value are associated using the = symbol. Parameter pairs are separated using the & symbol. The + symbol denotes a space character. So, here accountId is scott smith. When issuing a request from an HTML form, either a GET method or a POST method can be used. The form explicitly specifies one of these. If the GET method is used, the data in the form are appended to the request string as if it were submitted using a URL. If the POST method is used, the data in the form are packaged as part of the request file. The server program obtains the data by reading the file. The POST method is more secure than the GET method.
Note The GET and POST methods both send requests to the Web server. The POST method always triggers the execution of the corresponding CGI program. The GET method may not cause the CGI program to be executed, if the previous same request is cached in the Web browser. Web browsers often cache webpages so that the same request can be quickly responded to without contacting the Web server. The browser checks the request sent through the GET method as a URL query string. If the results for the exact same URL are cached on a disk, then the previous webpages for the URL may be displayed. To ensure that a new webpage is always displayed, use the POST method. For example, use a POST method if the request will actually update the database. If your request is not time sensitive, such as finding the address of a student in the database, use the GET method to speed up performance.
37.2.4 From CGI to Java Servlets CGI provides a relatively simple approach for creating dynamic Web applications that accept a user request, process it on the server side, and return responses to the Web browser. But CGI is very slow when handling a large number of requests simultaneously, because the Web server spawns a process for executing each CGI program. Each process has its own runtime environment that contains and runs the CGI program. It is not difficult to imagine what will happen if many CGI programs were executed simultaneously. System resource would be quickly exhausted, potentially causing the server to crash. Several new approaches have been developed to remedy the performance problem of CGI programs. Java servlets are one successful technology for this purpose. Java servlets are Java programs that function like CGI programs. They are executed upon request from a Web browser. All servlets run inside a servlet container, also referred to as a servlet server or a servlet engine. A servlet container is a single process that runs in a Java Virtual Machine. The JVM creates a thread to handle each servlet. Java threads have much less overhead than fullblown processes. All the threads share the same memory allocated to the JVM. Since the JVM persists beyond the life cycle of a single servlet execution, servlets can share objects already created in the JVM. For example, if multiple servlets access the same database, they can share the connection object. Servlets are much more efficient than CGI. Servlets have other benefits that are inherent in Java. As Java programs, they are object oriented, portable, and platform independent. Since you know Java, you can develop servlets immediately with the support of Java API for accessing databases and network resources. Check Point
7.2.1 What is the common gateway interface? 3 37.2.2 What are the differences between the GET and POST methods in an HTML form? 37.2.3 Can you submit a GET request directly from a URL? Can you submit a POST
request directly from a URL? 37.2.4 What is wrong in the following URL for submitting a GET request to the servlet FindScore on host liang at port 8084 with parameter name? http://liang:8084/findScore?name=“P Yates” 37.2.5 What are the differences between CGI and servlets?
M37_LIAN0182_11_SE_C37.indd 4
5/23/17 6:04 PM
37.3 Creating and Running Servlets 37-5
37.3 Creating and Running Servlets An IDE such as NetBeans is an effective tool for creating Java servlet. To run Java servlets, you need a servlet container. Many servlet containers are available for free. Two popular ones are Tomcat (developed by Apache, www.apache.org) and GlassFish (developed by Sun, glassfish.dev.java.net). Both Tomcat and GlassFish are bundled and integrated with NetBeans 7 (Java EE version). When you run a servlet from NetBeans, Tomcat or GlassFish will be automatically started. You can choose to use either of them, or any other application server. GlassFish has more features than Tomcat and it takes more system resource.
Key Point
37.3.1 Creating a Servlet Before our introduction to the servlet API, let us look at a simple example to see how servlets work. A servlet to some extent resembles a JavaFX program. Every Java applet is a subclass of the Application class. You need to override appropriate methods in the Application class to implement the application. Every servlet is a subclass of the HttpServlet class. You need to override appropriate methods in the HttpServlet class to implement the servlet. Listing 37.1 is a servlet that generates a response in HTML using the doGet method.
Listing 37.1 FirstServlet.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
package chapter37; import javax.servlet.*; import javax.servlet.http.*; public class FirstServlet extends HttpServlet { /** Handle the HTTP GET method. * @param request servlet request * @param response servlet response */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { response.setContentType("text/html"); java.io.PrintWriter out = response.getWriter(); // output your page here out.println(""); out.println(""); out.println("Servlet"); out.println(""); out.println(""); out.println("Hello, Java Servlets"); out.println(""); out.println(""); out.close(); } }
The doGet method (line 11) is invoked when the Web browser issues a request using the GET method. The doGet method has two parameters: request and response. request is for obtaining data from the Web browser, and response is for sending data back to the browser. Line 14 indicates that data are sent back to the browser as text/html. Line 15 obtains an instance of PrintWriter for actually outputting data to the browser.
M37_LIAN0182_11_SE_C37.indd 5
5/23/17 6:04 PM
37-6 Chapter 37 Servlets
37.3.2 Creating Servlets in NetBeans NetBeans is updated frequently. The current version is 8 at the time of this writing. To create a servlet in NetBeans 8, you have to first create a Web project, as follows: 1. Choose File, New Project to display the New Project dialog box. Choose Java Web in the Categories section and Web Application in the Projects section, as shown in Figure 37.3a. Click Next to display the New Web Application dialog box, as shown in Figure 37.3b. 2. Enter liangweb in the Project Name field and c:\book in the Project Location field. Check Set as Main Project. Click Next to display the dialog box for specifying server and settings, as shown in Figure 37.4. 3. Select GlassFish Server 4.1 for server and Java EE 7 Web for Java EE Version. Click Finish to create the Web project, as shown in Figure 37.5. Now you can create a servlet in the project, as follows: 1. Right-click the liangweb node in the project pane to display a context menu. Choose New, Servlet to display the New Servlet dialog box, as shown in Figure 37.6.
(a)
(b)
Figure 37.3 (a) Choose Web Application to create a Web project. (b) Specify project name and location.
Figure 37.4 Choose servers and settings.
M37_LIAN0182_11_SE_C37.indd 6
5/23/17 6:04 PM
37.3 Creating and Running Servlets 37-7
Figure 37.5 A new Web project is created.
Figure 37.6 You can create a servlet in the New Servlet dialog box. 2. Enter FirstServlet in the Class Name field and chapter37 in the Package field and click Next to display the Configure Servlet Deployment dialog box, as shown in Figure 37.7. 3. Select the checkbox to add the servlet information to web.xml and click Finish to create the servlet. A servlet template is now created in the project, as shown in Figure 37.8.
M37_LIAN0182_11_SE_C37.indd 7
5/23/17 6:04 PM
37-8 Chapter 37 Servlets
Figure 37.7 You need to click the checkbox to add servlet information to web.xml.
Figure 37.8 A new servlet class is created in the project.
M37_LIAN0182_11_SE_C37.indd 8
5/23/17 6:04 PM
37.4 The Servlet API 37-9 4. Replace the code in the content pane for the servlet using the code in Listing 37.1. 5. Right-click liangweb node in the Project pane to display a context menu and choose Run to launch the Web server. In the Web browser, enter http://localhost:8084/liangweb/FirstServlet in the URL. You will now see the servlet result displayed, as shown in Figure 37.9.
Figure 37.9 Servlet result is displayed in a Web browser.
Note If the servlet is not displayed in the browser, do the following: 1. Make sure that you have added the servlet in the xml.web file. 2. Right-click liangweb and choose Clean and Build. 3. Right-click liangweb and choose Run. Reenter http://localhost:8084/ liangweb/FirstServlet in the URL. If still not working, exit NetBeans and restart it.
Note Depending on the server setup, you may have a port number other than 8084.
Tip You can deploy a Web application using a Web archive file (WAR) to a Web application server (e.g., Tomcat). To create a WAR file for the liangweb project, right-click liangweb and choose Build Project. You can now locate liangweb.war in the c:\book\liangweb\dist folder. To deploy on Tomcat, simply place liangweb.war into the webapps directory. When Tomcat starts, the .war file will be automatically installed.
Note If you wish to use NetBeans as the development tool and Tomcat as the deployment server, please see Supplement V.E, “Tomcat Tutorial.”
37.3.1 Can you display an HTML file (e.g. c:\ 7.3.2 3 37.3.3 37.3.4 37.3.5 37.3.6
test.html) by typing the complete file name in the Address field of Internet Explorer? Can you run a servlet by simply typing the servlet class file name? How do you create a Web project in NetBeans? How do you create a servlet in NetBeans? How do you run a servlet in NetBeans? When you run a servlet from NetBeans, what is the port number by default? What happens if the port number is already in use? What is the .war file? How do you obtain a .war file for a Web project in NetBeans?
Check Point
37.4 The Servlet API The Servlet interface defines the methods init, service, and destroy to managing the life-cylce of a serlvet.
M37_LIAN0182_11_SE_C37.indd 9
Key Point
5/23/17 6:04 PM
37-10 Chapter 37 Servlets ServletConfig
Servlet
HttpServlet
GenericServlet
ServletRequest
HttpServletRequest
ServletResponse
HttpServletResponse
javax.Servlet*
javax.Servlet.http.*
Figure 37.10 The servlet API contains interfaces and classes that you use to develop and run servlets. You have to know the servlet API in order to understand the source code in Listing3 7.1, in FirstServlet.java. The servlet API provides the interfaces and classes that support servlets. These interfaces and classes are grouped into two packages, javax.servlet and javax. servlet.http, as shown in Figure 37.10. The javax.servlet package provides basic interfaces, and the javax.servlet.http package provides classes and interfaces derived from them, which provide specific means for servicing HTTP requests.
37.4.1 The Servlet Interface The javax.servlet.Servlet interface defines the methods that all servlets must i mplement. The methods are listed below: /** Invoked for every servlet constructed */ public void init() throws ServletException; /** Invoked to respond to incoming requests */ public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException; /** Invoked to release resource by the servlet */ public void destroy();
The init, service, and destroy methods are known as life-cycle methods and are called in the following sequence (see Figure 37.11): 1. The init method is called when the servlet is first created and is not called again as long as the servlet is not destroyed. This resembles an applet’s init method, which is invoked after the applet is created and is not invoked again as long as the applet is not destroyed. Creates the servlet using its constructor
JVM loads the servlet class Loaded
Servlet is invoked for the first time
Created
Invokes the service method
Invokes the init method
Initialized
The same servlet is invoked again, bypassing the Loaded, Created, and Initialized states, as long as it has not been destroyed
Invokes destroy() after a timeout period has passed or the Web server is being stopped
Served
Destroyed
Invokes the service method
Figure 37.11 The JVM uses the init, service, and destroy methods to control the servlet.
M37_LIAN0182_11_SE_C37.indd 10
5/23/17 6:04 PM
37.4 The Servlet API 37-11 2. The service method is invoked each time the server receives a request for the servlet. The server spawns a new thread and invokes service. 3. The destroy method is invoked after a timeout period has passed or as the Web server is terminated. This method releases resources for the servlet.
37.4.2 The GenericServlet Class, ServletConfig Interface, and HttpServlet Class The javax.servlet.GenericServlet class defines a generic, protocol-independent servlet. It implements javax.servlet.Servlet and javax.servlet.ServletConfig. ServletConfig is an interface that defines four methods (getInitParameter, getInitParameterNames, getServletContext, and getServletName) for obtaining information from a Web server during initialization. All the methods in Servlet and ServletConfig are implemented in GenericServlet except service. Therefore, GenericServlet is an abstract class. The javax.servlet.http.HttpServlet class defines a servlet for the HTTP protocol. It extends GenericServlet and implements the service method. The service method is implemented as a dispatcher of HTTP requests. The HTTP requests are processed in the following methods: ■■ doGet
is invoked to respond to a GET request.
■■ doPost
is invoked to respond to a POST request.
is invoked to respond to a DELETE request. Such a request is normally used to delete a file on the server.
■■ doDelete
is invoked to respond to a PUT request. Such a request is normally used to send a file to the server.
■■ doPut
■■ doOptions is invoked to respond to an OPTIONS request. This returns information
about the server, such as which HTTP methods it supports. ■■ doTrace is invoked to respond to a TRACE request. Such a request is normally used
for debugging. This method returns an HTML page that contains appropriate trace information. All these methods use the following signature: protected void doXxx(HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException
The HttpServlet class provides default implementation for these methods. You need to override doGet, doPost, doDelete, and doPut if you want the servlet to process a GET, POST, DELETE, or PUT request. By default, nothing will be done. Normally, you should not override the doOptions method unless the servlet implements new HTTP methods beyond those implemented by HTTP 1.1. Nor is there any need to override the doTrace method.
Note GET and POST requests are often used, whereas DELETE, PUT, OPTIONS, and TRACE are not. For more information about these requests, please refer to the HTTP 1.1 specification from www.cis.ohio-state.edu/htbin/rfc/rfc2068.html.
Note Although the methods in HttpServlet are all nonabstract, HttpServlet is defined as an abstract class. Thus you cannot create a servlet directly from HttpServlet. Instead you have to define your servlet by extending HttpServlet.
M37_LIAN0182_11_SE_C37.indd 11
5/23/17 6:04 PM
37-12 Chapter 37 Servlets The relationship of these interfaces and classes is shown in Figure 37.12. «interface» javax.servlet.Servlet
javax.servlet.GenericServlet
javax.servlet.http.HttpServlet
+init(config: ServletConfig): void
+doGet(req: HttpServletRequest, resp: HttpServletResponse): void
+service(req: ServletRequest, resp: ServletResponse): void
+doPost(req: HttpServletRequest, resp: HttpServletResponse): void
+destroy(): void
+doDelete(req: HttpServletRequest, resp: HttpServletResponse): void
+getServletInfo(): String
+doPut(req: HttpServletRequest, resp: HttpServletResponse): void
«interface» javax.servlet.ServletConfig
+doOptions(req: HttpServletRequest, resp: HttpServletResponse): void
+getInitParameter(name: String): String
+doTrace(req: HttpServletRequest, resp: HttpServletResponse): void
+getInitParameterNames(): Enumeration +getServletContext(): ServletContext +getServletName(): String
Figure 37.12 HttpServlet inherits abstract class GenericServlet, which implements interfaces Servlet and ServletConfig.
37.4.3 The ServletRequest Interface and HttpServletRequest Interface Every doXxx method in the HttpServlet class has a parameter of the HttpServletRequest type, which is an object that contains HTTP request information, including parameter name and values, attributes, and an input stream. HttpServletRequest is a subinterface of Servlet Request. ServletRequest defines a more general interface to provide information for all kinds of clients. The frequently used methods in these two interfaces are shown in Figure 37.13.
37.4.4 The ServletResponse Interface and HttpServletResponse Interface Every doXxx method in the HttpServlet class has a parameter of the HttpServlet Response type, which is an object that assists a servlet in sending a response to the c lient. HttpServletResponse is a subinterface of ServletResponse. ServletResponse defines a more general interface for sending output to the client. The frequently used methods in these two interfaces are shown in Figure 37.14. Check Point
7.4.1 Describe the life cycle of a servlet. 3 37.4.2 Suppose you started the Web server, ran the following servlet twice by issuing an appropriate URL from the Web browser, and finally stopped Tomcat. What was displayed on the console when the servlet was first invoked? What was displayed on the console when the servlet was invoked for the second time? What was displayed on the console when Tomcat was shut down? import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Test extends HttpServlet { public Test() { System.out.println("Constructor called"); } /** Initialize variables */ public void init() throws ServletException {
M37_LIAN0182_11_SE_C37.indd 12
5/23/17 6:04 PM
37.4 The Servlet API 37-13 System.out.println("init called"); } /** Process the HTTP Get request */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("doGet called"); } /** Clean up resources */ public void destroy() { System.out.println("destroy called"); } } «interface» javax.servlet.ServletRequest +getParamter(name: String): String +getParameterValues(): String[]
Returns the value of a request parameter as a String, or null if the parameter does not exist. Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted from data. Only use this method when you are sure that the parameter has only one value. If it has more than one value, use getParameterValues.
+getRemoteAddr(): String
Returns the Internet Protocol (IP) address of the client that sent the request.
+getRemoteHost(): String
Returns the fully qualified name of the client that sent the request, or the IP address of the client if the name cannot be determined.
«interface» javax.servlet.http.HttpServletRequest +getHeader(name: String): String
+getMethod(): String +getQueryString(): String
Returns the value of the specified request header as a String. If the request did not include a header of the specified name, this method returns null. Since the header name is caseinsensitive, you can use this method with any request header. Returns the name of the HTTP method with which this request was made; for example, GET, POST, DELETE, PUT, OPTIONS, or TRACE. Returns the query string that is contained in the request URL after the path. This method returns null if the URL does not have a query string.
+getCookies(): javax.servlet.http.Cookies[]
Returns an array containing all of the Cookie objects the client sent with the request. This method returns null if no cookies were sent. Using cookies is introduced in Section 37.8.2, “Session Tracking Using Cookies.”
+getSession(create: boolean): HttpSession
getSession(true) returns the current session associated with this request. If the request does not have a session, it creates one. getSession(false) returns the current session associated with the request. If the request does not have a session, it returns null. The getSession method is used in session tracking, which is introduced in Section 37.8.3, “Session Tracking Using the Servlet API.”
Figure 37.13 HttpServletRequest is a subinterface of ServletRequest. «interface» javax.servlet.ServletResponse +getWriter(): java.io.PrintWriter
Returns a PrintWriter object that can send character text to the client.
+setContentType(type: String): void
Sets the content type of the response being sent to the client before writing response to the client. When you are writing HTML to the client, the type should be set to “text/html.” For plain text, use “text/plain.” For sending a gif image to the browser, use “image/gif.”
«interface» javax.servlet.http.HttpServletResponse +addCookie(Cookie cookie): void
Adds the specified cookie to the response. This method can be called multiple times to set more than one cookie.
Figure 37.14 HttpServletResponse is a subinterface of ServletResponse.
M37_LIAN0182_11_SE_C37.indd 13
5/23/17 6:04 PM
37-14 Chapter 37 Servlets
37.5 Creating Servlets Key Point
You can define a servlet class by extending the HttpServlet class and implement the doGet and doPost methods. Servlets are the opposite of Java applets. Java applets run from a Web browser on the client side. To write Java programs, you define classes. To write a Java applet, you define a class that extends the Applet class. The Web browser runs and controls the execution of the applet through the methods defined in the Applet class. Similarly, to write a Java servlet, you define a class that extends the HttpServlet class. The servlet container runs and controls the execution of the servlet through the methods defined in the HttpServlet class. Like a Java applet, a servlet does not have a main method. A servlet depends on the servlet engine to call the methods. Every servlet has a structure like the one shown below: package chapter37; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class MyServlet extends HttpServlet { /** Called by the servlet engine to initialize servlet */ public void init() throws ServletException { ... } /** Process the HTTP Get request */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ... } /** Process the HTTP Post request */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ... } /** Called by the servlet engine to release resource */ public void destroy() { ... } // Other methods if necessary }
The servlet engine controls the servlets using init, doGet, doPost, destroy, and other methods. By default, the doGet and doPost methods do nothing. To handle a GET request, you need to override the doGet method; to handle a POST request, you need to override the doPost method. Listing 37.2 gives a simple Java servlet that generates a dynamic webpage for displaying the current time, as shown in Figure 37.15.
Figure 37.15 Servlet CurrentTime displays the current time.
M37_LIAN0182_11_SE_C37.indd 14
5/23/17 6:04 PM
37.6 HTML Forms 37-15
Listing 37.2 CurrentTime.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
package chapter37; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class CurrentTime extends HttpServlet { /** Process the HTTP Get request */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("
The current time is " + new java.util.Date()); out.close(); // Close stream } }
The HttpServlet class has a doGet method. The doGet method is invoked when the browser issues a request to the servlet using the GET method. Your servlet class should override the doGet method to respond to the GET request. In this case, you write the code to display the current time. Servlets return responses to the browser through an HttpServletResponse object. Since the setContentType("text/html") method sets the MIME type to “text/html,” the browser will display the response in HTML. The getWriter method returns a PrintWriter object for sending HTML back to the client.
Note The URL query string uses the GET method to issue a request to the servlet. The current time may not be current if the webpage for displaying the current time is cached. To ensure that a new current time is displayed, refresh the page in the browser. In the next example, you will write a new servlet that uses the POST method to obtain the current time.
37.6 HTML Forms HTML forms are used to collect and submit data from a client to a Web server. HTML forms enable you to submit data to the Web server in a convenient form. As shown in Figure 37.16, the form can contain text fields, text area, check boxes, combo boxes, lists, radio buttons, and buttons.
Key Point
Figure 37.16 An HTML form may contain text fields, radio buttons, combo boxes, lists, check boxes, text areas, and buttons.
M37_LIAN0182_11_SE_C37.indd 15
5/23/17 6:04 PM
37-16 Chapter 37 Servlets The HTML code for creating the form in Figure 37.16 is given in Listing 37.3. (If you are unfamiliar with HTML, please see Supplement V.A, “HTML and XHTML Tutorial.”)
Listing 37.3 StudentRegistrationForm.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
M37_LIAN0182_11_SE_C37.indd 16
Last Name
First Name
MI
Major
Computer Science Mathematics English Chinese
Hobby: Tennis Golf Ping Pong
Time Zone"); for (int i = 0; i < allTimeZone.length; i++) { out.println("" + allTimeZone[i] + ""); } out.println(""); out.println("
"); out.println("
"); out.println(""); out.close(); // Close stream } /** Process the HTTP Post request */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); out.println(""); int localeIndex = Integer.parseInt( request.getParameter("locale")); String timeZoneID = request.getParameter("timezone"); out.println("Current Time"); out.println(""); Calendar calendar = new GregorianCalendar(allLocale[localeIndex]); TimeZone timeZone = TimeZone.getTimeZone(timeZoneID); DateFormat dateFormat = DateFormat.getDateTimeInstance( DateFormat.FULL, DateFormat.FULL, allLocale[localeIndex]); dateFormat.setTimeZone(timeZone); out.println("Current time is " + dateFormat.format(calendar.getTime()) + ""); out.println(""); out.close(); // Close stream } }Last Name * First Name * MI
Telephone Email
5/23/17 6:04 PM
37.8 Session Tracking 37-27 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Street
City State
Georgia-GA Oklahoma-OK Indiana-IN Zip
* required fields
Last name: " + lastName); out.println("
First name: " + firstName); out.println("
MI: " + mi); out.println("
Telephone: " + telephone); out.println("
Email: " + email); out.println("
Address: " + street); out.println("
City: " + city); out.println("
State: " + state); out.println("
Zip: " + zip); // Set the action for processing the answers out.println("
"); // Set hidden values out.println("
"); out.println("
"); out.println("
"); out.println("
"); out.println("
"); out.println("
"); out.println("
"); out.println("
"); out.println("
"); out.println("
"); out.println(""); } out.close(); // Close stream } /** Process the HTTP Post request */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); try { String String String String String String String String String
lastName = request.getParameter("lastName"); firstName = request.getParameter("firstName"); mi = request.getParameter("mi"); telephone = request.getParameter("telephone"); email = request.getParameter("email"); street = request.getParameter("street"); city = request.getParameter("city"); state = request.getParameter("state"); zip = request.getParameter("zip");
storeStudent(lastName, firstName, mi, telephone, email, street, city, state, zip);
5/23/17 6:04 PM
37.8 Session Tracking 37-29 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
out.println(firstName + " " + lastName + " is now registered in the database"); } catch(Exception ex) { out.println("Error: " + ex.getMessage()); } } /** Initialize database connection */ private void initializeJdbc() { try { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); System.out.println("Driver loaded"); // Establish a connection Connection conn = DriverManager.getConnection ("jdbc:mysql://localhost/javabook" , "scott", "tiger"); System.out.println("Database connected"); // Create a Statement pstmt = conn.prepareStatement("insert into Address " + "(lastName, firstName, mi, telephone, email, street, city, " + "state, zip) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"); } catch (Exception ex) { System.out.println(ex); } } /** Store a student record to the database private void storeStudent(String lastName, String mi, String phone, String email, String city, String state, String zip) pstmt.setString(1, lastName); pstmt.setString(2, firstName); pstmt.setString(3, mi); pstmt.setString(4, phone); pstmt.setString(5, email); pstmt.setString(6, address); pstmt.setString(7, city); pstmt.setString(8, state); pstmt.setString(9, zip); pstmt.executeUpdate(); }
*/ String firstName, String address, throws SQLException {
}
The servlet processes the GET request by generating an HTML page that displays the client’s input and asks for the client’s confirmation. The input data consist of hidden values in the newly generated forms, so they will be sent back in the confirmation request. The confirmation request uses the POST method. The servlet retrieves the hidden values and stores them in the database. Since the first request does not write anything to the database, it is appropriate to use the GET method. Since the second request results in an update to the database, the POST method must be used.
Note The hidden values could also be sent from the URL query string if the request used the GET method.
M37_LIAN0182_11_SE_C37.indd 29
5/23/17 6:04 PM
37-30 Chapter 37 Servlets
37.8.2 Session Tracking Using Cookies You can track sessions using cookies, which are small text files that store sets of name/value pairs on the disk in the client’s computer. Cookies are sent from the server through the instructions in the header of the HTTP response. The instructions tell the browser to create a cookie with a given name and its associated value. If the browser already has a cookie with the key name, the value will be updated. The browser will then send the cookie with any request submitted to the same server. Cookies can have expiration dates set, after which they will not be sent to the server. The javax.servlet.http.Cookie is used to create and manipulate cookies, as shown in Figure 37.23. javax.servlet.http.Cookie +Cookie(name: String, value: String)
Creates a cookie with the specified name-value pair.
+getName(): String
Returns the name of the cookie.
+getValue(): String
Returns the value of the cookie.
+setValue(newValue: String): void
Assigns a new value to a cookie after the cookie is created.
+getMaxAge(): int
Returns the maximum age of the cookie, specified in seconds.
+setMaxAge(expiration: int): void
Specifies the maximum age of the cookie. By default, this value is –1, which implies that the cookie persists until the browser exits. If you set this value to 0, the cookie is deleted.
+getSecure(): boolean
Returns true if the browser is sending cookies only over a secure protocol.
+setSecure(flag: boolean): void
Indicates to the browser whether the cookie should only be sent using a secure protocol, such as HTTPS or SSL.
+getComment(): String
Returns the comment describing the purpose of this cookie, or null if the cookie has no comment. Sets the comment for this cookie.
+setComment(purpose: String): void
Figure 37.23 Cookie stores a name/value pair and other information about the cookie. To send a cookie to the browser, use the addCookie method in the HttpServlet Response class, as shown below: response.addCookie(cookie);
where response is an instance of HttpServletResponse. To obtain cookies from a browser, use request.getCookies();
where request is an instance of HttpServletRequest. To demonstrate the use of cookies, let us create an example that accomplishes the same task as Listing 37.9, Registration.java. Instead of using hidden values for session tracking, it uses cookies. Create the servlet named RegistrationWithCookie in Listing 37.10. Create an HTML file named RegistrationWithCookie.html that is identical to Registration.html except that the action is replaced by RegistrationWithCookie.java.
Listing 37.10 RegistrationWithCookie.java 1 2 3 4 5
M37_LIAN0182_11_SE_C37.indd 30
package chapter37; import javax.servlet.*; import javax.servlet.http.*; import java.io.*;
5/23/17 6:04 PM
37.8 Session Tracking 37-31 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
import java.sql.*; public class RegistrationWithCookie extends HttpServlet { private static final String CONTENT_TYPE = "text/html"; // Use a prepared statement to store a student into the database private PreparedStatement pstmt; /** Initialize variables */ public void init() throws ServletException { initializeJdbc(); } /** Process the HTTP Get request */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); // Obtain data from the form String lastName = request.getParameter("lastName"); String firstName = request.getParameter("firstName"); String mi = request.getParameter("mi"); String telephone = request.getParameter("telephone"); String email = request.getParameter("email"); String street = request.getParameter("street"); String city = request.getParameter("city"); String state = request.getParameter("state"); String zip = request.getParameter("zip"); if (lastName.length() == 0 || firstName.length() == 0) { out.println("Last Name and First Name are required"); } else { // Create cookies and send cookies to browsers Cookie cookieLastName = new Cookie("lastName", lastName); // cookieLastName.setMaxAge(1000); response.addCookie(cookieLastName); Cookie cookieFirstName = new Cookie("firstName", firstName); response.addCookie(cookieFirstName); // cookieFirstName.setMaxAge(0); Cookie cookieMi = new Cookie("mi", mi); response.addCookie(cookieMi); Cookie cookieTelephone = new Cookie("telephone", telephone); response.addCookie(cookieTelephone); Cookie cookieEmail = new Cookie("email", email); response.addCookie(cookieEmail); Cookie cookieStreet = new Cookie("street", street); response.addCookie(cookieStreet); Cookie cookieCity = new Cookie("city", city); response.addCookie(cookieCity); Cookie cookieState = new Cookie("state", state); response.addCookie(cookieState); Cookie cookieZip = new Cookie("zip", zip); response.addCookie(cookieZip); // Ask for confirmation out.println("You entered the following data"); out.println("
Last name: " + lastName); out.println("
First name: " + firstName); out.println("
MI: " + mi); out.println("
Telephone: " + telephone);
M37_LIAN0182_11_SE_C37.indd 31
5/23/17 6:04 PM
37-32 Chapter 37 Servlets 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
M37_LIAN0182_11_SE_C37.indd 32
out.println("
Email: " + email); out.println("
Street: " + street); out.println("
City: " + city); out.println("
State: " + state); out.println("
Zip: " + zip); // Set the action for processing the answers out.println("
"); out.println("
"); out.println(""); } out.close(); // Close stream } /** Process the HTTP Post request */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); String String String String String String String String String
lastName = ""; firstName = ""; mi = ""; telephone = ""; email = ""; street = ""; city = ""; state = ""; zip = "";
// Read the cookies Cookie[] cookies = request.getCookies(); // Get cookie values for (int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equals("lastName")) lastName = cookies[i].getValue(); else if (cookies[i].getName().equals("firstName")) firstName = cookies[i].getValue(); else if (cookies[i].getName().equals("mi")) mi = cookies[i].getValue(); else if (cookies[i].getName().equals("telephone")) telephone = cookies[i].getValue(); else if (cookies[i].getName().equals("email")) email = cookies[i].getValue(); else if (cookies[i].getName().equals("street")) street = cookies[i].getValue(); else if (cookies[i].getName().equals("city")) city = cookies[i].getValue(); else if (cookies[i].getName().equals("state")) state = cookies[i].getValue(); else if (cookies[i].getName().equals("zip")) zip = cookies[i].getValue(); } try { storeStudent(lastName, firstName, mi, telephone, email, street, city, state, zip);
5/23/17 6:04 PM
37.8 Session Tracking 37-33 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
out.println(firstName + " " + lastName + " is now registered in the database"); out.close(); // Close stream } catch(Exception ex) { out.println("Error: " + ex.getMessage()); } } /** Initialize database connection */ private void initializeJdbc() { try { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); System.out.println("Driver loaded"); // Establish a connection Connection conn = DriverManager.getConnection ("jdbc:mysql://localhost/javabook" , "scott", "tiger"); System.out.println("Database connected"); // Create a Statement pstmt = conn.prepareStatement("insert into Address " + "(lastName, firstName, mi, telephone, email, street, city, " + "state, zip) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"); } catch (Exception ex) { System.out.println(ex); } } /** Store a student record to the database */ private void storeStudent(String lastName, String firstName, String mi, String telephone, String email, String street, String city, String state, String zip) throws SQLException { pstmt.setString(1, lastName); pstmt.setString(2, firstName); pstmt.setString(3, mi); pstmt.setString(4, telephone); pstmt.setString(5, email); pstmt.setString(6, street); pstmt.setString(7, city); pstmt.setString(8, state); pstmt.setString(9, zip); pstmt.executeUpdate(); } }
You have to create a cookie for each value you want to track, using the Cookie class’s only constructor, which defines a cookie’s name and value as shown below (line 40): Cookie cookieLastName = new Cookie("lastName", lastName);
To send the cookie to the browser, use a statement like this one (line 42): response.addCookie(cookieLastName);
If a cookie with the same name already exists in the browser, its value is updated; otherwise, a new cookie is created.
M37_LIAN0182_11_SE_C37.indd 33
5/23/17 6:04 PM
37-34 Chapter 37 Servlets Cookies are automatically sent to the Web server with each request from the client. The servlet retrieves all the cookies into an array using the getCookies method (line 100): Cookie[] cookies = request.getCookies();
To obtain the name of the cookie, use the getName method (line 104): String name = cookies[i].getName();
The cookie’s value can be obtained using the getValue method: String value = cookies[i].getValue();
Cookies are stored as strings just like form parameters and hidden values. If a cookie represents a numeric value, you have to convert it into an integer or a double, using the parseInt method in the Integer class or the parseDouble method in the Double class. By default, a newly created cookie persists until the browser exits. However, you can set an expiration date, using the setMaxAge method, to allow a cookie to stay in the browser for up to 2,147,483,647 seconds (approximately 24,855 days).
37.8.3 Session Tracking Using the Servlet API You have now learned both session tracking using hidden values and session tracking using cookies. These two session-tracking methods have problems. They send data to the browser either as hidden values or as cookies. The data are not secure, and anybody with knowledge of computers can obtain them. The hidden data are in HTML form, which can be viewed from the browser. Cookies are stored in the Cache directory of the browser. Because of security concerns, some browsers do not accept cookies. The client can turn the cookies off and limit their number. Another problem is that hidden data and cookies pass data as strings. You cannot pass objects using these two methods. To address these problems, Java servlet API provides the javax.servlet.http .HttpSession interface, which provides a way to identify a user across more than one page request or visit to a website and to store information about that user. The servlet container uses this interface to create a session between an HTTP client and an HTTP server. The session persists for a specified time period, across more than one connection or page request from the user. A session usually corresponds to one user, who may visit a site many times. The session enables tracking of a large set of data. The data can be stored as objects and are secure because they are kept on the server side. To use the Java servlet API for session tracking, first create a session object using the getSession() method in the HttpServletRequest interface: HttpSession session = request.getSession();
This obtains the session or creates a new session if the client does not have a session on the server. The HttpSession interface provides the methods for reading and storing data to the session, and for manipulating the session, as shown in Figure 37.24.
Note HTTP is stateless. So how does the server associate a session with multiple requests from the same client? This is handled behind the scenes by the servlet container and is transparent to the servlet programmer.
To demonstrate using HttpSession, let us rewrite Listing 37.9, Registration.java, and Listing 37.10, RegistrationWithCookie.java. Instead of using hidden values or cookies for session tracking, it uses servlet HttpSession.
M37_LIAN0182_11_SE_C37.indd 34
5/23/17 6:04 PM
37.8 Session Tracking 37-35
javax.servlet.http.HttpSession +getAttribute(name: String): Object
Returns the object bound with the specified name in this session, or null if no object is bound under the name.
+setAttribute(name: String, value: Object): void
Binds an object to this session, using the specified name. If an object of the same name is already bound to the session, the object is replaced.
+getId(): String
Returns a string containing the unique identifier assigned to this session. The identifier is assigned by the servlet container and is implementation dependent.
+getLastAccessedTime(): long
Returns the last time the client sent a request associated with this session, as the number of milliseconds since midnight January 1, 1970 GMT, and marked by the time the container received the request.
+invalidate(): void
Invalidates this session, then unbinds any objects bound to it.
+isNew(): boolean
Returns true if the session was just created in the current request.
+removeAttribute(name: String): void
Removes the object bound with the specified name from this session. If the session does not have an object bound with the specified name, this method does nothing.
+getMaxInactiveInterval(): int +setMaxInactiveInterval(interval: int): void
Returns the time, in seconds, between client requests before the servlet container will invalidate this session. A negative time indicates that the session will never time-out. Use setMaxInactiveInterval to specify this value.
Figure 37.24 HttpSession establishes a persistent session between a client with multiple requests and the server. Create the servlet named RegistrationWithHttpSession in Listing 37.11. Create an HTML file named RegistrationWithHttpSession.html that is identical to Regis tration.html except that the action is replaced by RegistrationWithHttpSession.
Listing 37.11 RegistrationWithHttpSession.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
package chapter37; import import import import
javax.servlet.*; javax.servlet.http.*; java.io.*; java.sql.*;
public class RegistrationWithHttpSession extends HttpServlet { // Use a prepared statement to store a student into the database private PreparedStatement pstmt; /** Initialize variables */ public void init() throws ServletException { initializeJdbc(); } /** Process the HTTP Get request */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
M37_LIAN0182_11_SE_C37.indd 35
5/23/17 6:04 PM
37-36 Chapter 37 Servlets 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
M37_LIAN0182_11_SE_C37.indd 36
// Set response type and output stream to the browser response.setContentType("text/html"); PrintWriter out = response.getWriter(); // Obtain data from the form String lastName = request.getParameter("lastName"); String firstName = request.getParameter("firstName"); String mi = request.getParameter("mi"); String telephone = request.getParameter("telephone"); String email = request.getParameter("email"); String street = request.getParameter("street"); String city = request.getParameter("city"); String state = request.getParameter("state"); String zip = request.getParameter("zip"); if (lastName.length() == 0 || firstName.length() == 0) { out.println("Last Name and First Name are required"); } else { // Create an Address object Address address = new Address(); address.setLastName(lastName); address.setFirstName(firstName); address.setMi(mi); address.setTelephone(telephone); address.setEmail(email); address.setStreet(street); address.setCity(city); address.setState(state); address.setZip(zip); // Get an HttpSession or create one if it does not exist HttpSession httpSession = request.getSession(); // Store student object to the session httpSession.setAttribute("address", address); // Ask for confirmation out.println("You entered the following data"); out.println("
Last name: " + lastName); out.println("
First name: " + firstName); out.println("
MI: " + mi); out.println("
Telephone: " + telephone); out.println("
Email: " + email); out.println("
Address: " + street); out.println("
City: " + city); out.println("
State: " + state); out.println("
Zip: " + zip); // Set the action for processing the answers out.println("
"); out.println("
"); out.println(""); } out.close(); // Close stream } /** Process the HTTP Post request */
5/23/17 6:04 PM
37.8 Session Tracking 37-37 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Set response type and output stream to the browser response.setContentType("text/html"); PrintWriter out = response.getWriter(); // Obtain the HttpSession HttpSession httpSession = request.getSession(); // Get the Address object in the HttpSession Address address = (Address)(httpSession.getAttribute("address")); try { storeStudent(address); out.println(address.getFirstName() + " " + address.getLastName() + " is now registered in the database"); out.close(); // Close stream } catch(Exception ex) { out.println("Error: " + ex.getMessage()); } } /** Initialize database connection */ private void initializeJdbc() { try { // Load the JDBC driver Class.forName("com.mysql.jdbc.Driver"); System.out.println("Driver loaded"); // Establish a connection Connection conn = DriverManager.getConnection ("jdbc:mysql://localhost/javabook" , "scott", "tiger"); System.out.println("Database connected"); // Create a Statement pstmt = conn.prepareStatement("insert into Address " + "(lastName, firstName, mi, telephone, email, street, city, " + "state, zip) values (?, ?, ?, ?, ?, ?, ?, ?, ?)"); } catch (Exception ex) { System.out.println(ex); } } /** Store an address to the database */ private void storeStudent(Address address) throws SQLException { pstmt.setString(1, address.getLastName()); pstmt.setString(2, address.getFirstName()); pstmt.setString(3, address.getMi()); pstmt.setString(4, address.getTelephone()); pstmt.setString(5, address.getEmail()); pstmt.setString(6, address.getStreet()); pstmt.setString(7, address.getCity()); pstmt.setString(8, address.getState()); pstmt.setString(9, address.getZip()); pstmt.executeUpdate(); } }
M37_LIAN0182_11_SE_C37.indd 37
5/23/17 6:04 PM
37-38 Chapter 37 Servlets The statement (line 52) HttpSession httpSession = request.getSession();
obtains a session, or creates a new session if the session does not exist. Since objects can be stored in HttpSession, this program defines an Address class. An Address object is created and is stored in the session using the setAttribute method, which binds the object with a name like the one shown below (line 55): httpSession.setAttribute("address", address);
To retrieve the object, use the following statement (line 90): Address address = (Address)(httpSession.getAttribute("address"));
There is only one session between a client and a servlet. You can store any number of objects in a session. By default, the maximum inactive interval on many Web servers including Tomcat and GlassFish is 1800 seconds (i.e., a half-hour), meaning that the session expires if there is no activity for 30 minutes. You can change the default using the setMaxInactiveInterval method. For example, to set the maximum inactive interval to one hour, use httpSession.setMaxInactiveInterval(3600);
If you set a negative value, the session will never expire. For this servlet program to work, you have to create the Address class in NetBeans, as follows: 1. Choose New, Java Class from the context menu of the liangweb node in the project pane to display the New Java Class dialog box. 2. Enter Address as the Class Name and chapter37 as the package name. Click Finish to create the class. 3. Enter the code, as shown in Listing 37.12.
Listing 37.12 Address.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
M37_LIAN0182_11_SE_C37.indd 38
package chapter37; public class Address { private String firstName; private String mi; private String lastName; private String telephone; private String street; private String city; private String state; private String email; private String zip; public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getMi() { return this.mi; }
5/23/17 6:04 PM
37.8 Session Tracking 37-39 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
public void setMi(String mi) { this.mi = mi; } public String getLastName() { return this.lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getTelephone() { return this.telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } public String getEmail() { return this.email; } public void setEmail(String email) { this.email = email; } public String getStreet() { return this.street; } public void setStreet(String street) { this.street = street; } public String getCity() { return this.city; } public void setCity(String city) { this.city = city; } public String getState() { return this.state; } public void setState(String state) { this.state = state; } public String getZip() { return this.zip; } public void setZip(String zip) { this.zip = zip; } }
M37_LIAN0182_11_SE_C37.indd 39
5/23/17 6:04 PM
37-40 Chapter 37 Servlets This support class will also be reused in the upcoming chapters. Check Point
7.8.1 What is session tracking? What are three techniques for session tracking? 3 37.8.2 How do you create a cookie, send a cookie to a browser, get cookies from a 37.8.3 37.8.4 37.8.5
browser, get the name of a cookie, set a new value in the cookie, and set cookie expiration time? Do you have to create five Cookie objects in the servlet in order to send five cookies to the browser? How do you get a session, set object value for the session, and get object value from the session? Suppose you inserted the following code in line 53 in Listing 37.11: httpSession.setMaxInactiveInterval(1);
What would happen after the user clicked the Confirm button from the browser? Test your answer by running the program.
37.8.6 Suppose you inserted the following code in line 53 in Listing 37.11: httpSession.setMaxInactiveInterval(-1);
What would happen after the user clicked the Confirm button from the browser?
Key Terms Common Gateway Interface 37-3 CGI programs 37-3 cookie 37-30 GET and POST methods 37-3 GlassFish 37-5 HTML form 37-15
URL query string 37-3 servlet 37-2 servlet container (servlet engine) 37-4 servelt life-cycle methods 37-10 Tomcat 37-5
Chapter Summary 1. A servlet is a special kind of program that runs from a Web server. Tomcat and GlassFish are Web servers that can run servlets.
2. A servlet URL is specified by the host name, port, and request string (e.g., http://
localhost:8084/liangweb/ServletClass). There are several ways to invoke a servlet: (1) by typing a servlet URL from a Web browser, (2) by placing a hyper link in an HTML page, and (3) by embedding a servlet URL in an HTML form. All the requests trigger the GET method, except that in the HTML form you can explicitly specify the POST method.
3. You develop a servlet by defining a class that extends the HttpServlet class, imple-
ments the doGet(HttpServletRequest, HttpServletResponse) method to respond to the GET method, and implements the doPost(HttpServletRequest, HttpServletResponse) method to respond to the POST method.
M37_LIAN0182_11_SE_C37.indd 40
5/23/17 6:04 PM
Programming Exercises 37-41 4. The request information passed from a client to the servlet is contained in an object
of HttpServletRequest. You can use the methods getParameter, getParameterValues, getRemoteAddr, getRemoteHost, getHeader, getQueryString, etCookies, and getSession to obtain the information from the request. g
5. The content sent back to the client is contained in an object of HttpServletResponse.
To send content to the client, first set the type of the content (e.g., html/plain) using the setContentType(contentType) method, then output the content through an I/O stream on the HttpServletResponse object. You can obtain a character PrintWriter stream using the getWriter() method and obtain a binary OutputStream using the getOutputStream() method.
6. A servlet may be shared by many clients. When the servlet is first created, its init
method is called. It is not called again as long as the servlet is not destroyed. The service method is invoked each time the server receives a request for the servlet. The server spawns a new thread and invokes service. The destroy method is invoked after a timeout period has passed or the Web server is stopped.
7. There are three ways to track a session. You can track a session by passing data from the
servlet to the client as a hidden value in a dynamically generated HTML form by including a field such as . The next request will submit the data back to the servlet. The servlet retrieves this hidden value just like any other parameter value using the getParameter method.
8. You can track sessions using cookies. A cookie is created using the constructor new
Cookie(String name, String value). Cookies are sent from the server through the object of HttpServletResponse using the addCookie(aCookie) method to tell the browser to add a cookie with a given name and its associated value. If the browser already has a cookie with the key name, the value will be updated. The browser will then send the cookie with any request submitted to the same server. Cookies can have expiration dates set, after which they will not be sent to the server.
9. Java servlet API provides a session-tracking tool that enables tracking of a large set of data. A session can be obtained using the getSession() method through an HttpServletRequest object. The data can be stored as objects and are secure because they are kept on the server side using the setAttribute(String name, Object value) method.
Quiz Answer the quiz for this chapter online at the book Companion Website.
Programming Exercises Section 37.5
*37.1 (Factorial table) Write a servlet to display a table that contains factorials for the numbers from 0 to 10, as shown in Figure 37.25.
M37_LIAN0182_11_SE_C37.indd 41
5/23/17 6:04 PM
37-42 Chapter 37 Servlets
(a)
(b)
Figure 37.25 (a) The servlet displays factorials for the numbers from 0 to 10 in a table. (b) The servlet displays the multiplication table.
*37.2 (Multiplication table) Write a servlet to display a multiplication table, as shown in *37.3
Figure 37.25b. (Visit count) Develop a servlet that displays the number of visits on the servlet. Also display the client’s host name and IP address, as shown in Figure 37.26.
Figure 37.26 The servlet displays the number of visits and the client’s host name, IP address, and request URL. Implement this program in three different ways: 1. Use an instance variable to store count. When the servlet is created for the first time, count is 0. count is incremented every time the servlet’s doGet method is invoked. When the Web server stops, count is lost. 2. Store the count in a file named Exercise39_3.dat, and use RandomAccessFile to read the count in the servlet’s init method. The count is incremented every time the servlet’s doGet method is invoked. When the Web server stops, store the count back to the file. 3. Instead of counting total visits from all clients, count the visits by each client identified by the client’s IP address. Use Map to store a pair of IP addresses and visit counts. For the first visit, an entry is created in the map. For subsequent visits, the visit count is updated.
Section 37.6
*37.4 (Calculate tax) Write an HTML form to prompt the user to enter taxable income
and filing status, as shown in Figure 37.27a. Clicking the Compute Tax button invokes a servlet to compute and display the tax, as shown in Figure 37.27b. Use the computeTax method introduced in Listing 3.7, ComputingTax.java, to compute tax.
M37_LIAN0182_11_SE_C37.indd 42
5/23/17 6:04 PM
Programming Exercises 37-43
(a)
(b)
Figure 37.27 The servlet computes the tax.
*37.5 (Calculate loan) Write an HTML form that prompts the user to enter loan amount,
interest rate, and number of years, as shown in Figure 37.28a. Clicking the Compute Loan Payment button invokes a servlet to compute and display the monthly and total loan payments, as shown in Figure 37.28b. Use the Loan class given in Listing 10.2, Loan.java, to compute the monthly and total payments.
(a)
(b)
Figure 37.28 The servlet computes the loan payment.
**37.6 (Find scores from text files) Write a servlet that displays the student name and the
current score, given the SSN and class ID. For each class, a text file is used to store the student name, SSN, and current score. The file is named after the class ID with .txt extension. For instance, if the class ID were csci1301, the file name would be csci1301.txt. Suppose each line consists of student name, SSN, and score. These three items are separated by the # sign. Create an HTML form that enables the user to enter the SSN and class ID, as shown in Figure 37.29a. Upon clicking the Submit button, the result is displayed, as shown in Figure 37.29b. If the SSN or the class ID does not match, report an error. Assume three courses are available: CSCI1301, CSCI1302, and CSCI3720.
(a)
(b)
Figure 37.29 The HTML form accepts the SSN and class ID from the user and sends them to the servlet to obtain the score.
M37_LIAN0182_11_SE_C37.indd 43
5/23/17 6:04 PM
37-44 Chapter 37 Servlets Section 37.7
**37.7 (Find scores from database tables) Rewrite the preceding servlet. Assume for each
*37.8
class, a table is used to store the student name, ssn, and score. The table name is the same as the class ID. For instance, if the class ID were csci1301, the table name would be csci1301. (Change the password) Write a servlet that enables the user to change the password from an HTML form, as shown in Figure 37.30a. Suppose the user information is stored in a database table named Account with three columns: username, password, and name, where name is the real name of the user. The servlet performs the following tasks: a. Verify that the username and old password are in the table. If not, report the error and redisplay the HTML form. b. Verify that the new password and the confirmed password are the same. If not, report this error and redisplay the HTML form. c. If the user information is entered correctly, update the password and report the status of the update to the user, as shown in Figure 37.30b.
(a)
(b)
Figure 37.30 The user enters the username and the old password and sets a new password. The servlet reports the s tatus of the update to the user.
**37.9 (Display database tables) Write an HTML form that prompts the user to enter
or select a JDBC driver, database URL, username, password, and table name, as shown in Figure 37.31a. Clicking the Submit button displays the table content, as shown in Figure 37.31b.
(a)
(b)
Figure 37.31 The user enters database information and specifies a table to display its content.
M37_LIAN0182_11_SE_C37.indd 44
5/23/17 6:04 PM
Programming Exercises 37-45 Section 37.8
*37.10 (Store cookies) Write a servlet that stores the following cookies in a browser, and set their max age for two days.
Cookie 1: name is “color” and value is red. Cookie 2: name is “radius” and value is 5.5. Cookie 3: name is “count” and value is 2.
*37.11 (Retrieve cookies) Write a servlet that displays all the cookies on the client. The
client types the URL of the servlet from the browser to display all the cookies stored on the browser. (see Figure 37.32.)
Figure 37.32 All the cookies on the client are displayed in the browser.
Comprehensive
***37.12 (Syntax highlighting) Create an HTML form that prompts the user to enter a Java program in a text area, as shown in Figure 37.33a. The form invokes a servlet that displays the Java source code in a syntax-highlighted HTML format, as shown in Figure 37.33b. The keywords, comments, and literals are displayed in bold navy, green, and blue, respectively.
(a)
(b)
Figure 37.33 The Java code in plain text in (a) is displayed in HTML with syntax highlighted in (b).
M37_LIAN0182_11_SE_C37.indd 45
5/23/17 6:04 PM
37-46 Chapter 37 Servlets **37.13 (Access and update a Staff table) Write a Java servlet for Exercise 33.1, as shown in Figure 37.34.
Figure 37.34 The webpage lets you view, insert, and update staff information.
***37.14 (Opinion poll) Create an HTML form that prompts the user to answer a question such as “Are you a CS major?”, as shown in Figure 37.35a. When the Submit button is clicked, the servlet increases the Yes or No count in a database and displays the current Yes and No counts, as shown in Figure 37.35b.
(a)
(b)
Figure 37.35 The HTML form prompts the user to enter Yes or No for a question in (a), and the servlet updates the Yes or No counts (b). Create a table named Poll, as follows: create table Poll ( question varchar(40) primary key, yesCount int, noCount int);
Insert one row into the table, as follows: insert into Poll values ('Are you a CS major? ', 0, 0);
M37_LIAN0182_11_SE_C37.indd 46
5/23/17 6:04 PM
CHAPTER
38 Javaserver Pages Objectives ■■
To create a simple JSP page (§38.2).
■■
To explain how a JSP page is processed (§38.3).
■■
To use JSP constructs to code JSP script (§38.4).
■■
To use predefined variables and directives in JSP (§§38.5–38.6).
■■
To use JavaBeans components in JSP (§38.7).
■■
To get and set JavaBeans properties in JSP (§38.8).
■■
To associate JavaBeans properties with input parameters (§38.9).
■■
To forward requests from one JSP page to another (§38.10).
■■
To develop an application for browsing database tables using JSP (§38.11).
M38_LIAN0182_11_SE_C38.indd 1
5/22/17 5:31 PM
38-2 Chapter 38 Javaserver Pages
38.1 Introduction JavaServer Pages are the Java scripts and code embedded in an HTML file. Key Point
Servlets can be used to generate dynamic Web content. One drawback, however, is that you have to embed HTML tags and text inside the Java source code. Using servlets, you have to modify the Java source code and recompile it if changes are made to the HTML text. If you have a lot of HTML script in a servlet, the program is difficult to read and maintain, since the HTML text is part of the Java program. JavaServer Pages (JSP) was introduced to remedy this drawback. JSP enables you to write regular HTML script in the normal way and embed Java code to produce dynamic content.
38.2 Creating a Simple JSP Page An IDE such an NetBeans is an effecitve tools for creating JavaServer Pages. Key Point
JSP provides an easy way to create dynamic webpages and simplify the task of building Web applications. A JavaServer page is like a regular HTML page with special tags, known as JSP tags, which enable the Web server to generate dynamic content. You can create a webpage with HTML script and enclose the Java code for generating dynamic content in the JSP tags. Here is an example of a simple JSP page:
If you don’t want the comment to appear in the resultant HTML file, use the following comment in JSP:
Listing 38.1 creates a JavaServer page that displays factorials for numbers from 0 to 10, as shown in Figure 38.5.
Figure 38.5 The JSP page displays factorials.
Listing 38.1 Factorial.jsp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Factorial