- Barajar
ActivarDesactivar
- Alphabetizar
ActivarDesactivar
- Frente Primero
ActivarDesactivar
- Ambos lados
ActivarDesactivar
- Leer
ActivarDesactivar
Leyendo...
Cómo estudiar sus tarjetas
Teclas de Derecha/Izquierda: Navegar entre tarjetas.tecla derechatecla izquierda
Teclas Arriba/Abajo: Colvea la carta entre frente y dorso.tecla abajotecla arriba
Tecla H: Muestra pista (3er lado).tecla h
Tecla N: Lea el texto en voz.tecla n
Boton play
Boton play
249 Cartas en este set
- Frente
- Atrás
Chapter 1:
Understanding the Java Class Structure |
In Java programs, classes are the basic building blocks.
An object is a runtime instance of a class in memory. All the various objects of all the different classes represent the state of your program. |
Understanding the Java Class Structure
Fields and Methods |
Java classes have two primary elements: methods, often called functions or procedures in other languages, and fields, more generally known as variables. Together these are called the members of the class. Variables hold the state of the program, and methods operate on that state.
Java calls a word with special meaning a keyword. A method is an operation that can be called. A method requires information be supplied to it from the calling method;this information is called a parameter. The full declaration of a method is called a method signature. |
Understanding the Java Class Structure
Comments |
There are three types of comments in Java.
single-line comment: // comment until end of line multiple-line comment: /* Multiple * line comment */ Javadoc comment(it starts with /**.): /** * Javadoc multiple-line comment * @author Jeanne and Scott */ |
Understanding the Java Class Structure
Classes vs. Files |
Interestingly, Java does not require that the class be public.
You can even put two classes in the same file. When you do so, at most one of the classes in the file is allowed to be public. If you do have a public class, it needs to match the filename. |
Writing a main() Method
|
A Java program begins execution with its main() method. A main() method is the gateway between the startup of a Java process, which is managed by the Java Virtual Machine (JVM), and the beginning of the programmer’s code. The JVM calls on the underlying system to allocate memory and CPU time, access files, and so on.
public class Zoo { public static void main(String[] args) { System.out.println(args[0]); System.out.println(args[1]); } } $ javac Zoo.java $ java Zoo "San Diego" Zoo To compile Java code, the file must have the extension .java. Notice that we must omit the .class extension to run Zoo.java because the period has a reserved meaning in the JVM. The keyword public is what’s called an access modifier. It declares this method’s level of exposure to potential callers in the program. The keyword static binds a method to its class so it can be called by just the class name, as in, for example, Zoo.main(). |
Writing a main() Method
|
If a main() method isn’t present in the class we name with the .java executable, the process will throw an error and terminate. Even if a main() method is present, Java will throw an exception if it isn’t static.
The keyword void represents the return type. A method that returns no data returns control to the caller silently. Finally we arrive at the main() method’s parameter list, represented as an array of java.lang.String objects. In practice, you can write String[] args, String args[] or String... args. An array is a fixed-size list of items that are all of the same type.The characters ... are called varargs (variable argument lists). All command-line arguments are treated as String objects, even if they represent another data type. There’s no argument! What to do? Java prints out an exception: ZooException in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1 at mainmethod.Zoo.main(Zoo.java:7). You need to have a JDK to compile,to run the code a JRE is enough. |
Understanding Package Declarations and Imports
|
Java puts classes in packages. These are logical groupings for classes.
import java.util.Random; ... Random r = new Random(); System.out.println(r.nextInt(10)); // print a number between 0 and 9,just like arrays start from 0. If import begins with java or javax, this means it came with the JDK. If begins with name website in reverse,example com.amazon.java8book tells us the code came from amazon.com. |
Understanding Package Declarations and Imports Wildcards
|
import java.util.*; // imports java.util.Random among other things
Every class in the java.util package is available to this program when Java compiles it. It doesn’t import child packages, fields, or methods; it imports only classes. You might think that including so many classes slows down your program, but it doesn’t |
Understanding Package Declarations
and Imports Redundant Imports |
There’s one special package in the Java world called java.lang. This package is special in that it is automatically imported.
Java automatically looks in the current package for other classes. Files and Paths are both in the package java.nio.file. public class InputImports { public void read(Files files) { Paths.get("name"); } } import java.nio.*; // NO GOOD – a wildcard only matches //class names, not "file.*Files" import java.nio.*.*; // NO GOOD – you can only have one wildcard //and it must be at the end import java.nio.files.Paths.*; // NO GOOD – you cannot import methods //only class names |
Understanding Package Declarations and Imports
Naming Conflicts |
One of the reasons for using packages is so that class names don’t have to be unique across all of Java. This means you’ll sometimes want to import a class that can be found in multiple places. A common example of this is the Date class. Java provides implementations of java.util.Date and java.sql.Date.
import java.util.Date; import java.sql.*; If you explicitly import a class name, it takes precedence over any wildcards present. import java.util.*; import java.sql.*; // DOES NOT COMPILE import java.util.Date; import java.sql.Date; Java is smart enough to detect that this code is no good. The import java.sql.Date collides with another import statement. If You Really Need to Use Two Classes with the Same Name: import java.util.Date; public class Conflicts { Date date; java.sql.Date sqlDate; } Or you could have neither with an import and always use the fully qualified class name: public class Conflicts { java.util.Date date; java.sql.Date sqlDate; } |
Understanding Package Declarations and Import
Creating a New Package |
The directory structure on your computer is related to the package name. Suppose we have these two classes:
C:\temp\packagea\ClassA.java package packagea; public class ClassA { } C:\temp\packageb\ClassB.java package packageb; import packagea.ClassA; public class ClassB { public static void main(String[] args) { ClassA a; System.out.println("Got it"); } } When you run a Java program, Java knows where to look for those package names. In this case, running from C:\temp works because both packagea and packageb are underneath it. example: Create the two files: ■ C:\temp\packagea\ClassA.java ■ C:\temp\packageb\ClassB.java Then type this command: cd C:\temp To Compile Type this command: javac packagea/ClassA.java packageb/ClassB.java If the command does work, two new files will be created: packagea/ClassA.class and packageb/ClassB.class. To Run Type this command: java packageb.ClassB |
Understanding Package Declarations
and Imports Creating a New Package |
Class Paths and JARs
You can also specify the location of the other files explicitly using a class path. On Windows, you type the following: java -cp ".;C:\temp\someOtherLocation;c:\temp\myJar.jar" myPackage.MyClass And on Mac OS/Linux, you type this: java -cp ".:/tmp/someOtherLocation:/tmp/myJar.jar" myPackage.MyClass Windows uses semicolons to separate parts of the class path; other operating systems use colons. Finally, you can use a wildcard (*) to match all the JARs in a directory. Here’s an example: java -cp "C:\temp\directoryWithJars\*" myPackage.MyClass It won’t include any JARs in the class path that are in a subdirectory of directoryWithJars. |
Understanding Package Declarations
and Imports Code Formatting on the Exam |
Does it compile?
1: public class LineNumbers { 2: public void method(ArrayList list) { 3: if (list.isEmpty()) { System.out.println("e"); 4: } else { System.out.println("n"); 5: } } } For this one, you would answer “Does not compile.” Since the code begins with line 1, you don’t get to assume that valid imports were provided earlier. ArrayList is in java.util |
Creating Objects
|
Our programs wouldn’t be able to do anything useful if we didn’t have the ability to create new objects. Remember that an object is an instance of a class.
|
Creating Objects
Constructors |
To create an instance of a class, all you have to do is write new before it. For example:
Random r = new Random(); Random() looks like a method since it is followed by parentheses. It’s called a constructor, which is a special type of method that creates a new object. public class Chick { public Chick() { System.out.println("in constructor"); } } There are two key points to note about the constructor: the name of the constructor matches the name of the class, and there’s no return type. The purpose of a constructor is to initialize fields, although you can put any code in there. Another way to initialize fields is to do so directly on the line on which they’re declared. This example shows both approaches: public class Chicken { int numEggs = 0;// initialize on line String name; public Chicken() { name = "Duke";// initialize in constructor } } For most classes, you don’t have to code a constructor—the compiler will supply a “do nothing” default constructor for you. |
Creating Objects
Reading and Writing Object Fields |
It’s possible to read and write instance variables directly from the caller. In this example, a mother swan lays eggs:
public class Swan { int numberEggs;// instance variable public static void main(String[] args) { Swan mother = new Swan(); mother.numberEggs = 1; // set variable System.out.println(mother.numberEggs); // read variable } } Reading a variable is known as getting it.Writing to a variable is known as setting it You can even read and write fields directly on the line declaring them: 1: public class Name { 2: String first = "Theodore"; 3: String last = "Moose"; 4: String full = first + last; 5: { Lines 2 and 3 both write to fields. Line 4 does both. |
Creating Objects
Instance Initializer Blocks |
The code between the braces is called a code block.
Sometimes code blocks are inside a method. These are run when the method is called. Other times, code blocks appear outside a method. These are called instance initializers. How many blocks do you see in this example? How many instance initializers do you see? 3: public static void main(String[] args) { 4: { System.out.println("Feathers"); } 5: } 6: { System.out.println("Snowy"); } There are three code blocks and one instance initializer |
Creating Objects
Order of Initialization |
you need to remember:
■ Fields and instance initializer blocks are run in the order in which they appear in the file. ■ The constructor runs after all fields and instance initializer blocks have run. { System.out.println(name); } // DOES NOT COMPILE private String name = "Fluffy"; |
Distinguishing Between Object References and Primitives
|
Java applications contain two types of data: primitive types and reference types.
|
Distinguishing Between Object References and Primitives
Primitive Types |
Java has eight built-in data types, referred to as the Java primitive types.
TABLE 1.1 Java primitive types Keyword Type Example boolean true or false true byte 8-bit integral value 123 short 16-bit integral value 123 int 32-bit integral value 123 long 64-bit integral value 123 float 32-bit floating-point value 123.45f double 64-bit floating-point value 123.456 char 16-bit Unicode value 'a' Let’s look at some key points: ■ float and double are used for floating-point (decimal) values. ■ A float requires the letter f following the number so Java knows it is a float. ■ byte, short, int, and long are used for numbers without decimal points. ■ Each numeric type uses twice as many bits as the smaller similar type. For example, short uses twice as many bits as byte does. |
Distinguishing Between Object References and Primitives
Primitive Types |
The number of bits is used by Java when it figures out how much memory to reserve for your variable. For example, Java allocates 32 bits if you write this:
int num; What Is the Largest int?One way is to have Java tell us: System.out.println(Integer.MAX_VALUE); When a number is present in the code, it is called a literal. By default, Java assumes you are defining an int value with a literal. long max = 3123456789; // DOES NOT COMPILE Java complains the number is out of range. And it is—for an int. However, we don’t have an int. The solution is to add the character L to the number: long max = 3123456789L; // now Java knows it is a long Java allows you to specify digits in several other formats: ■ octal (digits 0–7), which uses the number 0 as a prefix—for example, 017 ■ hexadecimal (digits 0–9 and letters A–F), which uses the number 0 followed by x or X as a prefix—for example, 0xFF ■ binary (digits 0–1), which uses the number 0 followed by b or B as a prefix—for example, 0b10 |
Distinguishing Between Object References and Primitives
Primitive Types |
You can have underscores in numbers to make them easier to read:
int million1 = 1000000; int million2 = 1_000_000; You can add underscores anywhere except at the beginning of a literal, the end of a literal, right before a decimal point, or right after a decimal point. Let’s look at a few examples: double notAtStart = _1000.00; // DOES NOT COMPILE double notAtEnd = 1000.00_; // DOES NOT COMPILE double notByDecimal = 1000_.00; // DOES NOT COMPILE double annoyingButLegal = 1_00_0.0_0; // this one compiles |
Distinguishing Between Object References and Primitives
Reference Types |
A reference type refers to an object (an instance of a class).Unlike primitive types that hold their values in the memory where the variable is allocated, references do not hold the value of the object they refer to. Instead, a reference “points” to an object by storing the memory address where the object is located, a concept referred to as a pointer. Unlike other languages, Java does not allow you to learn what the physical memory address is. You can
only use the reference to refer to the object. java.util.Date today; String greeting; A value is assigned to a reference in one of two ways: ■ A reference can be assigned to another object of the same type. ■ A reference can be assigned to a new object using the new keyword. today = new java.util.Date(); greeting = "How are you?"; |
Distinguishing Between Object References and Primitives
Key Differences |
First, reference types can be assigned null, which means they do not currently refer to an object. Primitive types will give you a compiler error if you attempt to assign them null.
int value = null; // DOES NOT COMPILE String s = null; Next, reference types can be used to call methods when they do not point to null. Primitives do not have methods declared on them. String reference = "hello"; int len = reference.length(); int bad = len.length(); // DOES NOT COMPILE |
Declaring and Initializing Variables
|
A variable is a name for a piece of memory that stores
data. String zooName; int numberAnimals; Now that we’ve declared a variable, we can give it a value. This is called initializing a variable. To initialize a variable, you just type the variable name followed by an equal sign, followed by the desired value: zooName = "The Best Zoo"; numberAnimals = 100; Here we merge the declarations and initializations into more concise code: String zooName = "The Best Zoo"; int numberAnimals = 100; |
Declaring and Initializing Variables
Declaring Multiple Variables |
You can also declare and initialize multiple variables in the same statement.
You can declare many variables in the same declaration as long as they are all of the same type. You can also initialize any or all of those values inline. int num, String value; // DOES NOT COMPILE int i1, i2, i3 = 0; As you should expect, three variables were declared: i1, i2, and i3. However, only one of those values was initialized: i3. The other two remain declared but not yet initialized. boolean b1, b2; String s1 = "1", s2; double d1, double d2;// DOES NOT COMPILE int i1; int i2; int i3; i4;// DOES NOT COMPILE |
Declaring and Initializing Variables
Identifiers |
The same rules for identifiers apply to anything you are free to name, including variables, methods, classes, and fields.
There are only three rules to remember for legal identifiers: ■ The name must begin with a letter or the symbol $ or _. ■ Subsequent characters may also be numbers. ■ You cannot use the same name as a Java reserved word. As you might imagine, a reserved word is a keyword that Java has reserved so that you are not allowed to use it. Remember that Java is case sensitive, so you can use versions of the keywords that only differ in case. Please don’t, though. const and goto aren’t actually used in Java. abstract assert boolean break byte case catch char class const* continue default do double else enum extends false final finally float for goto* if implements import instanceof int interface long native new null package private protected public return short static strictfp super switch synchronized this throw throws transient true try void volatile while |
Declaring and Initializing Variables
Identifiers |
Most Java developers follow these conventions for identifier names:
■ Method and variables names begin with a lowercase letter followed by CamelCase. ■ Class names begin with an uppercase letter followed by CamelCase. Don’t start any identifi ers with $. The compiler uses this symbol for some files. |
Understanding Default Initialization of Variables
|
Before you can use a variable, it needs a value. Some types of variables get this value set automatically, and others require the programmer to specify it.
|
Understanding Default Initialization of Variables
Local Variables |
A local variable is a variable defined within a method. Local variables must be initialized before use. They do not have a default value and contain garbage data until initialized.
4: public int notValid() { 5: int y = 10; 6: int x; 7: int reply = x + y; // DOES NOT COMPILE 8: return reply; 9: } y is initialized to 10. However, because x is not initialized before it is used in the expression on line 7, the compiler generates the following error: Test.java:5: variable x might not have been initialized int reply = x + y; public void findAnswer(boolean check) { int answer; int onlyOneBranch; if (check) { onlyOneBranch = 1; answer = 1; } else { answer = 2; } System.out.println(answer); System.out.println(onlyOneBranch); // DOES NOT COMPILE } |
Understanding Default Initialization of Variables
Instance and Class Variables |
Variables that are not local variables are known as instance variables or class variables. Instance variables are also called fields. Class variables are shared across multiple objects.You can tell a variable is a class variable because it has the keyword static before it.
Instance and class variables do not require you to initialize them. It can give the value: null for an object and 0/false for a primitive. TABLE 1. 2 Default initialization values by type Variable type Default initialization value boolean false byte, short, int, long 0 (in the type’s bit-length) float, double 0.0 (in the type’s bit-length) char '\u0000' (NUL) All object references null (everything else) |
Understanding Default Initialization of Variables
Understanding Variable Scope |
Local variables can never have a scope larger than the method they are defined in.
public void eat(int piecesOfCheese) { int bitesOfCheese = 1; } There are two local variables in this method. 16: public void eatIfHungry(boolean hungry) { 17: if (hungry) { 18: int bitesOfCheese = 1; 19: { 20: boolean teenyBit = true; 21: System.out.println(bitesOfCheese); 22: } 23: } 24: System.out.println(teenyBit); // DOES NOT COMPILE 25: } All that was for local variables. Luckily the rule for instance variables is easier: they are available as soon as they are defi ned and last for the entire lifetime of the object itself. The rule for class (static) variables is even easier: they go into scope when declared like the other variables types. However, they stay in scope for the entire life of the program. |
Understanding Default Initialization of Variables
Understanding Variable Scope |
Let’s review the rules on scope:
■ Local variables—in scope from declaration to end of block ■ Instance variables—in scope from declaration until object garbage collected ■ Class variables—in scope from declaration until program ends |
Ordering Elements in a Class
|
Comments can go anywhere in the code.
Fields and methods must be within a class. Think of the acronym PIC (picture): package, import, and class. Multiple classes can be defined in the same file, but only one of them is allowed to be public. The public class matches the name of the file. A file is also allowed to have neither class be public. |
Destroying Objects
|
All Java objects are stored in your program memory’s heap. The heap, which is also referred to as the free store, represents a large pool of unused memory allocated to your Java application.
|
Destroying Objects
Garbage Collection |
You do need to know that System.gc() is not guaranteed to run, and you should be able to recognize when objects become eligible for garbage collection.
System.gc() , meekly suggests that now might be a good time for Java to kick off a garbage collection run. Java is free to ignore the request. An object will remain on the heap until it is no longer reachable. An object is no longer reachable when one of two situations occurs: ■ The object no longer has any references pointing to it. ■ All references to the object have gone out of scope. |
Destroying Objects
Objects vs. References |
Do not confuse a reference with the object that it refers to; they are two different entities.
The reference is a variable that has a name and can be used to access the contents of an object. A reference can be assigned to another reference, passed to a method, or returned from a method. All references are the same size, no matter what their type is. An object sits on the heap and does not have a name.Therefore, you have no way to access an object except through a reference. Objects come in all different shapes and sizes and consume varying amounts of memory. An object cannot be assigned to another object, nor can an object be passed to a method or returned from a method. It is the object that gets garbage collected, not its reference |
Destroying Objects
finalize() |
Java allows objects to implement a method called finalize() that might get called. This
method gets called if the garbage collector tries to collect the object. If the garbage collector doesn’t run, the method doesn’t get called. If the garbage collector fails to collect the object and tries to run it again later, the method doesn’t get called a second time. In practice, this means you are highly unlikely to use it in real projects. Luckily, there isn’t much to remember about finalize() for the exam. Just keep in mind that it might not get called and that it defi nitely won’t be called twice. |
Benefits of Java
|
Object Oriented: Java is an object-oriented language, which means all code is defined in classes and most of those classes can be instantiated into objects.
Encapsulation: Java supports access modifiers to protect data from unintended access and modifi cation. Platform Independent: Java is an interpreted language because it gets compiled to bytecode. A key benefit is that Java code gets compiled once rather than needing to be recompiled for different operating systems. This is known as “write once, run everywhere.” Robust: One of the major advantages of Java over C++ is that it prevents memory leaks. Java manages memory on its own and does garbage collection automatically. Bad memory management in C++ is a big source of errors in programs. Simple Java was intended to be simpler than C++. In addition to eliminating pointers, it got rid of operator overloading. In C++, you could write a + b and have it mean almost anything. |
Benefits of Java
|
Secure Java code runs inside the JVM. This creates a sandbox that makes it hard for Java code to do evil things to the computer it is running on.
|
Chapter 2:
Understanding Java Operators |
A Java operator is a special symbol that can be applied to a set of variables, values, or literals—referred to as operands—and that returns a result. Three fl avors of operators are available in Java: unary, binary, and ternary. These types of operators can be applied to one, two, or three operands, respectively.
Java operators are not necessarily evaluated from left-to-right order. For example, it is actually evaluated from right-to-left: int y = 4; double x = 3 + 2 * --y; In this example, you would fi rst decrement y to 3, and then multiply the resulting value by 2, and fi nally add 3. The value would then be automatically upcast from 9 to 9.0 and assigned to x. The final values of x and y would be 9.0 and 3, respectively. If two operators have the same level of precedence, then Java guarantees left-to-right evaluation. |
Working with Binary Arithmetic Operators
Arithmetic Operators |
Arithmetic operators are often encountered in early mathematics and include addition (+), subtraction (-), multiplication (*), division (/), and modulus (%). They also include the unary operators, ++ and --.
int x = 2 * 5 + 3 * 4 - 8; you first evaluate the 2 * 5 and 3 * 4, which reduces the expression to the following: int x = 10 + 12 - 8; All of the arithmetic operators may be applied to any Java primitives, except boolean and String. Furthermore, only the addition operators + and += may be applied to String values, which results in String concatenation. For a given divisor y, the modulus operation results in a value between 0 and (y - 1) for positive dividends and between (-y + 1) and 0 for negative dividends. |
Working with Binary Arithmetic Operators
Numeric Promotion |
Numeric Promotion Rules
1. If two values have different data types, Java will automatically promote one of the values to the larger of the two data types. 2. If one of the values is integral and the other is floating-point, Java will automatically promote the integral value to the floating-point value’s data type. 3. Smaller data types, namely byte, short, and char, are first promoted to int any time they’re used with a Java binary arithmetic operator, even if neither of the operands is int. 4. After all promotion has occurred and the operands have the same data type, the resulting value will have the same data type as its promoted operands. For the third rule, note that unary operators are excluded from this rule. For example, applying ++ to a short value results in a short value. |
Working with Unary Operators
|
By definition, a unary operator is one that requires exactly one operand, or variable, to function
|
Working with Unary Operators
Logical Complement and Negation Operators |
The logical complement operator, !, flips the value of a boolean expression. For example, if the value is true, it will be converted to false, and vice versa.
boolean x = false; System.out.println(x); // false x = !x; System.out.println(x); // true Error: int x = !5; // DOES NOT COMPILE boolean y = -true; // DOES NOT COMPILE boolean z = !0; // DOES NOT COMPILE Unlike some other programming languages, in Java 1 and true are not related in any way, just as 0 and false are not related. |
Working with Unary Operators
Increment and Decrement Operators |
Increment and decrement operators, ++ and --, respectively, can be applied to numeric operands and have the higher order or precedence, as compared to binary operators. In other words, they often get applied first to an expression.
int counter = 0; System.out.println(counter); // Outputs 0 System.out.println(++counter); // Outputs 1 System.out.println(counter); // Outputs 1 System.out.println(counter--); // Outputs 1 System.out.println(counter); // Outputs 0 example: int x = 3; int y = ++x * 5 / x-- + --x; System.out.println("x is " + x); System.out.println("y is " + y); So how do you read this code? |
Working with Unary Operators
Increment and Decrement Operators |
First, the x is incremented and returned to the expression,
which is multiplied by 5. We can simplify this: int y = 4 * 5 / x-- + --x; // x assigned value of 4 Next, x is decremented, but the original value of 4 is used in the expression, leading to this: int y = 4 * 5 / 4 + --x; // x assigned value of 3 The fi nal assignment of x reduces the value to 2, and since this is a pre-increment operator, that value is returned to the expression: int y = 4 * 5 / 4 + 2; // x assigned value of 2 Finally, we evaluate the multiple and division from left-to-right, and fi nish with the addition. The result is then printed: x is 2 y is 7 |
Using Additional Binary Operators
Assignment Operators |
An assignment operator is a binary operator that modifi es, or assigns, the variable on the left-hand side of the operator, with the result of the value on the right-hand side of the equation. Example:
int x=1; Java will automatically promote from smaller to larger data types, as we saw in the previous section on arithmetic operators, but it will throw a compiler exception if it detects you are trying to convert from larger to smaller data types. int x = 1.0; // DOES NOT COMPILE short y = 1921222; // DOES NOT COMPILE int z = 9f; // DOES NOT COMPILE long t = 192301398193810323; // DOES NOT COMPILE solution: int x = (int)1.0; short y = (short)1921222; // Stored as 20678 int z = (int)9l; long t = 192301398193810323L; example 2: System.out.print(2147483647+1); // -2147483648 short x = 10; short y = 3; short z = x * y; // DOES NOT COMPILE short z = (short)(x * y);// COMPILE |
Using Additional Binary Operators
Compound Assignment Operators |
int x = 2, z = 3;
x = x * z; // Simple assignment operator x *= z; // Compound assignment operator The left-hand side of the compound operator can only be applied to a variable that is already defined and cannot be used to declare a new variable. In the previous example, if x was not already defi ned, then the expression x *= z would not compile. Compound operators are useful for more than just shorthand—they can also save us from having to explicitly cast a value. For example, consider the following example, in which the last line will not compile due to the result being promoted to a long and assigned to an int variable: example: long x = 10; int y = 5; y = y * x; // DOES NOT COMPILE solution: long x = 10; int y = 5; y *= x;//cast implicity |
Using Additional Binary Operators
Compound Assignment Operators |
One final thing to know about the assignment operator is that the result of the assignment is an expression in and of itself, equal to the value of the assignment. For example:
long x = 5; long y = (x=3); System.out.println(x); // Outputs 3 System.out.println(y); // Also, outputs 3 The key here is that (x=3) does two things. First, it sets the value of the variable x to be 3. Second, it returns a value of the assignment, which is also 3. example: int x = 3; int y = ++x + 5 +(x=6) + (x-- * --x); int z = 4 + 5 + 6 + 6 * 4; System.out.println("x is " + x); System.out.println("y is " + y); System.out.println("z is " + z); x is 4 y is 39 z is 39 |
Using Additional Binary Operators
Relational Operators |
If the two numeric operands are not of the same data type, the smaller one is promoted in the manner as previously discussed.
int x = 10, y = 20, z = 10; System.out.println(x < y); // Outputs true System.out.println(x <= y); // Outputs true System.out.println(x >= z); // Outputs true System.out.println(x > z); // Outputs false |
Using Additional Binary Operators
Relational Operators |
The instanceof operator, while useful for determining whether an arbitrary object is a member of a particular class or interface, is out of scope for the OCA exam.
|
Using Additional Binary Operators
Logical Operators |
The logical operators, (&), (|), and (^), may be applied to both numeric and boolean data types. When they’re applied to boolean data types, they’re referred to as logical operators. Alternatively, when they’re applied to numeric data types, they’re referred to as bitwise operators, as they perform bitwise comparisons of the bits that compose the number.
Finally, we present the conditional operators, && and ||, which are often referred to as short-circuit operators. The short-circuit operators are nearly identical to the logical operators, & and |, respectively, except that the right-hand side of the expression may never be evaluated if the fi nal result can be determined by the left-hand side of the expression. int x = 6; boolean y = (x >= 6) || (++x <= 7); System.out.println(x); Because x >= 6 is true, the increment operator on the right-hand side of the expression is never evaluated, so the output is 6. |
Using Additional Binary Operators
Equality Operators |
Determining equality in Java can be a nontrivial endeavor as there’s a semantic difference between “two objects are the same” and “two objects are equivalent.” It is further complicated by the fact that for numeric and boolean primitives, there is no such distinction.
The equality operators are used in one of three scenarios: 1. Comparing two numeric primitive types. If the numeric values are of different data types, the values are automatically promoted as previously described. For example,5 == 5.00 returns true since the left side is promoted to a double. 2. Comparing two boolean values. 3. Comparing two objects, including null and String values. examples: boolean x = true == 3; // DOES NOT COMPILE boolean y = false != "Giraffe"; // DOES NOT COMPILE boolean z = 3 == "Kangaroo"; // DOES NOT COMPILE boolean y = false; boolean x = (y = true); System.out.println(x); // Outputs true |
Using Additional Binary Operators
Equality Operators |
For object comparison, the equality operator is applied to the references to the objects, not the objects they point to. Two references are equal if and only if they point to the same object, or both point to null. Let’s take a look at some examples:
File x = new File("myFile.txt"); File y = new File("myFile.txt"); File z = x; System.out.println(x == y); // Outputs false System.out.println(x == z); // Outputs true |
Understanding Java Statements
|
A Java statement is a complete unit of execution in
Java, terminated with a semicolon (;). Control flow statements break up the flow of execution by using decision making, looping, and branching, allowing the application to selectively execute particular segments of code. These statements can be applied to single expressions as well as a block of Java code. A block of code in Java is a group of zero or more statements between balanced braces, ({}), and can be used anywhere a single statement is allowed. |
Understanding Java Statements
The if-then Statement |
if(hourOfDay < 11)
System.out.println("Good Morning");//only going to be incremented if the hourOfDay is less than 11, morningGreetingCount++;//always execute the increment operation. Remember that in Java, unlike some other programming languages, tabs are just whitespace and are not evaluated as part of the execution. |
Understanding Java Statements
The if-then-else Statement |
if(hourOfDay < 11) {
System.out.println("Good Morning"); } else if(hourOfDay < 15) { System.out.println("Good Afternoon"); } else { System.out.println("Good Evening"); } if(hourOfDay < 15) { System.out.println("Good Afternoon"); } else if(hourOfDay < 11) { System.out.println("Good Morning"); // UNREACHABLE CODE } else { System.out.println("Good Evening"); } int x = 1; if(x) { // DOES NOT COMPILE ... } in Java, 0 and 1 are not considered boolean values. int x = 1; if(x = 5) { // DOES NOT COMPILE ... } |
Understanding Java Statements
Ternary Operator |
The conditional operator, ? :, otherwise known as the ternary operator, is the only operator that takes three operands and is of the form:
booleanExpression ? expression1 : expression2 The parentheses around the expressions in ternary operations, although it is certainly not required. There is no requirement that second and third expressions in ternary operations have the same data types, although it may come into play when combined with the assignment operator. System.out.println((y > 5) ? 21 : "Zebra");// COMPILE int animal = (y < 91) ? 9 : "Horse"; // DOES NOT COMPILE As of Java 7, only one of the right-hand expressions of the ternary operator will be evaluated at runtime. int y = 1; int z = 1; final int x = y<10 ? y++ : z++; System.out.println(y+","+z); // Outputs 2,1 |
Understanding Java Statements
The switch Statement |
A switch statement, is a complex decision-making structure in which a single value is evaluated and fl ow is redirected to the fi rst matching branch, known as a case statement. If no such case statement is found that matches the value, an optional default statement will be called. If no such default option is available, the entire switch statement will be skipped.
Data types supported by switch statements include the following: ■ int and Integer ■ byte and Byte ■ short and Short ■ char and Character ■ String ■ enum values Note that boolean and long, and their associated wrapper classes, are not supported by switch statements. The data type for case statements must all match the data type of the switch variable. The case statement value must also be a literal, enum constant, or final constant variable. |
Understanding Java Statements
The switch Statement |
private int getSortOrder(String firstName, final String lastName) {
String middleName = "Patricia"; final String suffix = "JR"; int id = 0; switch(firstName) { case "Test": return 52; case middleName: // DOES NOT COMPILE id = 5; break; case suffix: id = 0; break; case lastName: // DOES NOT COMPILE id = 8; break; case 5: // DOES NOT COMPILE id = 7; break; case 'J': // DOES NOT COMPILE id = 10; break; case java.time.DayOfWeek.SUNDAY: // DOES NOT COMPILE id=15; break; } return id; } |
Understanding Java Statements
The while Statement |
It is important to note that a while loop may terminate after its fi rst evaluation of the boolean expression. In this manner, the statement block may never be executed.
|
Understanding Java Statements
The do-while Statement |
Unlike a while loop, though, a do-while loop guarantees that the statement or block will be executed at least once.
|
Understanding Java Statements
The for Statement |
Starting in Java 5.0, there are now two types of for statements. The fi rst is referred to asthe basic for loop, and the second is often called the enhanced for loop.
|
Understanding Java Statements
The for Statement The Basic for Statement |
1. Creating an Infinite Loop
for( ; ; ) { System.out.println("Hello World"); } This example reinforces the fact that the components of the for loop are each optional. Note that the semicolons separating the three sections are required, as for( ; ) and for( ) will not compile. 2. Adding Multiple Terms to the for Statement int x = 0; for(long y = 0, z = 4; x < 5 && y < 10; x++, y++) { System.out.print(y + " "); } System.out.print(x); you can declare a variable, such as x in this example, before the loop begins and use it after it completes. Second, your initialization block, boolean expression, and update statements can include extra variables that may not reference each other. For example, z is defined in the initialization block and is never used. Finally, the update statement can modify multiple variables. This code will print the following when executed: 0 1 2 3 4 |
Understanding Java Statements
The for Statement The Basic for Statement |
3. Redeclaring a Variable in the Initialization Block
int x = 0; for(long y = 0, x = 4; x < 5 && y < 10; x++, y++) { // DOES NOT COMPILE System.out.print(x + " "); } We can fix this loop by changing the declaration of x and y as follows: int x = 0; long y = 10; for(y = 0, x = 4; x < 5 && y < 10; x++, y++) { System.out.print(x + " "); } Note that this variation will now compile because the initialization block simply assigns a value to x and does not declare it. 4. Using Incompatible Data Types in the Initialization Block for(long y = 0, int x = 4; x < 5 && y<10; x++, y++) { // DOES NOT COMPILE System.out.print(x + " "); } y and z have differing types, so the code will not compile 5. Using Loop Variables Outside the Loop for(long y = 0, x = 4; x < 5 && y < 10; x++, y++) { System.out.print(y + " "); } System.out.print(x); // DOES NOT COMPILE Since x was only scoped for the loop, using it outside the loop will throw a compiler error. |
Understanding Java Statements
The for Statement The for-each Statement |
The for-each loop declaration is composed of an initialization section and an object to be iterated over. The right-hand side of the for-each loop statement must be a built-in Java array or an object whose class implements java.lang.Iterable, which includes most of the Java Collections framework. The left-hand side of the for-each loop must include a
declaration for an instance of a variable, whose type matches the type of a member of the array or collection in the right-hand side of the statement. On each iteration of the loop, the named variable on the left-hand side of the statement is assigned a new value from the array or collection on the right-hand side of the statement. examples: String names = "Lisa"; for(String name : names) { // DOES NOT COMPILE System.out.print(name + " "); } In this example, the String names is not an array, nor does it implement java.lang.Iterable, so the compiler will throw an exception since it does not know how to iterate over the String. |
Understanding Java Statements
The for Statement The for-each Statement |
String[] names = new String[3];
for(int name : names) { // DOES NOT COMPILE System.out.print(name + " "); } This code will fail to compile because the left-hand side of the for-each statement does not defi ne an instance of String. Notice that in this last example, the array is initialized with three null pointer values. In and of itself, that will not cause the code to not compile, as a corrected loop would just output null three times. for(int value : values) { System.out.print(value + ", "); } for(java.util.Iterator<Integer> i = values.iterator(); i.hasNext(); ) { int value = i.next(); System.out.print(value + ", "); } for(String name : names) { System.out.print(name + ", "); } for(int i=0; i < names.length; i++) { String name = names[i]; System.out.print(name + ", "); } |
Understanding Advanced Flow Control
Nested Loops |
First off, loops can contain other loops.Nested loops can include while and do-while.
int[][] myComplexArray = {{5,2,1,3},{3,9,8,9},{5,7,12,7}}; for(int[] mySimpleArray : myComplexArray) { for(int i=0; i<mySimpleArray.length; i++) { System.out.print(mySimpleArray[i]+"\t"); } System.out.println(); } 5 2 1 3 3 9 8 9 5 7 12 7 int x = 20; while(x>0) { do { x -= 2 } while (x>5); x--; System.out.print(x+"\t"); } 3 0 |
Understanding Advanced Flow Control
Adding Optional Labels |
One thing we skipped when we presented if-then statements, switch statements, and loops is that they can all have optional labels. A label is an optional pointer to the head of a statement that allows the application flow to jump to it or break from it. It is a single word that is proceeded by a colon (:).
labels are not allowed for methods. For formatting, labels follow the same rules for identifi ers. For readability, they are commonly expressed in uppercase, with underscores between words, to distinguish them from regular variables. example: int[][] myComplexArray = {{5,2,1,3},{3,9,8,9},{5,7,12,7}}; OUTER_LOOP: for(int[] mySimpleArray : myComplexArray) { INNER_LOOP: for(int i=0; i<mySimpleArray.length; i++) { System.out.print(mySimpleArray[i]+"\t"); } System.out.println(); } |
Understanding Advanced Flow Control
The break Statement |
A break statement transfers the flow of control out to the enclosing statement.
Without a label parameter, the break statement will terminate the nearest inner loop it is currently in the process of executing. |
Understanding Advanced Flow Control
The continue Statement |
The continue statement, is a statement that causes flow to finish the execution of the current loop.
While the break statement transfers control to the enclosing statement, the continue statement transfers control to the boolean expression that determines if the loop should continue. In other words, it ends the current iteration of the loop. Also like the break statement, the continue statement is applied to the nearest inner loop under execution using optional label statements to override this behavior. |
chapter 3 : Core Java APIs
|
API stands for application programming interface. In Java, an interface is something special. In the context of an API, it can be a group of class or interface defi nitions that gives you access to a service or functionality.
|
Creating and Manipulating Strings
|
A string is basically a sequence of characters.
String name = "Fluffy"; String name = new String("Fluffy"); Both give you a reference variable of type name pointing to the String object "Fluffy". They are subtly different, just remember that the String class is special and doesn’t need to be instantiated with new. |
Creating and Manipulating Strings
Concatenation |
Placing one String before the other String and combining them together is called string concatenation.
rules: 1. If both operands are numeric, + means numeric addition. 2. If either operand is a String, + means oncatenation. 3. The expression is evaluated left to right. examples: System.out.println(1 + 2); // 3 System.out.println("a" + "b"); // ab System.out.println("a" + "b" + 3); // ab3 System.out.println(1 + 2 + "c"); // 3c remember what += does. s += "2" means the same thing as s = s + "2". 4: String s = "1"; // s currently holds "1" 5: s += "2"; // s currently holds "12" 6: s += 3; // s currently holds "123" 7: System.out.println(s); // 123 |
Creating and Manipulating Strings
Immutability |
Once a String object is created, it is not allowed to change. It cannot be made larger or smaller, and you cannot change one of the characters inside it.
Mutable is another word for changeable. Immutable is the opposite—an object that can’t be changed once it’s created.You need to know that String is immutable. class Mutable { private String s; public void setS(String newS){ s = newS; } // Setter makes it mutable public String getS() { return s; } } final class Immutable { private String s = "name"; public String getS() { return s; } } Immutable only has a getter. There's no way to change the value of s once it's set. Mutable has a setter as well. This allows the reference s to change to point to a different String later. |
Creating and Manipulating Strings
The String Pool |
The string pool, also known as the intern pool, is a location in the Java virtual machine (JVM) that collects all these strings.
The string pool contains literal values that appear in your program. For example, “name” is a literal and therefore goes into the string pool. myObject.toString() is a string but not a literal, so it does not go into the string pool. Strings not in the string pool are garbage collected just like any other object. String name = "Fluffy";//lo coloca en String pool String name = new String("Fluffy");//lo considera como cualquier objeto y lo coloca en el heap |
Creating and Manipulating Strings
Important String Methods |
The String class has dozens of methods and you need to remember that a string is a sequence of characters and Java counts from 0 when indexed.
length(): returns the number of characters in the String.Signature: int length().Example: String string = "animals"; System.out.println(string.length()); // 7 charAt(): lets you query the string to find out what character is at a specific index. Signature: char charAt(int index). Example: String string = "animals"; System.out.println(string.charAt(0)); // a System.out.println(string.charAt(6)); // s System.out.println(string.charAt(7)); // throws exception since indexes start counting with 0. indexOf(): looks at the characters in the string and finds the first index that matches the desired value.signatures: int indexOf(char ch) int indexOf(char ch, index fromIndex) int indexOf(String str) int indexOf(String str, index fromIndex) String string = "animals"; System.out.println(string.indexOf('a')) |
Creating and Manipulating Strings
Important String Methods |
indexOf(): looks at the characters in the string and finds the first index that matches the desired value.signatures:
int indexOf(char ch) int indexOf(char ch, index fromIndex) int indexOf(String str) int indexOf(String str, index fromIndex) examples: String string = "animals"; System.out.println(string.indexOf('a')); // 0 System.out.println(string.indexOf("al")); // 4 System.out.println(string.indexOf('a', 4)); // 4 System.out.println(string.indexOf("al", 5)); // -1 indexOf() returns –1 when no match is found. |
Creating and Manipulating Strings
Important String Methods |
substring(): returns parts of the string.signatures:
String substring(int beginIndex) String substring(int beginIndex, int endIndex)//second parameter is the end index you want to stop at,therefore.Notice we said “stop at” rather than “include.” This means the endIndex parameter is allowed to be 1 past the end of the sequence if you want to stop at the end of the sequence. Example: String string = "animals"; System.out.println(string.substring(3)); // mals System.out.println(string.substring(string.indexOf('m'))); // mals System.out.println(string.substring(3, 4)); // m System.out.println(string.substring(3, 3)); // empty string System.out.println(string.substring(3, 2)); // throws exception System.out.println(string.substring(3, 7)); // mals System.out.println(string.substring(3, 8)); // throws exception,Granted, there is no seventh character either, but at least there is the “end of string” invisible position. |
Creating and Manipulating Strings
Important String Methods |
toLowerCase() and toUpperCase():signatures:
String toLowerCase(String str) String toUpperCase(String str) examples: String string = "animals"; System.out.println(string.toUpperCase()); // ANIMALS System.out.println("Abc123".toLowerCase()); // abc123 Remember that strings are immutable, so the original string stays the same. equals() and equalsIgnoreCase(): The equals() method checks whether two String objects contain exactly the same characters in the same order. The equalsIgnoreCase() method checks whether two String objects contain the same characters with the exception that it will convert the characters’ case if needed.signatures: boolean equals(String str) boolean equalsIgnoreCase(String str) examples: System.out.println("abc".equals("ABC")); // false System.out.println("ABC".equals("ABC")); // true System.out.println("abc".equalsIgnoreCase("ABC")); // true |
Creating and Manipulating Strings
Important String Methods |
startsWith() and endsWith(): The startsWith() and endsWith() methods look at whether the provided value matches part of the String. signatures:
boolean startsWith(String prefix) boolean endsWith(String suffix) examples: System.out.println("abc".startsWith("a")); // true System.out.println("abc".startsWith("A")); // false System.out.println("abc".endsWith("c")); // true System.out.println("abc".endsWith("a")); // false contains(): also looks for matches in the String. signature: boolean contains(String str) examples: System.out.println("abc".contains("b")); // true System.out.println("abc".contains("B")); // false replace(): does a simple search and replace on the string. signature: String replace(char oldChar, char newChar) String replace(CharSequence oldChar, CharSequence newChar) examples: System.out.println("abcabc".replace('a', 'A')); // AbcAbc System.out.println("abcabc".replace("a", "A")); // AbcAbc String implements CharSequence. |
Creating and Manipulating Strings
Important String Methods |
trim(): removes whitespace from the beginning and end of a String. whitespace consists of spaces along with the \t (tab) and \n (newline) characters. Other characters, such as \r (carriage return), are also included in what gets trimmed.signature:
public String trim() examples: System.out.println("abc".trim()); // abc System.out.println("\t a b c\n".trim()); // a b c |
Creating and Manipulating Strings
Method Chaining |
example:
String start = "AniMaL "; String trimmed = start.trim(); // "AniMaL" String lowercase = trimmed.toLowerCase(); // "animal" String result = lowercase.replace('a', 'A'); // "Animal" System.out.println(result); There are four String values along the way, and Animal is output. String result = "AniMaL ".trim().toLowerCase().replace('a', 'A'); System.out.println(result); This code is equivalent to the previous example. It also creates four String objects and outputs Animal. |
Using the StringBuilder Class
|
10: String alpha = "";
11: for(char current = 'a'; current <= 'z'; current++) 12: alpha += current; 13: System.out.println(alpha); A total of 27 objects are instantiated, most of which are immediately eligible for garbage collection.This is very inefficient. Luckily, Java has a solution. The StringBuilder class creates a String without storing all those interim String values. Unlike the String class, StringBuilder is not immutable. 15: StringBuilder alpha = new StringBuilder(); 16: for(char current = 'a'; current <= 'z'; current++) 17: alpha.append(current); 18: System.out.println(alpha); This code reuses the same StringBuilder without creating an interim String each time. |
Using the StringBuilder Class
Mutability and Chaining |
When we chained String method calls, the result was a new String with the answer. Chaining StringBuilder objects doesn’t work this way. Instead, the StringBuilder changes its own state and returns a reference to itself!
example: 4: StringBuilder sb = new StringBuilder("start"); 5: sb.append("+middle"); // sb = "start+middle" 6: StringBuilder same = sb.append("+end"); // "start+middle+end" Line 5 adds text to the end of sb. It also returns a reference to sb, which is ignored. Line 6 also adds text to the end of sb and returns a reference to sb. This time the reference is stored in same—which means sb and same point to the exact same object and would print out the same value. |
Using the StringBuilder Class
Creating a StringBuilder |
There are three ways to construct a StringBuilder:
StringBuilder sb1 = new StringBuilder(); StringBuilder sb2 = new StringBuilder("animal"); StringBuilder sb3 = new StringBuilder(10); The first says to create a StringBuilder containing an empty sequence of characters and assign sb1 to point to it. The second says to create a StringBuilder containing a specific value and assign sb2 to point to it. For the fi rst two, it tells Java to manage the implementation details. The final example tells Java that we have some idea of how big the eventual value will be and would like the StringBuilder to reserve a certain number of slots for characters. Size vs. Capacity Size is the number of characters currently in the sequence, and capacity is the number of characters the sequence can currently hold.Since a String is immutable, the size and capacity are the same. The number of characters appearing in the String is both the size and capacity.the default capacity is 16. |
Using the StringBuilder Class
Important StringBuilder Methods |
charAt(), indexOf(), length(), and substring(): These four methods work exactly the same as in the String class.example:
StringBuilder sb = new StringBuilder("animals"); String sub = sb.substring(sb.indexOf("a"), sb.indexOf("al")); int len = sb.length(); char ch = sb.charAt(6); System.out.println(sub + " " + len + " " + ch); The correct answer is anim 7 s. Notice that substring() returns a String rather than a StringBuilder. That is why sb is not changed. substring() is really just a method that inquires about where the substring happens to be. append(): does just what it sounds like: it adds the parameter to the StringBuilder and returns a reference to the current StringBuilder.signature: StringBuilder append(String str). There are more than 10 method signatures that look similar but that take different data types as parameters.example: StringBuilder sb = new StringBuilder().append(1).append('c'); sb.append("-").append(true); System.out.println(sb); // 1c-true |
Using the StringBuilder Class
Important StringBuilder Methods |
insert(): adds characters to the StringBuilder at the requested index and returns a reference to the current StringBuilder.Just like append(), there are lots of method signatures for different types. Here’s one:
StringBuilder insert(int offset, String str) Example: 3: StringBuilder sb = new StringBuilder("animals"); 4: sb.insert(7, "-"); // sb = animals- 5: sb.insert(0, "-"); // sb = -animals- 6: sb.insert(4, "-"); // sb = -ani-mals 7: System.out.println(sb); delete() and deleteCharAt():The delete() method removes characters from the sequence and returns a reference to the current StringBuilder. The deleteCharAt() method is convenient when you want to delete only one character.signatures: StringBuilder delete(int start, int end) StringBuilder deleteCharAt(int index) example: StringBuilder sb = new StringBuilder("abcdef"); sb.delete(1, 3); // sb = adef sb.deleteCharAt(5); // throws an exception |
Using the StringBuilder Class
Important StringBuilder Methods |
reverse(): does just what it sounds like: it reverses the characters in the sequences and returns a reference to the current StringBuilder.signature:
StringBuilder reverse() StringBuilder sb = new StringBuilder("ABC"); sb.reverse(); System.out.println(sb); As expected, this prints CBA. toString(): converts a StringBuilder into a String.signature: String toString() example: String s = sb.toString(); |
Using the StringBuilder Class
StringBuilder vs. StringBuffer |
When writing new code that concatenates a lot of String objects together, you should use StringBuilder. StringBuilder was added to Java in Java 5. If you come across older code, you will see StringBuffer used for this purpose. StringBuffer does the same thing but more slowly because it is thread safe.
|
Understanding Equality
|
StringBuilder one = new StringBuilder();
StringBuilder two = new StringBuilder(); StringBuilder three = one.append("a"); System.out.println(one == two); // false System.out.println(one == three); // true String x = "Hello World"; String y = "Hello World"; System.out.println(x == y); // true String x = "Hello World"; String z = " Hello World".trim(); System.out.println(x == z); // false In this example, we don’t have two of the same String literal. Although x and z happen to evaluate to the same string, one is computed at runtime. Since it isn’t the same at compile-time, a new String object is created. You can even force the issue by creating a new String: String x = new String("Hello World"); String y = "Hello World"; System.out.println(x == y); // false Since you have specifically requested a different String object, the pooled value isn’t shared. The lesson is to never use == to compare String objects. |
Understanding Equality
|
String x = "Hello World";
String z = " Hello World".trim(); System.out.println(x.equals(z)); // true If a class doesn’t have an equals method, Java determines whether the references point to the same object—which is exactly what == does. In case you are wondering, the authors of StringBuilder did not implement equals(). If you call equals() on two StringBuilder instances, it will check reference equality. 1: public class Tiger { 2: String name; 3: public static void main(String[] args) { 4: Tiger t1 = new Tiger(); 5: Tiger t2 = new Tiger(); 6: Tiger t3 = t1; 7: System.out.println(t1 == t1); // true 8: System.out.println(t1 == t2); // false 9: System.out.println(t1.equals(t2)); // false 10: } } String x = "Hello World"; String z = "Hello World".trim();//no blank spaces System.out.println(x == z); // true |
Understanding Java Arrays
|
An array is an area of memory on the heap with space for a designated number of elements. An array can be of any other Java type.An array is an ordered list. It can contain duplicates.
|
Understanding Java Arrays
Creating an Array of Primitives |
int[] numbers1 = new int[3];
When using this form to instantiate an array, set all the elements to the default value for that type. int[] numbers2 = new int[] {42, 55, 99}; This time, we specify the initial values of those three elements instead of using the defaults. As a shortcut, Java lets you write this: int[] numbers2 = {42, 55, 99}; This approach is called an anonymous array. You can type the [] before or after the name, and adding a space is optional. int[] numAnimals; int [] numAnimals2; int numAnimals3[]; int numAnimals4 []; |
Understanding Java Arrays
Creating an Array with Reference Variables |
public class ArrayType {
public static void main(String args[]) { String [] bugs = { "cricket", "beetle", "ladybug" }; String [] alias = bugs; System.out.println(bugs.equals(alias)); // true System.out.println(bugs.toString()); // [Ljava.lang.String;@160bc7c0 } } We can call equals() because an array is an object.It returns true because of reference equality. The equals() method on arrays does not look at the elements of the array. Since Java 5, Java has provided a method that prints an array nicely: java.util.Arrays.toString(bugs) would print [cricket, beetle, ladybug]. class Names { String names[];//it is just a reference variable to null. } class Names { String names[] = new String[2];//It has two elements because the length is 2. Each of those two slots currently is null, but has the potential to point to a String object. } |
Understanding Java Arrays
Creating an Array with Reference Variables |
3: String[] strings = { "stringValue" };
4: Object[] objects = strings; 5: String[] againStrings = (String[]) objects; 6: againStrings[0] = new StringBuilder(); // DOES NOT COMPILE 7: objects[0] = new StringBuilder(); // careful! At runtime, the code throws an ArrayStoreException |
Understanding Java Arrays
Using an Array |
4: String[] mammals = {"monkey", "chimp", "donkey"};
5: System.out.println(mammals.length); // 3 6: System.out.println(mammals[0]); // monkey 7: System.out.println(mammals[1]); // chimp 8: System.out.println(mammals[2]); // donkey 5: int[] numbers = new int[10]; 6: for (int i = 0; i < numbers.length; i++) 7: numbers[i] = i + 5; numbers[10] = 3;//throws an ArrayIndexOutOfBoundsException numbers[numbers.length] = 5;//throws an ArrayIndexOutOfBoundsException for (int i = 0; i <= numbers.length; i++) numbers[i] = i + 5;//throws an ArrayIndexOutOfBoundsException |
Understanding Java Arrays
Sorting |
Just like StringBuilder allowed you to pass almost anything to append(), you can pass almost any array to Arrays.sort(). Arrays is the first class provided by Java we have used that requires an import. To use it,
you must have either of the following two statements in your class: import java.util.* // import whole package including Arrays import java.util.Arrays; // import just Arrays int[] numbers = { 6, 9, 1 }; Arrays.sort(numbers); for (int i = 0; i < numbers.length; i++) L System.out.print (numbers[i] + " "); The result is 1 6 9 String[] strings = { "10", "9", "100" }; Arrays.sort(strings); for (String string : strings) System.out.print(string + " "); This code outputs 10 100 9. The problem is that String sorts in alphabetic order, and 1 sorts before 9. (Numbers sort before letters and uppercase sorts before lowercase, in case you were wondering.) |
Understanding Java Arrays
Searching |
3: int[] numbers = {2,4,6,8};
4: System.out.println(Arrays.binarySearch(numbers, 2)); // 0 5: System.out.println(Arrays.binarySearch(numbers, 4)); // 1 6: System.out.println(Arrays.binarySearch(numbers, 1)); // -1 7: System.out.println(Arrays.binarySearch(numbers, 3)); // -2 8: System.out.println(Arrays.binarySearch(numbers, 9)); // -5 |
Understanding Java Arrays
Varargs |
public static void main(String[] args)
public static void main(String args[]) public static void main(String... args) // varargs The third example uses a syntax called varargs (variable arguments),args.length and args[0] are legal for varargs. |
Understanding Java Arrays
Multidimensional Arrays |
int[][] vars1; // 2D array
int vars2 [][]; // 2D array int[] vars3[]; // 2D array int[] vars4 [], space [][]; // a 2D AND a 3D array You can specify the size of your multidimensional array in the declaration if you like: String [][] rectangle = new String[3][2]; rectangle[0][1] = "set"; |
Understanding Java Arrays
Multidimensional Arrays |
An array doesn’t need to be rectangular in shape. Consider this one:
int[][] differentSize = {{1, 4}, {3}, {9,8,7}}; Another way to create an asymmetric array is to initialize just an array’s first dimension, and define the size of each array component in a separate statement: int [][] args = new int[4][]; args[0] = new int[5]; args[1] = new int[3]; This technique reveals what you really get with Java: arrays of arrays that, properly managed, offer a multidimensional effect. |
Using a Multidimensional Array
Multidimensional Arrays |
int[][] twoD = new int[3][2];
for (int i = 0; i < twoD.length; i++) { for (int j = 0; j < twoD[i].length; j++) System.out.print(twoD[i][j] + " "); // print element System.out.println(); // time for a new row } for (int[] inner : twoD) { for (int num : inner) System.out.print(num + " "); System.out.println(); } |
Understanding an ArrayList
|
An array has one glaring shortcoming: you have to know how many elements will be in the array when you create it and then you are stuck with that choice. Just like a StringBuilder, ArrayList can change size at runtime as needed. Like an array, an ArrayList is an ordered sequence that allows duplicates.
import java.util.* // import whole package including ArrayList import java.util.ArrayList; // import just ArrayList |
Understanding an ArrayList
Creating an ArrayList |
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList(10); ArrayList list3 = new ArrayList(list2); The fi rst says to create an ArrayList containing space for the default number of elements but not to fill any slots yet. The second says to create an ArrayList containing a specific number of slots, but again not to assign any. The final example tells Java that we want to make a copy of another ArrayList. We copy both the size and contents of that ArrayList. Granted, list2 is empty in this example so it isn’t particularly interesting. The previous examples were the old pre–Java 5 way of creating an ArrayList. Java 5 introduced generics, which allow you to specify the type of class that the ArrayList will contain: ArrayList<String> list4 = new ArrayList<String>(); ArrayList<String> list5 = new ArrayList<>();//Starting in Java 7, you can even omit that type from the right side. |
Understanding an ArrayList
Creating an ArrayList |
ArrayList implements an interface called List. In other
words, an ArrayList is a List. List<String> list6 = new ArrayList<>(); ArrayList<String> list7 = new List<>(); // DOES NOT COMPILE |
Understanding an ArrayList
Using an ArrayList |
You should also know that ArrayList implements equals() and toString() so you can easily see the contents just by printing it. Arrays do not do produce such pretty output.
add(): insert a new value in the ArrayList.signatures: boolean add(E element) void add(int index, E element) the returned boolean value will always be true.example: ArrayList list = new ArrayList(); list.add("hawk"); // [hawk] list.add(Boolean.TRUE); // [hawk, true] System.out.println(list); // [hawk, true] This is okay because we didn’t specify a type for ArrayList; therefore, the type is Object, which includes everything except primitives. ArrayList<String> safer = new ArrayList<>(); safer.add("sparrow"); safer.add(Boolean.TRUE); // DOES NOT COMPILE |
Understanding an ArrayList
Using an ArrayList |
let’s try adding multiple values to different positions.
4: List<String> birds = new ArrayList<>(); 5: birds.add("hawk"); // [hawk] 6: birds.add(1, "robin"); // [hawk, robin] 7: birds.add(0, "blue jay"); // [blue jay, hawk, robin] 8: birds.add(1, "cardinal"); // [blue jay, cardinal, hawk, robin] 9: System.out.println(birds); // [blue jay, cardinal, hawk, robin] remove(): remove the first matching value in the ArrayList or remove the element at a specifi ed index.signature: boolean remove(Object object) E remove(int index) This time the boolean return value tells us whether a match was removed. The E return type is the element that actually got removed. |
Understanding an ArrayList
Using an ArrayList |
3: List<String> birds = new ArrayList<>();
4: birds.add("hawk"); // [hawk] 5: birds.add("hawk"); // [hawk, hawk] 6: System.out.println(birds.remove("cardinal")); // prints false 7: System.out.println(birds.remove("hawk")); // prints true 8: System.out.println(birds.remove(0)); // prints hawk 9: System.out.println(birds); // [] Since calling remove() with an int uses the index, an index that doesn’t exist will throw an exception. For example, birds.remove(100) throws an IndexOutOfBoundsException. set():changes one of the elements of the ArrayList without changing the size.signature: E set(int index, E newElement) The E return type is the element that got replaced. List<String> birds = new ArrayList<>(); birds.add("hawk"); // [hawk] System.out.println(birds.size()); // 1 String nombre = birds.set(0, "robin"); // [robin] System.out.println("nombre:"+nombre);//nombre:haw System.out.println(birds.size()); // 1 birds.set(1, "robin"); // IndexOutOfBoundsException |
Understanding an ArrayList
Using an ArrayList |
isEmpty() and size():this methods look at how many of the slots are in use.signature:
boolean isEmpty() int size() The following shows how to use these methods: System.out.println(birds.isEmpty()); // true System.out.println(birds.size()); // 0 birds.add("hawk"); // [hawk] birds.add("hawk"); // [hawk, hawk] System.out.println(birds.isEmpty()); // false System.out.println(birds.size()); // 2 clear(): provides an easy way to discard all elements of the ArrayList.signature: void clear() List<String> birds = new ArrayList<>(); birds.add("hawk"); // [hawk] birds.add("hawk"); // [hawk, hawk] System.out.println(birds.isEmpty()); // false System.out.println(birds.size()); // 2 birds.clear(); // [] System.out.println(birds.isEmpty()); // true System.out.println(birds.size()); // 0 After we call clear(), birds is back to being an empty ArrayList of size 0. |
Understanding an ArrayList
Using an ArrayList |
contains(): checks whether a certain value is in the ArrayList.signature:
boolean contains(Object object) List<String> birds = new ArrayList<>(); birds.add("hawk"); // [hawk] System.out.println(birds.contains("hawk")); // true System.out.println(birds.contains("robin")); // false This method calls equals() on each element of the ArrayList to see whether there are any matches. equals(): ArrayList has a custom implementation of equals() so you can compare two lists to see if they contain the same elements in the same order. boolean equals(Object object) 31: List<String> one = new ArrayList<>(); 32: List<String> two = new ArrayList<>(); 33: System.out.println(one.equals(two)); // true 34: one.add("a"); // [a] 35: System.out.println(one.equals(two)); // false 36: two.add("a"); // [a] 37: System.out.println(one.equals(two)); // true 38: one.add("b"); // [a,b] 39: two.add(0, "b"); // [b,a] 40: System.out.println(one.equals(two)); // false |
Understanding an ArrayList
Wrapper Classes |
Each primitive type has a wrapper class, which is an object type that corresponds to the primitive.
The parse methods, such as parseInt(), return a primitive, and the valueOf() method returns a wrapper class.example: int primitive = Integer.parseInt("123"); Integer wrapper = Integer.valueOf("123"); If the String passed in is not valid for the given type, Java throws an exception. int bad1 = Integer.parseInt("a"); // throws NumberFormatException Integer bad2 = Integer.valueOf("123.45"); // throws NumberFormatException Also, the Character class doesn’t participate in the parse/ valueOf methods. |
Understanding an ArrayList
Wrapper Classes |
|
Understanding an ArrayList
Autoboxing |
Since Java 5, you can just type the primitive value and Java will convert it to the relevant wrapper class for you. This is called autoboxing.example:
4: List<Double> weights = new ArrayList<>(); 5: weights.add(50.5); // [50.5] 6: weights.add(new Double(60)); // [50.5, 60.0] 7: weights.remove(50.5); // [60.0] 8: double first = weights.get(0); // 60.0 Line 5 autoboxes the double primitive into a Double object and adds that to the List. Line 6 shows that you can still write code the long way and pass in a wrapper object. Line 7 again autoboxes into the wrapper object and passes it to remove(). Line 8 retrieves the Double and unboxes it into a double primitive. |
Understanding an ArrayList
Autoboxing |
What do you think happens if you try to unbox a null?
3: List<Integer> heights = new ArrayList<>(); 4: heights.add(null); 5: int h = heights.get(0); // NullPointerException On line 4, we add a null to the list. This is legal because a null reference can be assigned to any reference variable. On line 5, we try to unbox that null to an int primitive. This is a problem. Java tries to get the int value of null. Since calling any method on null gives a NullPointerException, that is just what we get. Be careful when you see null in relation to autoboxing. |
Understanding an ArrayList
Autoboxing |
Be careful when autoboxing into Integer. What do you think this code outputs?
List<Integer> numbers = new ArrayList<>(); numbers.add(1); numbers.add(2); numbers.remove(1); System.out.println(numbers); It actually outputs 1. After adding the two values, the List contains [1, 2]. We then request the element with index 1 be removed. That’s right: index 1. Because there’s already a remove() method that takes an int parameter, Java calls that method rather than autoboxing. If you want to remove the 2, you can write numbers.remove(new Integer(2)) to force wrapper class use. |
Understanding an ArrayList
Converting Between array and List |
3: List<String> list = new ArrayList<>();
4: list.add("hawk"); 5: list.add("robin"); 6: Object[] objectArray = list.toArray(); 7: System.out.println(objectArray.length); // 2 8: String[] stringArray = list.toArray(new String[0]); 9: System.out.println(stringArray.length); // 2 Line 8 specifies the type of the array and does what we actually want. The advantage of specifying a size of 0 for the parameter is that Java will create a new array of the proper size for the return value. If you like, you can suggest a larger array to be used instead. If the ArrayList fits in that array, it will be returned. Otherwise, a new one will be created. |
Understanding an ArrayList
Converting Between array and List |
The original array and created array backed List are linked. When a change is made to one, it is available in the other. It is a fixed-size list and is also known a backed List because the array changes with it.
ver imagen... Line 21 converts the array to a List. Note that it isn’t the java.util.ArrayList we’ve grown used to. It is a fixed-size, backed version of a List. Line 23 is okay because set() merely replaces an existing value. It updates both array and list because they point to the same data store. Line 24 also changes both array and list. Line 25 shows the array has changed to new test. Line 26 throws an exception because we are not allowed to change the size of the list. List<String> list = Arrays.asList("one", "two"); asList() takes varargs, which let you pass in an array or just type out the String values.This is handy when testing because you can easily create and populate a List on one line. |
Understanding an ArrayList
Sorting |
Sorting an ArrayList is very similar to sorting an array. You just use a different helper class:
List<Integer> numbers = new ArrayList<>(); numbers.add(99); numbers.add(5); numbers.add(81); Collections.sort(numbers); System.out.println(numbers); [5, 81, 99] |
Working with Dates and Times
|
As with an ArrayList, you need an import statement to work with the date and time classes.
Most of them are in the java.time package. To use it, add this import to your program: import java.time.*; // import time classes In the following sections, we’ll look at creating, manipulating, and formatting dates and times. |
Working with Dates and Times
Creating Dates and Times |
LocalDate Contains just a date—no time and no time zone.
LocalTime Contains just a time—no date and no time zone. LocalDateTime Contains both a date and time but no time zone. Oracle recommends avoiding time zones unless you really need them. If you do need to communicate across time zones, ZonedDateTime handles them. System.out.println(LocalDate.now()); System.out.println(LocalTime.now()); System.out.println(LocalDateTime.now()); Each of the three classes has a static method called now() that gives the current date and time.The output look like the following when run on January 20 at 12:45 p.m.: 2015-01-20 12:45:18.401 2015-01-20T12:45:18.401 Java uses T to separate the date and time when converting LocalDateTime to a String. Just remember that the month comes before the date. Also, Java tends to use a 24-hour clock even though the United States uses a 12-hour clock with a.m./p.m. |
Working with Dates and Times
Creating Dates and Times |
LocalDate date1 = LocalDate.of(2015, Month.JANUARY, 20);
LocalDate date2 = LocalDate.of(2015, 1, 20); Both pass in the year, month, and date. Although it is good to use the Month constants (to make the code easier to read), you can pass the int number of the month directly. Just use the number of the month the same way you would if you were writing the date in real life. The method signatures are as follows: public static LocalDate of(int year, int month, int dayOfMonth) public static LocalDate of(int year, Month month, int dayOfMonth) Month is a special type of class called an enum. For months in the new date and time methods, Java counts starting from 1 like we human beings do. The method signatures are as follows: public static LocalTime of(int hour, int minute) public static LocalTime of(int hour, int minute, int second) public static LocalTime of(int hour, int minute, int second, int nanos) |
Working with Dates and Times
Creating Dates and Times |
Finally, we can combine dates and times:
LocalDateTime dateTime1 = LocalDateTime.of(2015, Month.JANUARY, 20, 6, 15, 30); LocalDateTime dateTime2 = LocalDateTime.of(date1, time1); The date and time classes have private constructors to force you to use the static methods. LocalDate d = new LocalDate(); // DOES NOT COMPILE LocalDate.of(2015, Month.JANUARY, 32) // throws DateTimeException because value 32 is invalid. |
Working with Dates and Times
Creating Dates and Times |
|
Working with Dates and Times
Manipulating Dates and Times |
The date and time classes are immutable, just like String was. This means that we need to remember to assign the results of these methods to a reference
variable so they are not lost. 12: LocalDate date = LocalDate.of(2014, Month.JANUARY, 20); 13: System.out.println(date); // 2014-01-20 14: date = date.plusDays(2); 15: System.out.println(date); // 2014-01-22 16: date = date.plusWeeks(1); 17: System.out.println(date); // 2014-01-29 18: date = date.plusMonths(1); 19: System.out.println(date); // 2014-02-28 20: date = date.plusYears(5); 21: System.out.println(date); // 2019-02-28 |
Working with Dates and Times
Manipulating Dates and Times |
22: LocalDate date = LocalDate.of(2020, Month.JANUARY, 20);
23: LocalTime time = LocalTime.of(5, 15); 24: LocalDateTime dateTime = LocalDateTime.of(date, time); 25: System.out.println(dateTime); // 2020-01-20T05:15 26: dateTime = dateTime.minusDays(1); 27: System.out.println(dateTime); // 2020-01-19T05:15 28: dateTime = dateTime.minusHours(10); 29: System.out.println(dateTime); // 2020-01-18T19:15 30: dateTime = dateTime.minusSeconds(30); 31: System.out.println(dateTime); // 2020-01-18T19:14:30 or LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); LocalTime time = LocalTime.of(5, 15); LocalDateTime dateTime = LocalDateTime.of(date2, time).minusDays(1).minusHours(10).minusSeconds(30); LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); date.plusDays(10); System.out.println(date);//It prints January 20, 2020. LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); date = date.plusMinutes(1); // DOES NOT COMPILE because LocalDate does not contain time. |
Working with Dates and Times
Manipulating Dates and Times |
|
Working with Dates and Times
Working with Periods |
■ LocalDate has toEpochDay(), which is the number of days since January 1, 1970.
■ LocalDateTime has toEpochTime(), which is the number of seconds since January 1, 1970. ■ LocalTime does not have an epoch method. Period annually = Period.ofYears(1); // every 1 year Period quarterly = Period.ofMonths(3); // every 3 months Period everyThreeWeeks = Period.ofWeeks(3); // every 3 weeks Period everyOtherDay = Period.ofDays(2); // every 2 days Period everyYearAndAWeek = Period.of(1, 0, 7); // every year and 7 days Period wrong = Period.ofYears(1).ofWeeks(1); // every week This tricky code is really like writing the following: Period wrong = Period.ofYears(1); wrong = Period.ofWeeks(7); There is also Duration, which is intended for smaller units of time. For Duration, you can specify the number of days, hours, minutes, seconds, or nanoseconds. |
Working with Dates and Times
Formatting Dates and Times |
LocalDate date = LocalDate.of(2020, Month.JANUARY, 20);
System.out.println(date.getDayOfWeek()); // MONDAY System.out.println(date.getMonth()); // JANUARY System.out.println(date.getYear()); // 2020 System.out.println(date.getDayOfYear()); // 20 Java provides a class called DateTimeFormatter to help us out. Unlike the LocalDateTime class, DateTimeFormatter can be used to format any type of date and/or time object.DateTimeFormatter is in the package java.time.format. LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); LocalTime time = LocalTime.of(11, 12, 34); LocalDateTime dateTime = LocalDateTime.of(date, time); System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE));//2020-01-20 System.out.println(time.format(DateTimeFormatter.ISO_LOCAL_TIME));//11:12:34 System.out.println(dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));//2020-01-20T11:12:34 ISO is a standard for dates. |
Working with Dates and Times
Formatting Dates and Times |
DateTimeFormatter shortDateTime =
DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); System.out.println(shortDateTime.format(dateTime)); // 1/20/20 System.out.println(shortDateTime.format(date)); // 1/20/20 System.out.println(shortDateTime.format(time)); // UnsupportedTemporalTypeException or DateTimeFormatter shortDateTime = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); System.out.println(dateTime.format(shortDateTime)); System.out.println(date.format(shortDateTime)); System.out.println(time.format(shortDateTime)); // UnsupportedTemporalTypeException |
Working with Dates and Times
Formatting Dates and Times |
There are two predefi ned formats that can show up on the exam: SHORT and MEDIUM. The other predefined formats involve time zones, which are not on the exam.
LocalDate date = LocalDate.of(2020, Month.JANUARY, 20); LocalTime time = LocalTime.of(11, 12, 34); LocalDateTime dateTime = LocalDateTime.of(date, time); DateTimeFormatter shortF = DateTimeFormatter .ofLocalizedDateTime(FormatStyle.SHORT); DateTimeFormatter mediumF = DateTimeFormatter .ofLocalizedDateTime(FormatStyle.MEDIUM); System.out.println(shortF.format(dateTime)); // 1/20/20 11:12 AM System.out.println(mediumF.format(dateTime)); // Jan 20, 2020 11:12:34 AM If you don’t want to use one of the predefi ned formats, you can create your own. For example, this code spells out the month: DateTimeFormatter f = DateTimeFormatter.ofPattern("MMMM dd, yyyy, hh:mm"); System.out.println(dateTime.format(f)); // January 20, 2020, 11:12 |
Working with Dates and Times
Formatting Dates and Times |
4: DateTimeFormatter f = DateTimeFormatter.ofPattern("hh:mm");
5: f.format(dateTime); 6: f.format(date);//throw an exception. 7: f.format(time); |
Working with Dates and Times
Parsing Dates and Times |
Just like the format() method, the parse() method takes a formatter as well. If you don’t specify one, it uses the default for that type.
DateTimeFormatter f = DateTimeFormatter.ofPattern("MM dd yyyy"); LocalDate date = LocalDate.parse("01 02 2015", f); LocalTime time = LocalTime.parse("11:22"); System.out.println(date); // 2015-01-02 System.out.println(time); // 11:22 Parsing is consistent in that if anything goes wrong, Java throws a runtime exception. That could be a format that doesn’t match the String to be parsed or an invalid date. |
chapter 4: Methods and Encapsulation
Designing Methods |
The figure 4.1 show a method declaration, which specifies all the information needed to call the method.
|
Designing Methods
|
To call to method of the figure 4.1, just type its name, followed by a single int value in parentheses:
nap(10); |
Designing Methods
Access Modifiers |
Java offers four choices of access modifier:
public: The method can be called from any class. private: The method can only be called from within the same class. protected: The method can only be called from classes in the same package or subclasses. Default (Package Private) Access: The method can only be called from classes in the same package. This one is tricky because there is no keyword for default access.You simply omit the access modifier. public void walk1() {} default void walk2() {} // DOES NOT COMPILE void public walk3() {} // DOES NOT COMPILE void walk4() {} |
Designing Methods
Optional Specifiers |
Unlike with access modifi ers, you can have multiple
specifi ers in the same method (although not all combinations are legal). When this happens, you can specify them in any order.You can have zero or more specifiers in a method declaration. static: Used for class methods. abstract: Used when not providing a method body. final: Used when a method is not allowed to be overridden by a subclass. synchronized: On the OCP but not the OCA exam. native: Not on the OCA or OCP exam. Used when interacting with code written in another language such as C++. strictfp: Not on the OCA or OCP exam. Used for making floating-point calculations portable. public void walk1() {} public final void walk2() {} public static final void walk3() {} public final static void walk4() {} public modifier void walk5() {} // DOES NOT COMPILE public void final walk6() {} // DOES NOT COMPILE final public void walk7() {} Java allows the optional specifi ers to appear before the access modifier. |
Designing Methods
Return Type |
The return type might be an actual Java type such as String or int. If there is no return type, the void keyword is used.You cannot omit the return type. Methods with a return type other than void are required to have a return statement inside the method body.
Methods that have a return type of void are permitted to have a return statement with no value returned or omit the return statement entirely. public void walk1() { } public void walk2() { return; } public String walk3() { return ""; } public String walk4() { } // DOES NOT COMPILE public walk5() { } // DOES NOT COMPILE String walk6(int a) { if (a == 4) return ""; } // DOES NOT COMPILE |
Designing Methods
Method Name |
To review, an identifi er may only contain letters, numbers, $, or _. Also, the fi rst character is not allowed to be a number, and reserved words are not allowed.By convention, methods begin with a lowercase letter but are not required to.
public void walk1() { } public void 2walk() { } // DOES NOT COMPILE public walk3 void() { } // DOES NOT COMPILE public void Walk_$() { } public void() { } // DOES NOT COMPILE |
Designing Methods
Parameter List |
You can just have an empty pair of parentheses after the method name, such as void nap(){}. If you do have multiple parameters, you separate them with a comma.
public void walk1() { } public void walk2 { } // DOES NOT COMPILE public void walk3(int a) { } public void walk4(int a; int b) { } // DOES NOT COMPILE public void walk5(int a, int b) { } |
Designing Methods
Optional Exception List |
You just need to know that it is optional.
public void zeroExceptions() { } public void oneException() throws IllegalArgumentException { } public void twoExceptions() throws IllegalArgumentException, InterruptedException { } The calling method can throw the same exceptions or handle them. |
Designing Methods
Method Body |
The fi nal part of a method declaration is the method body (except for abstract methods and interfaces).
A method body is simply a code block.It has braces that contain zero or more Java statements. public void walk1() { } public void walk2; // DOES NOT COMPILE public void walk3(int a) { int name = 5; } |
Working with Varargs
|
A method may use a vararg parameter (variable argument) as if it is an array. A vararg parameter
must be the last element in a method’s parameter list. You are only allowed to have one vararg parameter per method. public void walk1(int... nums) { } public void walk2(int start, int... nums) { } public void walk3(int... nums, int start) { } // DOES NOT COMPILE public void walk4(int... start, int... nums) { } // DOES NOT COMPILE You can pass in an array, or you can list the elements of the array and let Java create it for you. You can even omit the vararg values in the method call and Java will create an array of length zero for you. 15: public static void walk(int start, int... nums) { 16: System.out.println(nums.length); 17: } 18: public static void main(String[] args) { 19: walk(1); // 0 20: walk(1, {4, 5}); // Does not compile 21: walk(1, 2, 3); // 2 22: walk(1, new int[] {4, 5}); // 2 23: walk(1,null);// throws a NullPointerException 24: } |
Working with Varargs
|
Accessing a vararg parameter is also just like accessing an array. It uses array indexing. For example:
16: public static void run(int... nums) { 17: System.out.println(nums[1]); 18: } 19: public static void main(String[] args) { 20: run(11, 22); // 22 21: } |
Applying Access Modifiers
|
■ private: Only accessible within the same class
■ default (package private) access: private and other classes in the same package ■ protected: default access and child classes ■ public: protected and classes in the other packages |
Applying Access Modifiers
Private Access |
Only code in the same class can call private methods or access private fields.
1: package pond.duck; 2: public class FatherDuck { 3: private String noise = "quack"; 4: private void quack() { 5: System.out.println(noise); // private access is ok 6: } 7: private void makeNoise() { 8: quack(); // private access is ok 9: } } 1: package pond.duck; 2: public class BadDuckling { 3: public void makeNoise() { 4: FatherDuck duck = new FatherDuck(); 5: duck.quack(); // DOES NOT COMPILE 6: System.out.println(duck.noise); // DOES NOT COMPILE 7: } } |
Applying Access Modifiers
Default (Package Private) Access |
Only classes in the package may access to its members.
package pond.duck; public class MotherDuck { String noise = "quack"; void quack() { System.out.println(noise); // default access is ok } private void makeNoise() { quack(); // default access is ok } } package pond.duck; public class GoodDuckling { public void makeNoise() { MotherDuck duck = new MotherDuck(); duck.quack(); // default access System.out.println(duck.noise); // default access } } package pond.swan; import pond.duck.MotherDuck; // import another package public class BadCygnet { public void makeNoise() { MotherDuck duck = new MotherDuck(); duck.quack(); // DOES NOT COMPILE System.out.println(duck.noise); // DOES NOT COMPILE } } Remember that when there is no access modifi er, only classes in the same package can access it. |
Applying Access Modifiers
Protected Access |
The protected access modifi er adds the ability to access members of a parent class.
package pond.shore; public class Bird { protected String text = "floating"; // protected access protected void floatInWater() { // protected access System.out.println(text); } } package pond.goose; import pond.shore.Bird; // in a different package public class Gosling extends Bird { // extends means create subclass public void swim() { floatInWater(); // calling protected member System.out.println(text); // calling protected member } } Extending means creating a subclass that has access to any protected or public members of the parent class. Since Gosling is a subclass of Bird, it can access these members even though it is in a different package. |
Applying Access Modifiers
Protected Access |
Remember that protected also gives us access to everything that default access does. This means that a class in the same package as Bird can access its protected members.
package pond.shore; // same package as Bird public class BirdWatcher { public void watchBird() { Bird bird = new Bird(); bird.floatInWater(); // calling protected member System.out.println(bird.text); // calling protected member } } The definition of protected allows access to subclasses and classes in the same package. |
Applying Access Modifiers
Protected Access |
■A member is used without referring to a variable. This is the case on lines 5 and 6. In this case, we are taking advantage of inheritance and protected access is allowed.
■ A member is used through a variable. This is the case on lines 10, 11, 15, and 16. In this case, the rules for the reference type of the variable are what matter. If it is a subclass, protected access is allowed. This works for references to the same class or a subclass. |
Applying Access Modifiers
Protected Access |
The fi rst method is fi ne. In fact, it is equivalent to the Swan example. Goose extends Bird. Since we are in the Goose subclass and referring to a Goose reference, it can access protected members. The second method is a problem. Although the object happens to be a Goose, it is stored in a Bird reference. We are not allowed to refer to members of the Bird class since we are not in the same package and Bird is not a subclass of Bird.
|
Applying Access Modifiers
Protected Access |
This code doesn’t compile because we are not in the Goose class. The floatInWater() method is declared in Bird. GooseWatcher is not in the same package as Bird, nor does it extend Bird. Goose extends Bird. That only lets Goose refer to floatInWater() and not
callers of Goose. |
Applying Access Modifiers
Public Access |
public means anyone can access the member from anywhere.
|
Designing Static Methods and Fields
|
Static methods don’t require an instance of the class.They are shared among all users of the class.
Each class has a copy of the instance variables. There is only one copy of the code for the instance methods. Each instance of the class can call it as many times as it would like. However, each call of an instance method (or any method) gets space on the stack for method parameters and local variables. The same thing happens for static methods. There is one copy of the code. Parameters and local variables go on the stack.The main() method is a static method. That means you can call it by the classname. |
Designing Static Methods and Fields
|
static methods have two main purposes:
■ For utility or helper methods that don’t require any object state. Since there is no need to access instance variables, having static methods eliminates the need for the caller to instantiate the object just to call the method. ■ For state that is shared by all instances of a class, like a counter. All instances must share the same state. Methods that merely use that state should be static as well. |
Designing Static Methods and Fields
Calling a Static Variable or Method |
System.out.println(Koala.count);
Koala.main(new String[0]); You can use an instance of the object to call a static method. 5: Koala k = new Koala(); 6: System.out.println(k.count); // k is a Koala 7: k = null; 8: System.out.println(k.count); // k is still a Koala Believe it or not, this code outputs 0 twice. Line 6 sees that k is a Koala and count is a static variable, so it reads that static variable. Line 8 does the same thing. Java doesn’t care that k happens to be null. Since we are looking for a static, it doesn’t matter. Koala.count = 4; Koala koala1 = new Koala(); Koala koala2 = new Koala(); koala1.count = 6; koala2.count = 5; System.out.println(Koala.count);//5 |
Designing Static Methods and Fields
Static vs. Instance |
Remember that “member” means field or method.A static member cannot call an instance member.
About Picture: The compiler will give you an error about making a static reference to a nonstatic method.A solution would have been to call third as an instance method—for example, new Static().third();. A static method or instance method can call a static method because static methods don’t require an object to use. |
Designing Static Methods and Fields
Static vs. Instance |
|
Designing Static Methods and Fields
Static vs. Instance |
Each time the constructor gets called, it increments count by 1. This example relies on the fact that static (and instance) variables are automatically initialized to the default value for that type, which is 0 for int.
Also notice that we didn’t write Counter.count. We could have. It isn’t necessary because we are already in that class so the compiler can infer it. |
Designing Static Methods and Fields
Static Variables |
Just as with instance variables, you can initialize a static variable on the line it is declared:
public class Initializers { private static int counter = 0; // initialization } A constant uses the final modifier to ensure the variable never changes. static final constants use a different naming convention than other variables:all uppercase letters with underscores between “words.” public class Initializers { private static final int NUM_BUCKETS = 45; public static void main(String[] args) { NUM_BUCKETS = 5; // DOES NOT COMPILE } } |
Designing Static Methods and Fields
Static Variables |
private static final ArrayList<String> values = new ArrayList<>();
public static void main(String[] args) { values.add("changed"); } It actually does compile. values is a reference variable. We are allowed to call methods on reference variables. All the compiler can do is check that we don’t try to reassign the final values to point to a different object. |
Designing Static Methods and Fields
Static Initialization |
Instance initializers that looked like unnamed methods. Just code inside braces. Static initializers look similar. They add the static keyword to specify they should be run when the class is first used.
private static final int NUM_SECONDS_PER_HOUR; static { int numSecondsPerMinute = 60; int numMinutesPerHour = 60; NUM_SECONDS_PER_HOUR = numSecondsPerMinute * numMinutesPerHour; } We just got through saying that fi nal variables aren’t allowed to be reassigned. The key here is that the static initializer is the fi rst assignment. And since it occurs up front, it is okay. 14: private static int one; 15: private static final int two; 16: private static final int three = 3; 17: private static final int four; // DOES NOT COMPILE 18: static { 19: one = 1; 20: two = 2; 21: three = 3; // DOES NOT COMPILE 22: two = 4; // DOES NOT COMPILE 23: } |
Designing Static Methods and Fields
Static Imports |
Regular imports are for importing classes. Static imports are for importing static members of classes.
import java.util.List; import static java.util.Arrays.asList; // static import public class StaticImports { public static void main(String[] args) { List<String> list = asList("one", "two"); // no Arrays. } } An interesting case is what would happen if we created an asList method in our StaticImports class. Java would give it preference over the imported one and the method we coded would be used. 1: import static java.util.Arrays; // DOES NOT COMPILE 2: import static java.util.Arrays.asList; 3: static import java.util.Arrays.*; // DOES NOT COMPILE 4: public class BadStaticImports { 5: public static void main(String[] args) { 6: Arrays.asList("one"); // DOES NOT COMPILE 7: } } |
Designing Static Methods and Fields
Static Imports |
import static statics.A.TYPE;
import static statics.B.TYPE; // DOES NOT COMPILE Luckily when this happens, we can just refer to the static members via their classname in the code instead of trying to use a static import. |
Passing Data Among Methods
|
Java is a “pass-by-value” language. This means that a copy of the variable is made and the method receives that copy.
2: public static void main(String[] args) { 3: int num = 4; 4: newNumber(5); 5: System.out.println(num); // 4 6: } 7: public static void newNumber(int num) { 8: num = 8; 9: } public static void main(String[] args) { String name = "Webby"; speak(name); System.out.println(name); } public static void speak(String name) { name = "Sparky"; } The correct answer is Webby. Just as in the primitive example, the variable assignment is only to the method parameter and doesn’t affect the caller. public static void main(String[] args) { StringBuilder name = new StringBuilder(); speak(name); System.out.println(name); // Webby } public static void speak(StringBuilder s) { s.append("Webby"); } In this case, the output is Webby because the method merely calls a method on the parameter. |
Passing Data Among Methods
|
To review, Java uses pass-by-value to get data into a method. Assigning a new primitive or reference to a parameter doesn’t change the caller. Calling methods on a reference to an object does affect the caller.
|
Overloading Methods
|
Method overloading occurs when there are different method signatures with the same name but different type parameters.These are all valid overloaded methods:
public void fly(int numMiles) { } public void fly(short numFeet) { } public boolean fly() { return false; } void fly(int numMiles, short numFeet) { } public void fly(short numFeet, int numMiles) throws Exception { } We can overload by changing anything in the parameter list. We can have a different type, more types, or the same types in a different order. Also notice that the access modifier,return type,specifiers (like static) and exception list are irrelevant to overloading. public void fly(int numMiles) { } public int fly(int numMiles) { } // DOES NOT COMPILE public void fly(int numMiles) { } public static void fly(int numMiles) { } // DOES NOT COMPILE |
Overloading Methods
Overloading and Varargs |
public void fly(int[] lengths) { }
public void fly(int... lengths) { } // DOES NOT COMPILE fly(new int[] { 1, 2, 3 }); However, you can only call the varargs version with stand-alone parameters: fly(1, 2, 3); Obviously, this means they don't compile exactly the same. |
Overloading Methods
Autoboxing |
public void fly(int numMiles) { }
public void fly(Integer numMiles) { } call fly(3), Java will match the int numMiles version. Java tries to use the most specific parameter list it can find. When the primitive int version isn't present, it will autobox. However, when the primitive int version is provided, there is no reason for Java to do the extra work of autoboxing. |
Overloading Methods
Reference Types |
public class ReferenceTypes {
public void fly(String s) { System.out.print("string "); } public void fly(Object o) { System.out.print("object "); } public static void main(String[] args) { ReferenceTypes r = new ReferenceTypes(); r.fly("test"); r.fly(56); } } The answer is "string object". The first call is a String and fi nds a direct match. There's no reason to use the Object version when there is a nice String parameter list just waiting to be called. The second call looks for an int parameter list. When it doesn't find one, it autoboxes to Integer. Since it still doesn't fi nd a match, it goes to the Object one. |
Overloading Methods
Primitives |
public class Plane {
public void fly(int i) { System.out.print("int "); } public void fly(long l) { System.out.print("long "); } public static void main(String[] args) { Plane p = new Plane(); p.fly(123); p.fly(123L); } } The answer is int long. The first call passes an int and sees an exact match. The second call passes a long and also sees an exact match. If we comment out the overloaded method with the int parameter list, the output becomes long long. Java has no problem calling a larger primitive. However, it will not do so unless a better match is not found. Note that Java can only accept wider types. An int can be passed to a method taking a long parameter. Java will not automatically convert to a narrower type. If you want to pass a long to a method taking an int parameter, you have to add a cast to explicitly say narrowing is okay. |
Creating Constructors
|
A constructor is a special method that matches the name of the class and has no return type.Constructors are used when creating a new object. This process is called instantiation because it creates a new instance of the class.A constructor is called when we write new. For example:
new Bunny() When Java sees the new keyword, it allocates memory for the new object. Java also looks for a constructor and calls it. The this keyword tells Java you want to reference an instance variable. The problem is that sometimes there are two variables with the same name. In a constructor, one is a parameter and one is an instance variable. If you don’t say otherwise, Java gives you the one with the most granular scope, which is the parameter. Using this.name tells Java you want the instance variable. 1: public class Bunny { 2: private String color; 3: public Bunny(String color) { 4: this.color = color; 5: } } |
Creating Constructors
Default Constructor |
If you don’t include any constructors in the class, Java will create one for you without any parameters.This Java-created constructor is called the default constructor.
public class Rabbit { public static void main(String[] args) { Rabbit rabbit = new Rabbit(); // Calls default constructor } } In the Rabbit class, Java sees no constructor was coded and creates one. We keep saying generated. This happens during the compile step. Having a private constructor in a class tells the compiler not to provide a default noargument constructor. It also prevents other classes from instantiating the class. This is useful when a class only has static methods or the class wants to control all calls to create new instances of itself. |
Creating Constructors
Overloading Constructors |
You can have multiple constructors in the same class as long as they have different method signatures.When overloading methods, the method name and parameter list needed to match. With constructors, the name is always the same since it has to be the same as the name of the class. This means constructors must have different parameters in order to be overloaded.
public class Hamster { private String color; private int weight; public Hamster(int weight) { // first constructor this.weight = weight; color = "brown"; } public Hamster(int weight, String color) { // second constructor this.weight = weight; this.color = color; } } There is a bit of duplication. Solution a: public Hamster(int weight) { Hamster(weight, "brown"); // DOES NOT COMPILE } |
Creating Constructors
Overloading Constructors |
Solution b:
public Hamster(int weight) { new Hamster(weight, "brown"); // Compiles but does not do what we want } When the constructor with one parameter is called, it creates an object with the default weight and color. It then constructs a different object with the desired weight and color and ignores the new object. Solution c(Correct): public Hamster(int weight) { this(weight, "brown"); } this() has one special rule you need to know. If you choose to call it, the this() call must be the first noncommented statement in the constructor. 3: public Hamster(int weight) { 4: System.out.println("in constructor"); 5: // ready to call this 6: this(weight, "brown"); // DOES NOT COMPILE 7: } |
Creating Constructors
Constructor Chaining |
public class Mouse {
private int numTeeth; private int numWhiskers; private int weight; public Mouse(int weight) { this(weight, 16); // calls constructor with 2 parameters } public Mouse(int weight, int numTeeth) { this(weight, numTeeth, 6); // calls constructor with 3 parameters } public Mouse(int weight, int numTeeth, int numWhiskers) { this.weight = weight; this.numTeeth = numTeeth; this.numWhiskers = numWhiskers; } public void print() { System.out.println(weight + " " + numTeeth + " " + numWhiskers); } public static void main(String[] args) { Mouse mouse = new Mouse(15); mouse.print(); } } |
Final Fields
|
final instance variables must be assigned a value exactly once.
public class MouseHouse { private final int volume; private final String name = "The Mouse House"; public MouseHouse(int length, int width, int height) { volume = length * width * height; }} The constructor is part of the initialization process, so it is allowed to assign final instance variables in it. By the time the constructor completes, all final instance variables must have been set. |
Order of Initialization
|
1. If there is a superclass, initialize it first (we’ll cover this rule in the next chapter. For now, just say “no superclass” and go on to the next rule.)
2. Static variable declarations and static initializers in the order they appear in the file. 3. Instance variable declarations and instance initializers in the order they appear in the file. 4. The constructor. Keep in mind that the four rules apply only if an object is instantiated. If the class is referred to without a new call, only rules 1 and 2 apply. 1: public class YetMoreInitializationOrder { 2: static { add(2); } 3: static void add(int num) { System.out.print(num + " "); } 4: YetMoreInitializationOrder() { add(5); } 5: static { add(4); } 6: { add(6); } 7: static { new YetMoreInitializationOrder(); } 8: { add(8); } 9: public static void main(String[] args) { } } The correct answer is 2 4 6 8 5. |
Encapsulating Data
|
Encapsulation means we set up the class so only methods in the class with the variables can refer to the instance variables. Callers are required to use these methods.
1: public class Swan { 2: private int numberEggs; // private 3: public int getNumberEggs() { // accessor method or getter 4: return numberEggs; 5: } 6: public void setNumberEggs(int numberEggs) { // mutator method or setter 7: if (numberEggs >= 0) // guard condition 8: this.numberEggs = numberEggs; For encapsulation, remember that data (an instance variable) is private and getters/setters are public.Java defines a naming convention that is used in JavaBeans. JavaBeans are reusable software components. JavaBeans call an instance variable a property. |
Encapsulating Data
Creating Immutable Classes |
Encapsulating data is helpful because it prevents callers from making uncontrolled changes to your class. Immutable classes are helpful because you know they will always be the same.You can pass them around your application with a guarantee that the caller didn’t change anything. This helps make programs easier to maintain. It also helps with performance by limiting
the number of copies.One step in making a class immutable is to omit the setters. public class ImmutableSwan { private int numberEggs; public ImmutableSwan(int numberEggs) { this.numberEggs = numberEggs; } public int getNumberEggs() { return numberEggs; } } Immutable classes are allowed to have values. They just can't change after instantiation. Encapsulation refers to preventing callers from changing the instance variables directly. Immutability refers to preventing callers from changing the instance variables at all. |
Writing Simple Lambdas
|
Functional programming is a way of writing code more declaratively. You specify what you want to do rather than dealing with the state of objects. You focus more on expressions than loops.
Functional programming uses lambda expressions to write code. A lambda expression is a block of code that gets passed around. You can think of a lambda expression as an anonymous method.Lambda expressions are often referred to as lambdas for short. You might also know them as closures if Java isn’t your first language. In other words, a lambda expression is like a method that you can pass as if it were a variable. |
Writing Simple Lambdas
Lambda Example |
Our goal is to print out all the animals in a list according to some criteria.
|
Writing Simple Lambdas
Lambda Syntax |
examples:
a -> a.canHop() (Animal a) -> { return a.canHop(); } The parentheses can only be omitted if there is a single parameter and its type is not explicitly stated. Java doesn’t require you to type return or use a semicolon when no braces are used.This special shortcut doesn’t work when we have two or more statements. 3: print(() -> true); // 0 parameters 4: print(a -> a.startsWith("test")); // 1 parameter 5: print((String a) -> a.startsWith("test")); // 1 parameter 6: print((a, b) -> a.startsWith("test")); // 2 parameters 7: print((String a, String b) -> a.startsWith("test")); // 2 parameters print(a, b -> a.startsWith("test")); // DOES NOT COMPILE print(a -> { a.startsWith("test"); }); // DOES NOT COMPILE print(a -> { return a.startsWith("test") }); // DOES NOT COMPILE |
Writing Simple Lambdas
Lambda Syntax |
Lambdas are allowed to access variables. Here’s an
example: boolean wantWhetherCanHop = true; print(animals, a -> a.canHop() == wantWhetherCanHop); The trick is that they cannot access all variables. Instance and static variables are okay. Method parameters and local variables are fi ne if they are not assigned new values. Since Java doesn’t allow us to redeclare a local variable, the following is an issue: (a, b) -> { int a = 0; return 5;} // DOES NOT COMPILE (a, b) -> { int c = 0; return 5;}//ok |
Writing Simple Lambdas
Predicates |
Lambdas work with interfaces that have only one method. These are called functional interfaces—interfaces that can be used with functional programming.You can imagine that we’d have to create lots of interfaces like this to use lambdas. We want to test Animals and Strings and Plants and anything else that we come across. Luckily, Java recognizes that this is a common problem and provides such an interface for us. It’s in the package java.util.function and the gist of it is as follows:
public interface Predicate<T> { boolean test(T t); } ArrayList declares a removeIf() method that takes a Predicate. 3: List<String> bunnies = new ArrayList<>(); 4: bunnies.add("long ear"); 5: bunnies.add("floppy"); 6: bunnies.add("hoppy"); 7: System.out.println(bunnies); // [long ear, floppy, hoppy] 8: bunnies.removeIf(s -> s.charAt(0) != 'h'); 9: System.out.println(bunnies); // [hoppy] |
Chapter 5: Class Design
|
At its core, proper Java class design is about code reusability, increased functionality, and standardization. For example, by creating a new class that extends an existing class, you may gain access to a slew of inherited primitives, objects, and methods. Alternatively, by designing a standard interface for your application, you ensure that any class that implements the interface has certain required methods defined. Finally, by creating abstract class definitions, you’re defining a platform that other developers can extend and build on top of.
|
Introducing Class Inheritance
|
Inheritance is the process by which the new child subclass automatically includes any public or protected primitives, objects, or methods defined in the parent class.Java supports single inheritance.You can extend a class any number of times, allowing each descendent to gain access to its ancestor’s members.Java does allow one exception to the single inheritance rule: classes may implement multiple interfaces.
|
Introducing Class Inheritance
Extending a Class |
public class Animal {
private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } } And here are the contents of Lion.java: public class Lion extends Animal { private void roar() { System.out.println("The "+getAge()+" year old lion says: Roar!"); } } public class Lion extends Animal { private void roar() { System.out.println("The "+age+" year old lion says: Roar!"); // DOES NOT COMPILE } } Despite the fact that age is inaccessible by the child class, if we have an instance of a Lion object, there is still an age value that exists within the instance. The age value just cannot be directly referenced by the child class nor any instance of the class. In this manner, the Lion object is actually “bigger” than the Animal object in the sense that it includes all the properties of the Animal object (although not all of those properties may be directly accessible) along with its own set of Lion attributes. |
Introducing Class Inheritance
Applying Class Access Modifiers |
public and default package-level class access modifiers
can be applied to top-level classes within a Java file. The protected and private modifiers can only be applied to inner classes. The public access modifier applied to a class indicates that it can be referenced and used in any class. The default package private modifier, which is the lack of any access modifier, indicates the class can be accessed only by a subclass or class within the same package. As you know, a Java file can have many classes but at most one public class. In fact, it may have no public class at all. One feature of using the default package private modifier is that you can define many classes within the same Java file. The rules for applying class access modifiers are identical for interfaces. There can be at most one public class or interface in a Java file. Like classes, top-level interfaces can also be declared with the public or default modifiers. |
Introducing Class Inheritance
Creating Java Objects |
In Java, all classes inherit from a single class,java.lang.Object.when Java sees you define a class that doesn’t extend another class, it immediately adds the syntax extends java.lang.Object to the class definition.
public class Zoo { } public class Zoo extends java.lang.Object { } |
Introducing Class Inheritance
Defining Constructors |
In Java, the first statement of every constructor is either a call to another constructor within the class, using this(), or a call to a constructor in the direct parent class, using super().
public class Animal { private int age; public Animal(int age) { super(); this.age = age; } } public class Zebra extends Animal { public Zebra(int age) { super(age); } public Zebra() { this(4); } } Like the this() command, the super() command may only be used as the first statement of the constructor. public class Zoo { public Zoo() { System.out.println("Zoo created"); super(); // DOES NOT COMPILE } } public class Zoo { public Zoo() { super(); System.out.println("Zoo created"); super(); // DOES NOT COMPILE } } |
Introducing Class Inheritance
Understanding Compiler Enhancements |
Java compiler automatically inserts a call to the no-argument constructor super() if the first statement is not a call to the parent constructor.The following three class and constructor definitions are equivalent:
public class Donkey { } public class Donkey { public Donkey() { } } public class Donkey { public Donkey() { super(); } } Subclasses may define no-argument constructors even if their parent classes do not, provided the constructor of the child maps to a parent constructor via an explicit call of the super() command. |
Introducing Class Inheritance
Reviewing Constructor Rules |
|
Introducing Class Inheritance
Calling Constructors |
|
Introducing Class Inheritance
Calling Inherited Class Members |
Java classes may use any public or protected member of the parent class, including methods, primitives, or object references. If the parent class and child class are part of the same package, the child class may also use any default members defined in the parent class.
you can use the keyword this to access a member of the class. You may also use this to access members of the parent class that are accessible from the child class, since a child class inherits all of its parent members. In Java, you can explicitly reference a member of the parent class by using the super keyword |
Introducing Class Inheritance
Inheriting Methods-Overriding a Method |
The method signature includes the name and list of input parameters.When you override a method, you may reference the parent version of the method using the super keyword.
public class Canine { public double getAverageWeight() { return 50; } } public class Wolf extends Canine { public double getAverageWeight() { return super.getAverageWeight()+20; } public static void main(String[] args) { System.out.println(new Canine().getAverageWeight()); System.out.println(new Wolf().getAverageWeight()); } } Output: 50.00 70.00 |
Introducing Class Inheritance
Inheriting Methods-Overriding a Method |
The compiler performs the following checks when you override a nonprivate method:
1. The method in the child class must have the same signature as the method in the parent class. 2. The method in the child class must be at least as accessible or more accessible than the method in the parent class. 3. The method in the child class may not throw a checked exception that is new or broader than the class of any exception thrown in the parent class method. 4. If the method returns a value, it must be the same or a subclass of the method in the parent class, known as covariant return types. If two methods have the same name but different signatures, the methods are overloaded, not overridden. Overloading a method and overriding a method are similar in that they both involve redefining a method using the same name. They differ in that an overloaded method will use a different signature than an overridden method. A child method may hide or eliminate a parent method’s exception without issue. |
Introducing Class Inheritance
Redeclaring private Methods |
In Java, it is not possible to override a private method in a parent class since the parent method is not accessible from the child class. Just because a child class doesn’t have access to the parent method, doesn’t mean the child class can’t define its own version of the method.
Java permits you to redeclare a new method in the child class with the same or modified signature as the method in the parent class. This method in the child class is a separate and independent method, unrelated to the parent version’s method, so none of the rules for overriding methods are invoked. public class Camel { private String getNumberOfHumps() { return "Undefined"; } } public class BactrianCamel extends Camel { private int getNumberOfHumps() { return 2; } } In this example, the method getNumberOfHumps() in the parent class is hidden, so the method in the child class is a new method and not an override of the method in the parent class. |
Introducing Class Inheritance
Hiding Static Methods |
A hidden method occurs when a child class defines a static method with the same name and signature as a static method defined in a parent class.First, the four previous rules for overriding a method must be followed when a method is hidden. In addition, a new rule is added for hiding a method, namely that the usage of the static keyword must be the same between
parent and child classes. public class Bear { public static void sneeze() { System.out.println("Bear is sneezing"); } public void hibernate() { System.out.println("Bear is hibernating"); } } public class Panda extends Bear { public void sneeze() { // DOES NOT COMPILE System.out.println("Panda bear sneezes quietly"); } public static void hibernate() { // DOES NOT COMPILE System.out.println("Panda bear is going to sleep"); } } |
Introducing Class Inheritance
Overriding vs. Hiding Methods |
Unlike overriding a method, in which a child method
replaces the parent method in calls defined in both the parent and child, hidden methods only replace parent methods in the calls defined in the child class. At runtime the child version of an overridden method is always executed for an instance regardless of whether the method call is defined in a parent or child class method. In this manner, the parent method is never used unless an explicit call to the parent method is referenced, using the syntax parentClassName.method(). Alternatively, at runtime the parent version of a hidden method is always executed if the call to the method is defined in the parent class. |
Introducing Class Inheritance
Creating final methods |
final methods cannot be overridden.This rule is in place both when you override a method and when you hide a method.The final modifier is only used on methods when the author of the parent method wants to guarantee very precise behavior.
|
Introducing Class Inheritance
Inheriting Variables |
Java doesn’t allow variables to be overridden but instead hidden.
|
Introducing Class Inheritance
Hiding Variables |
When you hide a variable, you define a variable with the same name as a variable in a parent class. This creates two copies of the variable within an instance of the child class: one instance defi ned for the parent reference and another defi ned for the child reference.
You can reference the parent value of the variable with an explicit use of the super keyword. The important thing to remember is that there is no notion of overriding a member variable. These rules are the same regardless of whether the variable is an instance variable or a static variable. public class Animal { public int length = 2; } public class Jellyfish extends Animal { public int length = 5; public static void main(String[] args) { Jellyfish jellyfish = new Jellyfish(); Animal animal = new Jellyfish(); System.out.println(jellyfish.length); System.out.println(animal.length); } } output: 5 2 |
Creating Abstract Classes
|
An abstract class is a class that is marked with the abstract keyword and cannot be instantiated. An abstract method is a method marked with the abstract keyword defined in an abstract class, for which no implementation is provided in the class in which it is declared.
public abstract class Animal { protected int age; public void eat() { System.out.println("Animal is eating"); } public abstract String getName(); } public class Swan extends Animal { public String getName() { return "Swan"; } } The first thing to notice about this sample code is that the Animal class is declared abstract and Swan is not. Next, the member age and the method eat() are marked as protected and public, respectively; therefore, they are inherited in subclasses such as Swan. Finally, the abstract method getName() is terminated with a semicolon and doesn’t provide a body in the parent class Animal. This method is implemented with the same name and signature as the parent method in the Swan class. |
Creating Abstract Classes
Defining an Abstract Class |
An abstract class may include nonabstract methods and variables.In fact, an abstract class is not required to
include any abstract methods.Example: public abstract class Cow { } An abstract method may only be defined in an abstract class. public class Chicken { public abstract void peck(); // DOES NOT COMPILE } public abstract class Turtle { public abstract void swim() {} // DOES NOT COMPILE public abstract int getAge() { // DOES NOT COMPILE return 10; } } In an abstract class, you can still define a method with a body—you just can’t mark it as abstract. As long as you do not mark it as final, the subclass still has the option to override it. An abstract class cannot be marked as final. public final abstract class Tortoise { // DOES NOT COMPILE } An abstract method may not be marked as final. public abstract class Goat { public abstract final void chew(); // DOES NOT COMPILE } |
Creating Abstract Classes
Defining an Abstract Class |
A method may not be marked as both abstract and private.
public abstract class Whale { private abstract void sing(); // DOES NOT COMPILE } public class HumpbackWhale extends Whale { private void sing() { System.out.println("Humpback whale is singing"); } } Even with abstract methods, the rules for overriding methods must be followed. public abstract class Whale { protected abstract void sing(); } public class HumpbackWhale extends Whale { private void sing() { // DOES NOT COMPILE System.out.println("Humpback whale is singing"); } } |
Creating Abstract Classes
Creating a Concrete Class |
When working with abstract classes, it is important to remember that by themselves, they cannot be instantiated and therefore do not do much other than define static variables and methods.
public abstract class Eel { public static void main(String[] args) { final Eel eel = new Eel(); // DOES NOT COMPILE } } An abstract class becomes useful when it is extended by a concrete subclass. A concrete class is the first nonabstract subclass that extends an abstract class and is required to implement all inherited abstract methods. public abstract class Animal { public abstract String getName(); } public class Walrus extends Animal { // DOES NOT COMPILE } ---------------- public abstract class Animal { public abstract String getName(); } public class Bird extends Animal { // DOES NOT COMPILE } public class Flamingo extends Bird { public String getName() { return "Flamingo"; } } |
Creating Abstract Classes
Extending an Abstract Class |
public abstract class Animal {
public abstract String getName(); } public class Walrus extends Animal { // DOES NOT COMPILE } public abstract class Eagle extends Animal { } Abstract classes can extend other abstract classes and are not required to provide implementations for any of the abstract methods. public abstract class Animal { public abstract String getName(); } public abstract class BigCat extends Animal { public abstract void roar(); } public class Lion extends BigCat { public String getName() { return "Lion"; } public void roar() { System.out.println("The Lion lets out a loud ROAR!"); } } |
Creating Abstract Classes
Extending an Abstract Class |
There is one exception to the rule for abstract methods and concrete classes: a concrete subclass is not required to provide an implementation for an abstract method if an intermediate abstract class provides the implementation.
public abstract class Animal { public abstract String getName(); } public abstract class BigCat extends Animal { public String getName() { return "BigCat"; } public abstract void roar(); } public class Lion extends BigCat { public void roar() { System.out.println("The Lion lets out a loud ROAR!"); } } |
Implementing Interfaces
|
Although Java doesn’t allow multiple inheritance, it does allow classes to implement any number of interfaces. An interface is an abstract data type that defines a list of abstract public methods that any class implementing the interface must provide.
The method modifiers , abstract and public, are assumed.In other words, whether or not you provide them, the compiler will automatically insert them as part of the method definition. A class may implement multiple interfaces, each separated by a comma, such as in the following example: public class Elephant implements WalksOnFourLegs, HasTrunk, Herbivore { } |
Implementing Interfaces
Defining an Interface |
It may be helpful to think of an interface as a specialized kind of abstract class.
public interface CanFly { void fly(int speed); abstract void takeoff(); public abstract double dive(); } public abstract interface CanFly { public abstract void fly(int speed); public abstract void takeoff(); public abstract double dive(); } |
Implementing Interfaces
Inheriting an Interface |
1. An interface that extends another interface, as well as an abstract class that implements an interface, inherits all of the abstract methods as its own abstract methods.
2. The first concrete class that implements an interface, or extends an abstract class that implements an interface, must provide an implementation for all of the inherited abstract methods. Unlike an abstract class, though, an interface may extend multiple interfaces. public interface HasTail { public int getTailLength(); } public interface HasWhiskers { public int getNumberOfWhiskers(); } public interface Seal extends HasTail, HasWhiskers { } |
Implementing Interfaces
Inheriting an Interface |
An abstract class that implements an interface is treated in the same way as an interface extending another interface.In other words, the abstract class inherits the abstract methods of the interface but is not required to implement them.
public interface HasTail { public int getTailLength(); } public interface HasWhiskers { public int getNumberOfWhiskers(); } public abstract class HarborSeal implements HasTail, HasWhiskers { } public class LeopardSeal implements HasTail, HasWhiskers { // DOES NOT COMPILE } |
Implementing Interfaces
Classes, Interfaces, and Keywords |
Although a class can implement an interface, a class cannot extend an interface. Likewise, whereas an interface can extend another interface, an interface cannot implement another interface.
public interface CanRun {} public class Cheetah extends CanRun {} // DOES NOT COMPILE public class Hyena {} public interface HasFur extends Hyena {} // DOES NOT COMPILE Make sure the only connection between a class and an interface is with the class implements interface syntax. |
Implementing Interfaces
Abstract Methods and Multiple Inheritance |
In this scenario, the signatures for the two interface methods eatPlants() are compatible, so you can define a class that fulfills both interfaces simultaneously:
public interface Herbivore { public void eatPlants(); } public interface Omnivore { public void eatPlants(); public void eatMeat(); } public class Bear implements Herbivore, Omnivore { public void eatMeat() { System.out.println("Eating meat"); } public void eatPlants() { System.out.println("Eating plants"); } } |
Implementing Interfaces
Abstract Methods and Multiple Inheritance |
If the method name is the same but the input parameters are different, there is no conflict because this is considered a method overload
public interface Herbivore { public int eatPlants(int quantity); } public interface Omnivore { public void eatPlants(); } public class Bear implements Herbivore, Omnivore { public int eatPlants(int quantity) { System.out.println("Eating plants: "+quantity); return quantity; } public void eatPlants() { System.out.println("Eating plants"); } } that the class that implements both interfaces must provide implements of both versions of eatPlants(), since they are considered separate methods |
Implementing Interfaces
Abstract Methods and Multiple Inheritance |
if the method name and input parameters are the same but the return types are different between the two methods, the class or interface attempting to inherit both interfaces will not compile.
public interface Herbivore { public int eatPlants(); } public interface Omnivore { public void eatPlants(); } public class Bear implements Herbivore, Omnivore { public int eatPlants() { // DOES NOT COMPILE System.out.println("Eating plants: 10"); return 10; } public void eatPlants() { // DOES NOT COMPILE System.out.println("Eating plants"); } } public interface Supervore extends Herbivore, Omnivore {} // DOES NOT COMPILE public abstract class AbstractBear implements Herbivore, Omnivore {} // DOES NOT COMPILE |
Implementing Interfaces
Interface Variables |
Like interface methods, interface variables are assumed to be public. Unlike interface methods, though, interface variables are also assumed to be static and final.
1. Interface variables are assumed to be public, static, and final. Therefore, marking a variable as private or protected will trigger a compiler error, as will marking any variable as abstract. 2. The value of an interface variable must be set when it is declared since it is marked as final. public interface CanSwim { int MAXIMUM_DEPTH = 100; final static boolean UNDERWATER = true; public static final String TYPE = "Submersible"; } public interface CanSwim { public static final int MAXIMUM_DEPTH = 100; public static final boolean UNDERWATER = true; public static final String TYPE = "Submersible"; } The compile will automatically insert public static final to any constant interface variables it finds missing those modifiers. |
Implementing Interfaces
Interface Variables |
public interface CanDig {
private int MAXIMUM_DEPTH = 100; // DOES NOT COMPILE protected abstract boolean UNDERWATER = false; // DOES NOT COMPILE public static String TYPE; // DOES NOT COMPILE } |
Implementing Interfaces
Default Interface Methods |
A default method is a method defined within an interface with the default keyword in which a method body is provided.Classes have the option to override the default method if they need to, but they are not required to do so.
public interface IsWarmBlooded { boolean hasScales(); public default double getTemperature() { return 10.0; } } The following are the default interface method rules you need to be familiar with: 1. A default method may only be declared within an interface and not within a class or abstract class. 2. A default method must be marked with the default keyword. If a method is marked as default, it must provide a method body. 3. A default method is not assumed to be static, final, or abstract, as it may be used or overridden by a class that implements the interface. 4. Like all methods in an interface, a default method is assumed to be public and will not compile if marked as private or protected. |
Implementing Interfaces
Default Interface Methods |
public interface Carnivore {
public default void eatMeat(); // DOES NOT COMPILE public int getRequiredFoodAmount() { // DOES NOT COMPILE return 13; } } Unlike interface variables, which are assumed static class members, default methods cannot be marked as static and require an instance of the class implementing the interface to be invoked.They can also not be marked as final or abstract, because they are allowed to be overridden in subclasses but are not required to be overridden. When an interface extends another interface that contains a default method,the interface may override the definition of the default method using the standard rules for method overriding. The interface may redeclare the method as abstract, requiring classes that implement the new interface to explicitly provide a method body. |
Implementing Interfaces
Default Methods and Multiple Inheritance |
public interface Walk {
public default int getSpeed() { return 5; } } public interface Run { public default int getSpeed() { return 10; } } public class Cat implements Walk, Run { // DOES NOT COMPILE public static void main(String[] args) { System.out.println(new Cat().getSpeed()); } } If a class implements two interfaces that have default methods with the same name and signature, the compiler will throw an error. There is an exception to this rule, though: if the subclass overrides the duplicate default methods, the code will compile without issue. public class Cat implements Walk, Run { public int getSpeed() { return 1; } public static void main(String[] args) { System.out.println(new Cat().getSpeed()); } } This rule holds true even for abstract classes that implement multiple interfaces, because the default method could be called in a concrete method within the abstract class. |
Implementing Interfaces
Static Interface Methods |
These methods are defined explicitly with the static keyword and function nearly identically to static methods defined in classes.A static method defined in an interface is not inherited in any classes that implement the interface.Rules:
1. Like all methods in an interface, a static method is assumed to be public and will not compile if marked as private or protected. 2. To reference the static method, a reference to the name of the interface must be used. public interface Hop { static int getJumpHeight() { return 8; } } The compiler will automatically insert the access modifier public since all methods in interfaces are assumed to be public. public class Bunny implements Hop { public void printDetails() { System.out.println(getJumpHeight()); // DOES NOT COMPILE } } ---- public class Bunny implements Hop { public void printDetails() { System.out.println(Hop.getJumpHeight()); } } |
Implementing Interfaces
Static Interface Methods |
A class that implements two interfaces containing static methods with the same signature will still compile at runtime, because the static methods are not inherited by the subclass and must be accessed with a reference to the interface name.
|
Understanding Polymorphism
|
Java supports polymorphism, the property of an object to take on many different forms. To put this more precisely, a Java object may be accessed using a reference with the same type as the object, a reference that is a superclass of the object, or a reference that defines an interface the object implements, either directly or through a superclass. Furthermore, a cast is not required if the object is being reassigned to a super type or interface of the object.
|
Understanding Polymorphism
|
Only one object, Lemur, is created and referenced. The ability of an instance of Lemur to be passed as an instance of an interface it implements, HasTail, as well as an instance of one of its superclasses, Primate,
is the nature of polymorphism. Once the object has been assigned a new reference type, only the methods and variables available to that reference type are callable on the object without an explicit cast. HasTail hasTail = lemur; System.out.println(hasTail.age); // DOES NOT COMPILE Primate primate = lemur; System.out.println(primate.isTailStriped()); // DOES NOT COMPILE In this example, the reference hasTail has direct access only to methods defi ned with the HasTail interface; therefore, it doesn’t know the variable age is part of the object. Likewise, the reference primate has access only to methods defi ned in the Primate class, and it doesn’t have direct access to the isTailStriped() method. |
Understanding Polymorphism
Object vs. Reference |
In Java, all objects are accessed by reference. Conceptually, though, you should consider the object as the entity that exists in memory, allocated by the Java runtime environment.
Since all objects inherit java.lang.Object, they can all be reassigned to java.lang.Object: Lemur lemur = new Lemur(); Object lemurAsObject = lemur; Even though the Lemur object has been assigned a reference with a different type, the object itself has not changed and still exists as a Lemur object in memory. Rules: 1. The type of the object determines which properties exist within the object in memory. 2. The type of the reference to the object determines which methods and variables are accessible to the Java program. |
Understanding Polymorphism
Casting Objects |
Rules:
1. Casting an object from a subclass to a superclass doesn’t require an explicit cast. 2. Casting an object from a superclass to a subclass requires an explicit cast. 3. The compiler will not allow casts to unrelated types. 4. Even when the code compiles without issue, an exception may be thrown at runtime if the object being cast is not actually an instance of that class. public class Bird {} public class Fish { public static void main(String[] args) { Fish fish = new Fish(); Bird bird = (Bird)fish; // DOES NOT COMPILE } } ----- public class Rodent { } public class Capybara extends Rodent { public static void main(String[] args) { Rodent rodent = new Rodent(); Capybara capybara = (Capybara)rodent; // Throws ClassCastException at runtime } } The thing to keep in mind in this example is the object that was created is not related to the Capybara class in any way. |
Understanding Polymorphism
Casting Objects |
keep in mind that the instanceof operator can be used to check whether an object belongs to a particular class and to prevent ClassCastExceptions at runtime.
if(rodent instanceof Capybara) { Capybara capybara = (Capybara)rodent; } |
Understanding Polymorphism
Virtual Methods |
A virtual method is a method in which the specific implementation is not determined until runtime. In fact, all non-final, nonstatic, and non-private Java methods are considered virtual methods, since any of them can
be overridden at runtime. |
Understanding Polymorphism
Polymorphic Parameters |
One of the most useful applications of polymorphism is the ability to pass instances of a subclass or interface to a method.
|
Understanding Polymorphism
Polymorphism and Method Overriding |
The first rule is that an overridden method must be at least as accessible as the method it is overriding.
public class Animal { public String getName() { return "Animal"; } } public class Gorilla extends Animal { protected String getName() { // DOES NOT COMPILE return "Gorilla"; } } public class ZooKeeper { public static void main(String[] args) { Animal animal = new Gorilla(); System.out.println(animal.getName()); } } This example creates an ambiguity problem in the ZooKeeper class. The reference animal.getName() is allowed because the method is public in the Animal class, but due to polymorphism, the Gorilla object itself has been overridden with a less accessible version, not available to the ZooKeeper class. This creates a contradiction in that the compiler should not allow access to this method, but because it is being referenced as an instance of Animal, it is allowed. |
Understanding Polymorphism
Polymorphism and Method Overriding |
Therefore, Java eliminates this contradiction, thus disallowing a method from being overridden by a less accessible version of the method.Likewise, a subclass cannot declare an overridden method with a new or broader exception than in the superclass, since the method may be accessed using a reference to the superclass. For example, if an instance of the subclass is passed to a method using a superclass reference, then the enclosing method would not know about any new checked exceptions that exist on methods for this object, potentially leading to compiled code with “unchecked” checked exceptions. Therefore, the Java compiler disallows overriding methods with new or broader exceptions.
Finally, overridden methods must use covariant return types for the same kinds of reasons as just discussed. If an object is cast to a superclass reference and the overridden method is called, the return type must be compatible with the return type of the parent method. |
Understanding Polymorphism
Polymorphism and Method Overriding |
If the return type in the child is too broad, it will result an inherent cast exception when accessed through the superclass reference.
For example, if the return type of a method is Double in the parent class and is overridden in a subclass with a method that returns Number, a superclass of Double, then the subclass method would be allowed to return any valid Number, including Integer, another subclass of Number. If we are using the object with a reference to the superclass, that means an Integer could be returned when a Double was expected. Since Integer is not a subclass of Double, this would lead to an implicit cast exception as soon as the value was referenced. Java solves this problem by only allowing covariant return types for overridden methods. |
Chapter 6: Exceptions
Understanding Exception Understanding Exception Types |
Error means something went so horribly wrong that your program should not attempt to recover from it. For example, the disk drive “disappeared.” These are abnormal conditions that you aren’t likely to encounter.
A runtime exception is defi ned as the untimeException class and its subclasses. Runtime exceptions tend to be unexpected but not necessarily fatal. For example, accessing an invalid array index is unexpected. Runtime exceptions are also known as unchecked exceptions. A checked exception includes Exception and all subclasses that do not extend RuntimeException. Checked exceptions tend to be more anticipated—for example, trying to read a fi le that doesn’t exist. For checked exceptions, Java requires the code to either handle them or declare them in the method signature. void fall() throws Exception { throw new Exception(); } |
Understanding Exception
Throwing an Exception |
String[] animals = new String[0];
System.out.println(animals[0]); This code throws an ArrayIndexOutOfBoundsException. throw new Exception(); throw new Exception("Ow! I fell."); throw new RuntimeException(); throw new RuntimeException("Ow! I fell."); The throw keyword tells Java you want some other part of the code to deal with the exception. |
Using a try Statement
|
try // DOES NOT COMPILE
fall(); catch (Exception e) System.out.println("get up"); The problem is that the braces are missing. It needs to look like this: try statements are like methods in that the curly braces are required even if there is only one statement inside the code blocks. if statements and loops are special in this respect as they allow you to omit the curly braces. try {// DOES NOT COMPILE fall(); } This code doesn’t compile because the try block doesn’t have anything after it. |
Using a try Statement
Adding a finally Block |
There are two paths through code with both a catch and a finally. If an exception is thrown, the finally block is run after the catch block. If no exception is thrown, the finally block is run after the try block completes.
a try statement must have catch and/or finally. 25: try { // DOES NOT COMPILE 26: fall(); 27: } finally { 28: System.out.println("all better"); 29: } catch (Exception e) { 30: System.out.println("get up"); 31: } 32: 33: try { // DOES NOT COMPILE 34: fall(); 35: } 36: 37: try { 38: fall(); 39: } finally { 40: System.out.println("all better"); 41: } finally is typically used to close resources such as files or databases. When System.exit is called in the try or catch block, finally does not run. |
Using a try Statement
Catching Various Types of Exceptions |
A rule exists for the order of the catch blocks. Java looks at them in the order they appear. If it is impossible for one of the catch blocks to be executed, a compiler error
about unreachable code occurs. This happens when a superclass is caught before a subclass. Remember, we warned you to pay attention to any subclass exceptions. class AnimalsOutForAWalk extends RuntimeException { } class ExhibitClosed extends RuntimeException { } class ExhibitClosedForLunch extends ExhibitClosed { } public void visitMonkeys() { try { seeAnimal(); } catch (ExhibitClosedForLunch e) {// subclass exception System.out.print("try back later"); } catch (ExhibitClosed e) {// superclass exception System.out.print("not today"); } } public void visitMonkeys() { try { seeAnimal(); } catch (ExhibitClosed e) { System.out.print("not today"); } catch (ExhibitClosedForLunch e) {// DOES NOT COMPILE System.out.print("try back later"); } } |
Using a try Statement
Throwing a Second Exception |
26: try {
27: throw new RuntimeException(); 28: } catch (RuntimeException e) { 29: throw new RuntimeException(); 30: } finally { 31: throw new Exception(); 32: } Since the finally block throws an exception of its own on line 31, this one gets thrown. The exception from the catch block gets forgotten about. 30: public String exceptions() { 31: String result = ""; 32: String v = null; 33: try { 34: try { 35: result += "before"; 36: v.length(); 37: result += "after"; 38: } catch (NullPointerException e) { 39: result += "catch"; 40: throw new RuntimeException(); 41: } finally { 42: result += "finally"; 43: throw new Exception(); 44: } 45: } catch (Exception e) { 46: result += "done"; 47: } 48: return result; 49: } The correct answer is before catch finally done. |
Recognizing Common Exception Types
Runtime Exceptions |
Runtime exceptions extend RuntimeException. They don’t have to be handled or declared. They can be thrown by the programmer or by the JVM.
ArithmeticException: Trying to divide an int by zero gives an undefined result. When this occurs, the JVM will throw an ArithmeticException: int answer = 11 / 0; Running this code results in the following output: Exception in thread "main" java.lang.ArithmeticException: / by zero ArrayIndexOutOfBoundsException: int total = 0; int[] countsOfMoose = new int[3]; for (int i = 0; i <= countsOfMoose.length; i++) total += countsOfMoose[i]; The problem is that the for loop should have < instead of <=.The output looks like this: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 ClassCastException: String type = "moose"; Object obj = type; Integer number = (Integer) obj; Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer |
Recognizing Common Exception Types
Runtime Exceptions |
IllegalArgumentException:
public static void setNumberEggs(int numberEggs) { if (numberEggs < 0) throw new IllegalArgumentException( "# eggs must not be negative"); this.numberEggs = numberEggs; } The program throws an exception when it’s not happy with the parameter values. The output looks like this: Exception in thread "main" java.lang.IllegalArgumentException: # eggs must not be negative NullPointerException: String name; public void printLength() throws NullPointerException { System.out.println(name.length()); } Running this code results in this output: Exception in thread "main" java.lang.NullPointerException NumberFormatException:NumberFormatException is a subclass of IllegalArgumentException. Integer.parseInt("abc"); The output looks like this: Exception in thread "main" java.lang.NumberFormatException: For input string: "abc" |
Recognizing Common Exception Types
Checked Exceptions |
Checked exceptions have Exception in their hierarchy but not RuntimeException. They must be handled or declared. They can be thrown by the programmer or by the JVM.
FileNotFoundException: Thrown programmatically when code tries to reference a file that does not exist IOException: Thrown programmatically when there’s a problem reading or writing a file. Also keep in mind that FileNotFoundException is a subclass of IOException, |
Recognizing Common Exception Types
Errors |
Errors extend the Error class. They are thrown by the JVM and should not be handled or declared.
ExceptionInInitializerError:Java runs static initializers the fi rst time a class is used. If one of the static initializers throws an exception, Java can’t start using the class. It declares defeat by throwing an ExceptionInInitializerError. static { int[] countsOfMoose = new int[3]; int num = countsOfMoose[-1]; } public static void main(String[] args) { } This code yields information about two exceptions: Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.ArrayIndexOutOfBoundsException: -1 |
Recognizing Common Exception Types
Errors |
StackOverflowError: When Java calls methods, it puts parameters and local variables on the stack.After doing this a very large number of times, the stack runs out of room and overfl ows. This is called a StackOverflowError.
public static void doNotCodeThis(int num) { doNotCodeThis(1); } The output contains this line: Exception in thread "main" java.lang.StackOverflowError This is called infinite recursion. It is better than an infinite loop because at least Java will catch it and throw the error. With an infinite loop, Java just uses all your CPU until you can kill it. NoClassDefFoundError: NoClassDefFoundError occurs when Java can’t find the class at runtime. |
Calling Methods That Throw Exceptions
|
class NoMoreCarrotsException extends Exception {}
public class Bunny { public static void main(String[] args) { eatCarrot();// DOES NOT COMPILE } private static void eatCarrot() throws NoMoreCarrotsException { } } fix: public static void main(String[] args) throws NoMoreCarrotsException {// declare exception eatCarrot(); } public static void main(String[] args) { try { eatCarrot(); } catch (NoMoreCarrotsException e ) {// handle exception System.out.print("sad rabbit"); } } ------- public void bad() { try { eatCarrot(); } catch (NoMoreCarrotsException e ) {// DOES NOT COMPILE System.out.print("sad rabbit"); } } public void good() throws NoMoreCarrotsException { eatCarrot(); } private static void eatCarrot() { } Java knows that eatCarrot() can’t throw a checked exception—which means there’s no way for the catch block in bad() to be reached. In comparison, good() is free to declare other exceptions. |
Calling Methods That Throw Exceptions
Subclasses |
A subclass is allowed to declare fewer exceptions than the superclass or interface. This is legal because callers are already handling them.
class Hopper { public void hop() throws CanNotHopException { } } class Bunny extends Hopper { public void hop() { } } ---- class Hopper { public void hop() throws Exception { } } class Bunny extends Hopper { public void hop() throws CanNotHopException { } } Bunny could declare that it throws Exception directly, or it could declare that it throws a more specifi c type of Exception. It could even declare that it throws nothing at all. This rule applies only to checked exceptions. class Hopper { public void hop() { } } class Bunny extends Hopper { public void hop() throws IllegalStateException { } } The reason that it’s okay to declare new runtime exceptions in a subclass method is that the declaration is redundant. Methods are free to throw any runtime exceptions they want without mentioning them in the method declaration |
Calling Methods That Throw Exceptions
Printing an Exception |
5: public static void main(String[] args) {
6: try { 7: hop(); 8: } catch (Exception e) { 9: System.out.println(e); 10: System.out.println(e.getMessage()); 11: e.printStackTrace(); 12: } 13: } 14: private static void hop() { 15: throw new RuntimeException("cannot hop"); 16: } This code results in the following output: java.lang.RuntimeException: cannot hop cannot hop java.lang.RuntimeException: cannot hop at trycatch.Handling.hop(Handling.java:15) at trycatch.Handling.main(Handling.java:7) |