BOOKS FOR PROFESSIONALS BY PROFESSIONALS® Spell Pro Java 8 Programming RELATED Pro Java 8 Programming covers the core Java development kit. It takes advantage of the finer points of the core standard edition (SE) and development kit version 8. You’ll discover the particulars of working with the Java language and APIs to develop applications in many different contexts. You will also delve into more advanced topics like lambda expressions, closures, new i/o (NIO.2), enums, generics, XML, metadata and the Swing APIs for GUI design and development. By the end of the book, you’ll be fully prepared to take advantage of Java’s ease of development, and able to create powerful, sophisticated Java applications. • How to use and design your own libraries, classes and methods • How to use the new lambda expressions, closures, stream API and more • How to use the new thread and I/O APIs for today’s Java applications that must perform at enterprise and parallel scales • How to use the improved collections APIs • How to build a better Java UI/UX using layout managers, Swing’s JTable and JTree APIs, cut-and-paste, and drag-and-drop • How to use Java Database Connectivity (JDBC) to connect and integrate with various MySQL, Oracle, and NoSQL databases • How to work with internationalization, localization and more • How to effectively use XML and add annotations to your Java applications and more Shelve in: ISBN 978-1-4842-0642-3 55999 Programming Languages /Java User level: Intermediate–Advanced SOURCE CODE ONLINE 9781484206423 THIRD EDITION www.apress.com For your convenience Apress has placed some of the front matter material after the index. Please use the Bookmarks and Contents at a Glance links to access them. Contents at a Glance About the Author ��������������������������������������������������������������������������������������������������xxiii About the Technical Reviewer �������������������������������������������������������������������������������xxv Acknowledgments �����������������������������������������������������������������������������������������������xxvii Introduction ����������������������������������������������������������������������������������������������������������xxix ■ Chapter 1: Going Inside Java ���������������������������������������������������������������������������������1 ■ Chapter 2: Designing Libraries, Classes, and Methods ���������������������������������������19 ■ Chapter 3: Lambdas and Other Java 8 Features ��������������������������������������������������81 ■ Chapter 4: Using Threads in Your Applications �������������������������������������������������105 ■ Chapter 5: Using Stream APIs and Collections ��������������������������������������������������163 ■ Chapter 6: Using Layout Managers ��������������������������������������������������������������������207 ■ Chapter 7: Using Swing’s JTable �����������������������������������������������������������������������281 ■ Chapter 8: Using Swing’s JTree �������������������������������������������������������������������������327 ■ Chapter 9: Adding Cut-and-Paste Functionality ������������������������������������������������������379 ■ Chapter 10: Adding Drag-and-Drop Functionality ���������������������������������������������403 ■ Chapter 11: Printing ������������������������������������������������������������������������������������������449 ■ Chapter 12: Introducing JDBC ���������������������������������������������������������������������������479 ■ Chapter 13: Internationalizing Your Applications ����������������������������������������������529 ■ Chapter 14: Using XML ��������������������������������������������������������������������������������������587 ■ Chapter 15: Adding Annotations ������������������������������������������������������������������������637 Index ���������������������������������������������������������������������������������������������������������������������663 v Introduction It’s been a while since I last revised this material and even longer than that since the first edition was published. In that time the technologies that Java programmers use have changed quite a bit and there’s no doubt that if I were writing this book for the first time I would do some things differently. For example, I’d place more of an emphasis on technologies related to web development to reflect the dominance that it has in the industry today. Even so, it’s a little surprising to find out how relevant most of the original material still is, and I hope that you’ll find both the principles and specific technology topics covered here useful in learning how to program in Java. xxix Chapter 1 Going Inside Java Java has been described as “a simple, robust, object-oriented, platform-independent, multithreaded, dynamic, general-purpose programming environment.” Living up to this definition allowed Java to grow and expand into so many niches that it’s almost unrecognizable from its earliest days. Today you can find Java just about anywhere you can find a microprocessor. It’s used in the largest of enterprises to the smallest of devices, and it’s used in devices from cell phones to supercooled mainframes. For Java to support such a wide range of environments, an almost bewildering array of application programming interfaces (APIs) and versions have been developed, though they’re built around a common set of core classes. In order to become a good Java programmer, it’s important to be able to do the basics well. Being able to produce a highly complex user interface is all very well, but if your code is bloated, memory hungry, and inefficient, your users won’t be happy. This book isn’t about the huge array of development options available to you as a Java developer but about how to do the common tasks that as a Java developer you’ll encounter again and again. Over the course of the book, we’ll examine some of the core language features, such as threading and memory management, that can really make the difference in a professional-quality Java application. At the core of Java’s adaptability, and hence popularity, is that it’s platform-independent. Its “write once, run anywhere” (WORA) capability stems from the way Java itself operates and in particular from the use of an abstract execution environment that allows Java code to be separated from the underlying operating system. Whereas the rest of this book will be about exploring the programming language and APIs of Java, in this chapter we’ll look at the foundations of how Java really operates under the hood, with the Java Virtual Machine (JVM). Understanding the inner workings of Java will give you as a programmer a better understanding of the language, which should make you a better programmer. In this chapter, we’ll cover the following: • The various components of the Java platform • How the JVM allows Java to be platform-independent • What happens when you run a Java program • What a Java class file really contains • The key tools needed to work with a JVM First, then, let’s look at what Java actually is. 1 Chapter 1 ■ GoinG inside Java Java’s Architecture It’s easy to think of Java as merely the programming language with which you develop your applications—writing source files and compiling them into bytecode. However, Java as a programming language is just one component of Java, and it’s the underlying architecture that gives Java many of its advantages, including platform independence. The complete Java architecture is actually the combination of four components: • The Java programming language • The Java class file format • The Java APIs • The JVM So, when you develop in Java, you’re writing with the Java programming language, which is then compiled into Java class files, and those in turn are executed in the JVM. In fact, these days the Java language is just one of the options available if you want to use the rest of the Java platform. Scala, for example, has generated a great deal of interest as an alternative to the Java language and is only one of many different languages that use Java technology without also using the Java language. The combination of the JVM and the core classes form the Java platform, also known as the Java Runtime Environment (JRE), sits on whatever operating system is being used. Figure 1-1 shows how different aspects of Java function relative to one another, to your application, and to the operating system. Figure 1-1. An overview of Java’s role 2 Chapter 1 ■ GoinG inside Java The Java API is prewritten code organized into packages of similar topics. The Java API is divided into three main platforms: • Java Platform, Standard Edition (Java SE): This platform contains the core Java classes and the graphical user interface (GUI) classes. • Java Platform, Enterprise Edition (Java EE): This platform contains the classes and interfaces for developing more complex “enterprise” applications; it contains servlets, JavaServer Pages, and Enterprise JavaBeans, among others. • Java Platform, Micro Edition (Java ME): In this platform, Java goes back to its roots. It provides an optimized runtime environment for consumer products such as Blu-ray disc players, cell phones, and various other types of hardware such as smart appliances. The Java Virtual Machine Before we cover the various aspects of writing powerful Java applications, in this section we’ll spend some time examining the engine that makes this possible. That engine is the JVM, which is an abstract computing machine that interprets compiled Java programs. With other programming languages such as C or C++, a compiler, which is specific to the processor and often also the operating system, compiles the source code into an executable. This executable is then self-sufficient and can be run on the machine. One drawback of this is the lack of portability: code compiled under one operating system can’t be run on another operating system but must be recompiled on every different system on which it is to run. In addition, because of vendor-specific compiler features, code compiled under a certain operating system for a certain processor family (for example, Intel x86, SPARC) may not run on a different type of processor, even if that processor supports the same operating system. This problem occurred particularly when people began writing applications for the Internet. Their applications were intended for users running many different operating systems on various different platforms through different browsers. The only way to resolve this problem was to develop a platform-independent language. In the early 1990s, developers at Sun Microsystems were working on a platform-independent language for use in consumer electronic devices, which unfortunately was somewhat ahead of its time and was therefore shelved. With the advent of the Internet, these developers saw a much greater potential for the language they had created and therefore Java was born. The key to the portability of the Java language is that the output of the Java compiler isn’t standard executable code. Instead, the Java compiler generates an optimized set of instructions called a bytecode program. Bytecodes are sequences of bytes that follow a documented pattern, and we’ll cover them in more detail later. The bytecode program is interpreted by the runtime system, otherwise known as the JVM, and a bytecode program generated on one platform can be run on any other platform that has a JVM installed. This is generally true even though some specifics of the JVM may differ from platform to platform. In other words, a Java program that’s compiled on a Linux workstation can be run on a PC or a Mac. The source code is written in a standard way in the Java language and compiled into a bytecode program, and each JVM interprets the bytecode into native calls specific to its platform (that is, into a language the specific processor can understand). This abstraction is the way various operating systems achieve such operations as printing, accessing files, and handling hardware in a consistent manner across platforms. 3 Chapter 1 ■ GoinG inside Java One feature (and some would say disadvantage) of bytecode is that it’s not executed directly by the processor of the machine on which it’s run. The bytecode program is run through the JVM, which interprets the bytecode, and that’s why Java is referred to as an interpreted language. In reality, Java’s days of being a purely interpreted language are long gone, and the current architecture of most JVM implementations is a mixture of interpretation and compilation. Interpretation is a relatively slow process compared to compilation, and it was during the days of purely interpreted Java that it gained a reputation for being slower than other languages. However, the newer interpreted/compiled hybrid model has largely eliminated the speed difference in Java programs and those of other programming languages, making it appropriate for all but the most resource-intensive applications. Table 1-1 lists compiled versus interpreted languages. Table 1-1. Compiled vs. Interpreted Languages Language Compiled or Interpreted? Portable Code? Minimal Execution Overhead? C++ Compiled No Yes Java Interpreted Yes No It’s also worth noting that Java includes an API for interfacing with native applications (those written in non-Java languages such as C and C++). This API is the Java Native Interface (JNI) API and allows developers to call code written in a non-Java language from Java code, and vice versa. JNI accomplishes two things, one of which is to allow your application to take advantage of operating system–specific features that wouldn’t be available directly through Java. More to the point, JNI allows you to use a compiled language such as C or C++ for functions used by your Java application where performance is critical. Using JNI does, however, negate some of the platform independence of Java, as the native code is generally platform-specific, and therefore the Java code will be tied to the target platform as well if it relies on the native code for some functionality. For machine portability to work, the JVM must be fairly tightly defined, and that’s achieved by the JVM specification. That specification dictates the format of the bytecode recognized by the JVM as well as features and functionality that must be implemented by the JVM. The JVM specification is what ensures the platform independence of the Java language; you can find it on the Oracle web site. In this context, referring to a “JVM” can mean any one of three different things: • An abstract specification, such as the specification for Java 8. • A concrete implementation of the specification. • A runtime execution environment. Different JVM Implementations Sun Microsystems, the original company that developed Java, initially provided its own implementations of various Java technologies, including the JVM, and these were referred to as the reference implementations. However, Sun (and now Oracle, which acquired Sun in 2010) has also granted licenses that allow other organizations to create their own implementations. Although the reference implementations of the JVM and other Java technologies have always been widely used, they’re far from the only implementations available and licensees include IBM, Apple, Hewlett-Packard, and many other organizations. Following the standards defined in the JVM specification means that Java code will behave the same in one-on-one implementation as it does in any other. 4 Chapter 1 ■ GoinG inside Java In 2006, Sun began transitioning Java from its original proprietary model—where Sun tightly controlled the standards and reference implementation—to an open model. That transition resulted in changes in how Java was managed, including the following: • The full source code was made publicly available, or at least as much of it as Sun could legally publish given associated licensing restrictions. • Future changes and additions to Java have been handled through the Java Community Process (JCP) instead of internally within Sun. The JCP is an open and collaborative process for making decisions about the future of Java, though Sun (and now Oracle) continued to play a prominent role in the decision-making process. • The reference implementation of Java is now produced using an open source model and is referred to as the Open Java Development Kit (OpenJDK). Many JVM implementations still exist, but the OpenJDK remains the most commonly used implementation. Why do different versions of the JVM exist? Remember, the JVM specification sets down the required functionality for a JVM but doesn’t mandate how that functionality should be implemented. In an attempt to maximize the use of Java, some flexibility to be creative with the platform was given. The important thing is that whatever the implementation, a JVM must adhere to the guidelines defined by the Java specification. In terms of platform independence, this means a JVM must be able to interpret bytecode that’s correctly generated on any other platform. The JVM As a Runtime Execution Environment Every time you run a Java application, you’re in fact running your application within an instance of the JVM, and each separate application you run will have its own JVM instance. So far you’ve seen that Java uses an interpreted form of source code called bytecode, but how do the instructions you code in the Java programming language get translated into instructions that the underlying operating system (OS) can understand? The JVM specification defines an abstract internal architecture for this process. You’ll learn about the components of this internal architecture in a moment, but at a high level, class files (compiled Java files have a .class extension and are referred to as class files) are loaded into the JVM where they’re then executed by an execution engine. When executing the bytecodes, the JVM interacts with the underlying OS through means of native methods, and it’s the implementation of those native methods that tie a particular JVM implementation to a particular platform (see Figure 1-2). Figure 1-2. Role of the JVM 5 Chapter 1 ■ GoinG inside Java In addition to the previous components, a JVM also needs memory in order to store temporary data related to code execution, such as local variables, which method is executing, and so on. That data is stored within the runtime data areas of the JVM, as explained next. The Runtime Data Areas of the JVM Although the individual implementations may differ slightly from platform to platform, every JVM must supply the runtime components shown in Figure 1-3. Figure 1-3. Runtime data area The Heap The heap is a region of free memory that’s often used for dynamic or temporary memory allocation. The heap is the runtime data area that provides memory for class and array objects. When class or array objects are created in Java, the memory they require is allocated from the heap, which is created when the JVM starts. Heap memory is reclaimed when references to an object or array no longer exist by an automatic storage management system known as the garbage collection, which you’ll learn more about later. The JVM specification doesn’t dictate how the heap is implemented; that’s left up to the creativity of the individual implementations of the JVM. The size of the heap may be constant, or it may be allowed to grow as needed or shrink if the current size is unnecessarily large. The programmer may be allowed to specify the initial size of the heap; for example, on the Win32 and Solaris reference implementations, you can do this with the –mx command-line option. Heap memory doesn’t need to be contiguous. If the heap runs out of memory and additional memory can’t be allocated to it, the system will generate an OutOfMemoryError exception. The Stack A Java stack frame stores the state of method invocations. The stack frame stores data and partial results and includes the method’s execution environment, any local variables used for the method invocation, and the method’s operand stack. The operand stack stores the parameters and return values for most bytecode instructions. The execution environment contains pointers to various aspects of the method invocation. 6
Description: