Java Collections (Best Tutorial 2019)

Java Collections

Java collections

Almost all applications perform tasks against user data. Sometimes data is obtained from a user, tasks are performed against the data, and the result is returned immediately.

 

More often, data is obtained, and then it is stored within the application for later use, and eventually, tasks are performed against it. Applications make use of data structures to store data that can be utilized throughout the lifetime of an application instance.

 

The Java language contains a number of data structures that are known as Collection types, and they can be utilized for this purpose. These data structures implement the java.util.Collection interface, which provides a variety of methods that are useful for adding, removing, and performing tasks against the data that is used with the collection.

 

Java 8 changed the game when it comes to data structures and Collection types. The concepts of pipelines and streams were introduced, enabling easy iteration and operations against data contained within Collection types. In prior releases of Java, the developer had to tell the compiler how to iterate over data within a Collection.

 

Oftentimes in the past, developers utilized a loop to perform iterative tasks on data structures. Java 8 enabled developers to begin utilizing streams for iterative tasks on Collection types.

 

When using streams and pipeline of operations on collections, the developer specifies what type of operation to perform, and the JDK decides how to do it. This reduces the burden on a developer by reducing boilerplate code and providing an easy-to-use algorithm for working with collections.

 

This blog introduces some of the data structures that can be utilized within a Java application for the storage of user data. It discusses some of the data structures in detail and introduces operations that can be performed on the data.

 

The concepts of pipelines and streams are introduced in this blog, and it provides recipes that demonstrate their usage. Java 8 forces developers to think differently about the way that they write collection code, enabling the development of smarter and more productive solutions

 

Defining a Fixed Set of Related Constants

Java collections Constants

Problem You need a type that can represent a fixed set of related constants.

Solution

Use an enum type. The following example defines an enum type, called FieldType, to represent various form fields you might find on the GUI of an application:

See BasicFieldType.java
public enum FieldType { PASSWORD, EMAIL_ADDRESS, PHONE_NUMBER, SOCIAL_SECURITY_NUMBER }
This is the simplest form of an enum type, which will often suffice when all that is needed is a related set of named constants. In the following code, a field variable of type FieldType is declared and initialized to the FieldType.EMAIL_ADDRESS enum constant. Next, the code prints the results from calling various methods that are defined for all enum types:
FieldType field = FieldType.EMAIL_ADDRESS;
System.out.println("field.name(): " + field.name());
System.out.println("field.ordinal(): " + field.ordinal());
System.out.println("field.toString(): " + field.toString());
System.out.println("field.isEqual(EMAIL_ADDRESS): " + field.equals(FieldType.EMAIL_ADDRESS));
System.out.println("field.isEqual(\"EMAIL_ADDRESS\"'): " + field.equals("EMAIL_ADDRESS"));
System.out.println("field == EMAIL_ADDRESS: " + (field == FieldType.EMAIL_ADDRESS));
Won't compile – illustrates type safety of enum
System.out.println("field == \”EMAIL_ADDRESS\": " + (field == "EMAIL_ADDRESS"));
System.out.println("field.compareTo(EMAIL_ADDRESS): " + field.compareTo(FieldType.EMAIL_ADDRESS));
System.out.println("field.compareTo(PASSWORD): " + field.compareTo(FieldType.PASSWORD));
System.out.println("field.valueOf(\"EMAIL_ADDRESS\"): " + field.valueOf("EMAIL_ADDRESS"));
try {
System.out.print("field.valueOf(\"email_address\"): ");
System.out.println(FieldType.valueOf("email_address"));
} catch (IllegalArgumentException e) { System.out.println(e.toString());
}
System.out.println("FieldType.values(): " + Arrays.toString(FieldType.values()));
Running this code will result in the following output:
field.name(): EMAIL_ADDRESS
field.ordinal(): 1
field.toString(): EMAIL_ADDRESS
field.isEqual(EMAIL_ADDRESS): true
field.isEqual("EMAIL_ADDRESS"'): false
field == EMAIL_ADDRESS: true
field.compareTo(EMAIL_ADDRESS): 0
field.compareTo(PASSWORD): 1
field.valueOf("EMAIL_ADDRESS"): EMAIL_ADDRESS
field.valueOf("email_address"): java.lang.IllegalArgumentException: No enum constant org. java9recipes.blog4.BasicEnumExample.FieldType.email_address FieldType.values(): [PASSWORD, EMAIL_ADDRESS, PHONE_NUMBER, SSN]

 

How It Works

A common pattern for representing a fixed set of related constants is to define each constant as an int, String, or some other data type. Often, these constants are defined in a class or interface whose sole purpose is to encapsulate constants. In any case, constants are sometimes defined with the static and final modifiers, as follows:

// Input field constants
public static final int PASSWORD = 0;
public static final int EMAIL_ADDRESS = 1;
public static final int PHONE_NUMBER = 2;
public static final int SOCIAL_SECURITY_NUMBER = 3;

There are multiple problems with this pattern, the primary issue being the lack of type safety. By defining these constants as ints, it is possible to assign an invalid value to a variable that is supposed to be allowed to hold only one of the constant values:

int inputField = PHONE_NUMBER; // OK

inputField = 4; // Bad - no input field constant with value 4; compiles without error

 

As you can see, there will be no compiler error or warning produced to inform you of this invalid value assignment. Chances are, you will discover this at runtime when your application tries to use inputField, and an incorrect value is assigned to it. In contrast, Java enum types provide compile-time type safety.

 

That is, if one attempts to assign a value of the wrong type to an enum variable, it will result in a compiler error. 

 

In the solution this recipe, the FieldType.EMAIL_ADDRESS enum constant was assigned to the field variable. Attempting to assign a value that isn’t of type FieldType naturally results in a compiler error:

 

FieldType field = FieldType.EMAIL_ADDRESS; // OK field = "EMAIL_ADDRESS"; // Wrong type - compiler error

 

An enum is simply a special type of class. Under the covers, Java implements an enum type as a subclass of the abstract and final java.lang.Enum class. Thus, an enum type cannot be instantiated directly (outside of the enum type) or extended. The constants defined by an enum type are actually instances of the enum type.

 

The java.lang.Enum class defines a number of final methods that all enum types inherit. In addition, all enum types have two implicitly declared static methods: values() and valueOf(String). The solution code demonstrates these static methods and some of the more often used instance methods.

common pattern

Most of these methods are fairly self-explanatory, but you should keep the following details in mind:

 

Each enum constant has an ordinal value representing its relative position in the enum declaration. The first constant in the declaration is assigned an ordinal value of zero.

 

The ordinal() method can be used to retrieve an enum constant’s ordinal value; however, it is not recommended that applications be written to depend on this value for maintainability reasons.

 

The name() method and the default implementation of the toString() method both return a String representation of the enum constant (toString() actually calls name()).

 

It is common for toString() to be overridden to provide a more user-friendly String representation of the enum constant. For this reason, and for maintainability reasons, it is recommended that toString() be used in preference to name().

 

When testing for equality, note that both the equals() method and == perform reference comparison. They can be used interchangeably. However, it is recommended that == be used to take advantage of compile-time type safety.

 

This is illustrated in the solution code. Performing equals() comparison with a String parameter, for example, may allow the error to go unnoticed; it will compile, but it will always return false.

 

Conversely, attempting to compare an enum with a String using the == comparison would result in an error at compile time. When you have the choice of catching errors sooner (at compile time) rather than later (at runtime), choose the former.

 

The implicitly declared static methods values() and valueOf(String) do not appear in the Java documentation or the source code for the java.lang.Enum class. However, the Java Language Specification does detail their required implementations.

 

To summarize these methods, values() returns an array containing the constants of the enum, in the order they are declared. The valueOf(String) method returns the enum constant whose name exactly matches (including case) the value of the String argument, or throws an IllegalArgumentException if there is no enum constant with the specified name.

 

Refer to the online Java documentation for further details on java.lang.Enum and each of its methods (Enum (Java SE 9 & JDK 9 )). As the next recipe demonstrates, enum types, as full-fledged Java classes, can be used to build more intelligent constants.

 

Designing Intelligent Constants

Designing Intelligent Constants

Problem

You need a type that can represent a fixed set of related constants, and you would like to build some state and behavior (logic) around your constants in an object-oriented fashion.

 

Solution

Use an enum type and take advantage of type safety and the fact that enum types are full-fledged Java classes. An enum type can have state and behavior just like any other class, and the enum constants, themselves being instances of the enum type, inherit this state and behavior. This is best illustrated by an example.

 

Let’s expand on the example from the previous recipe. Imagine that you need to process and validate all the fields from an HTML form that has been submitted. 

 

Each form field has a unique set of rules for validating its content, based on the field type. For each form field, you have the field’s “name” and the value that was entered into that form field. The FieldType enum can be expanded to handle this very easily:

See FieldType.java public enum FieldType {
PASSWORD(FieldType.passwordFieldName) {
A password must contain one or more digits, one or more lowercase letters, one or
more uppercase letters, and be a minimum of 6 characters in length.
//
@Override
public boolean validate(String fieldValue) {
return Pattern.matches("((?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{6,})", fieldValue);
}
},
EMAIL_ADDRESS(FieldType.emailFieldName) {
An email address begins with a combination of alphanumeric characters, periods,and hyphens, followed by a mandatory ampersand ('@') character, followed by a combination of alphanumeric characters (hyphens allowed), followed by a
one or more periods (to separate domains and subdomains), and ending in 2-4 alphabetic characters representing the domain.
//
@Override
public boolean validate(String fieldValue) {
return Pattern.matches("^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z|a-z]{2,4}$", fieldValue);
}
},
PHONE_NUMBER(FieldType.phoneFieldName) {
A phone number must contain a minium of 7 digits. Three optional digits
representing the area code may appear in front of the main 7 digits. The area
code may, optionally, be surrounded by parenthesis. If an area code is included,
the number may optionally be prefixed by a '1' for long distance numbers.
Optional hypens my appear after the country code ('1'), the area code, and the
first 3 digits of the 7 digit number.
//
@Override
public boolean validate(String fieldValue) {
return Pattern.matches("^1?[- ]?\\(?(\\d{3})\\)?[- ]?(\\d{3})[- ]?(\\d{4})$", fieldValue);
}
},
SOCIAL_SECURITY_NUMBER(FieldType.ssnFieldName) {
A social security number must contain 9 digits with optional hyphens after the
third and fifth digits.
//
@Override
public boolean validate(String fieldValue) {
return Pattern.matches("^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$",
fieldValue);
}
}; // End of enum constants definition
Instance members
private String fieldName;
Define static constants to increase type safety static final String passwordFieldName = "password"; static final String emailFieldName = "email"; static final String phoneFieldName = "phone"; static final String ssnFieldName = "ssn";
private FieldType(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldName() {
return this.fieldName;
}
abstract boolean validate(String fieldValue);
Static class members
private static final Map<String, FieldType> nameToFieldTypeMap = new HashMap<>(); static { for (FieldType field : FieldType.values()) { nameToFieldTypeMap.put(field.getFieldName(), field); } } public static FieldType lookup(String fieldName) { return nameToFieldTypeMap.get(fieldName.toLowerCase()); } private static void printValid(FieldType field, String fieldValue, boolean valid) { System.out.println(field.getFieldName() + "(\"" + fieldValue + "\") valid: " + valid); } public static void main(String... args) { String fieldName=FieldType.passwordFieldName; String fieldValue="1Cxy9"; // invalid - must be at least 6 characters FieldType field=lookup(fieldName); printValid(field, fieldValue, field.validate(fieldValue)); fieldName=FieldType.phoneFieldName; fieldValue="1-800-555-1234"; // valid field=lookup(fieldName); printValid(field, fieldValue, field.validate(fieldValue)); fieldName=FieldType.emailFieldName; fieldValue="john@doe"; // invalid - missing .<tld> field = lookup(fieldName);
printValid(field, fieldValue, field.validate(fieldValue));
fieldName = FieldType.ssnFieldName;
fieldValue = "111-11-1111"; // valid
field = lookup(fieldName);
printValid(field, fieldValue, field.validate(fieldValue));
}
}
Running the preceding code results in the following output:
password("1Cxy9") valid: false
phone("1-800-555-1234") valid: true
email("john@doe") valid: false
ssn("111-11-1111") valid: true

 

How It Works

Java collections

Notice that the enhanced FieldType enum now defines a fieldName instance variable and a constructor with a fieldName String argument for initializing the instance variable. Each enum constant (again, each constant being an instance of FieldType) must be instantiated with a fieldName.

 

FieldType also defines an abstract validate(String) method that each enum constant must implement to perform the field validation.

 

Here, each FieldType’s validate() method applies a regular expression match against the field value and returns the Boolean result of the match. Imagine the following form input fields corresponding to our FieldType instances:

<input type="password" name="password" value=""/> <input type="tel" name="phone" value=""/> 
<input type="email" name="email" value=""/> <input type="text" name="ssn" value=""/>

 

The value of the input field’s name attribute will be used to identify the FieldType; you used this same name when you instantiated each FieldType enum constant.

 

When a form is submitted, you have access to each input field’s name and the value that was entered into the field. You need to be able to map the field’s name to a FieldType and call the validate() method with the input value. The class variable, nameToFieldTypeMap, is declared and initialized for this purpose.

 

For each FieldType enum constant, nameToFieldTypeMap stores an entry with the field name as the key, and the FieldType as the value. The lookup(String) class method uses this map to look up the FieldType from the field name. The code to validate an e-mail input field with an input value of john@doe.com is quite concise:

<input type="email" name="email" value="john@doe.com"/> String fieldName = FieldType.emailFieldName;
String fieldValue = "john@doe.com";
boolean valid = FieldType.lookup(fieldName).validate(fieldValue);

The main() method shows an example validation for each of the FieldTypes. The printValid() method prints the field name, field value, and the field’s validation result.

 

This recipe has demonstrated that there is a lot more potential in the enum type than just the ability to define a set of named constants. Enum types have all the power of a normal class, plus additional features that allow you to create well-encapsulated and intelligent constants.

 

Executing Code Based on a Specified Value

Executing Code

Problem: You want to execute different blocks of code based on the value of a singular expression.

Solution

Consider using a switch statement if your variable or expression result is one of the allowed switch types and you want to test for equality against a type-compatible constant. These examples show various ways to use the switch statement, including a new feature that became available in Java 7: the ability to switch on Strings.

 

First, let’s play some Rock-Paper-Scissors! The rock paper scissors class shows two different switch statements: one using an int as the switch expression type, and the other using an enum type.

See RockPaperScissors.java
public class RockPaperScissors {
enum Hand { ROCK, PAPER, SCISSORS, INVALID };
private static void getHand(int handVal) {
Hand hand;
try {
hand = Hand.values()[handVal - 1];
}
catch (ArrayIndexOutOfBoundsException ex) {
hand = Hand.INVALID;
}
switch (hand) {
case ROCK:
System.out.println("Rock");
break;
case PAPER:
System.out.println("Paper");
break;
case SCISSORS:
System.out.println("Scissors");
break;
default:
System.out.println("Invalid");
}
}
private static void playHands(int yourHand, int myHand) {
Rock = 1
Paper = 2
Scissors = 3
Hand combinations:
1,1; 2,2; 3,3 => Draw
1,2 => sum = 3 => Paper
1,3 => sum = 4 => Rock
2,3 => sum = 5 => Scissors
switch ((yourHand == myHand) ? 0 : (yourHand + myHand)) { case 0:
System.out.println("Draw!");
break;
case 3:
System.out.print("Paper beats Rock. "); printWinner(yourHand, 2);
break;
case 4:
System.out.print("Rock beats Scissors. "); printWinner(yourHand, 1);
break;
case 5:
System.out.print("Scissors beats Paper. "); printWinner(yourHand, 3);
break;
default:
System.out.print("You cheated! "); printWinner(yourHand, myHand);
}
}
private static void printWinner(int yourHand, int winningHand) { if (yourHand == winningHand) {
System.out.println("You win!");
}
else {
System.out.println("I win!");
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in); System.out.println("Let's Play Rock, Paper, Scissors"); System.out.println(" Enter 1 (Rock)"); System.out.println(" Enter 2 (Paper)"); System.out.println(" Enter 3 (Scissors)"); System.out.print("> ");
int playerHand = input.hasNextInt() ? input.nextInt() : -99; int computerHand = (int)(3*Math.random()) + 1;
System.out.print("Your hand: (" + playerHand + ") "); getHand(playerHand);
System.out.print("My hand: (" + computerHand + ") ");
getHand(computerHand);
playHands(playerHand, computerHand);
}
}

When the RockPaperScissors class is executed, an interactive game begins, allowing users to type input at the keyboard. The users can type the number corresponding to the entry they’d like to choose, and the computer utilizes random number calculations to try to beat the users’ choices.

 

Java 7 added the capability to switch on Strings. The SwitchTypeChecker class demonstrates the use of a String as the switch expression type. The isValidSwitchType() method takes a Class object and determines whether the corresponding type is a valid type that can be used in a switch expression.

 

So, SwitchTypeChecker is using a switch statement to simultaneously demonstrate switching on Strings and to show the valid types for use in a switch expression:

 

See SwitchTypeChecker.java

public class SwitchTypeChecker {
public static Class varTypeClass(Object o) { return o.getClass(); };
public static Class varTypeClass(Enum e) { return e.getClass().getSuperclass(); }; public static Class varTypeClass(char c) { return char.class; };
public static Class varTypeClass(byte b) { return byte.class; }; public static Class varTypeClass(short s) { return short.class; }; public static Class varTypeClass(int i) { return int.class; }; public static Class varTypeClass(long l) { return long.class; }; public static Class varTypeClass(float f) { return float.class; }; public static Class varTypeClass(double d) { return double.class; }; public static Class varTypeClass(boolean d) { return boolean.class; };
public void isValidSwitchType(Class typeClass) { String switchType = typeClass.getSimpleName(); boolean valid = true;
switch (switchType) {
case "char":
case "byte":
case "short":
case "int":
System.out.print("Primitive type " + switchType); break;
case "Character":
case "Byte":
case "Short":
case "Integer":
System.out.print("Boxed primitive type " + switchType); break;
case "String":
case "Enum":
System.out.print(switchType);
break;
default: // invalid switch type
System.out.print(switchType);
valid = false;
}
System.out.println(" is " + (valid ? "" : "not ") + "a valid switch type.");
}
public static void main(String[] args) { SwitchTypeChecker check = new SwitchTypeChecker(); check.isValidSwitchType(varTypeClass('7')); check.isValidSwitchType(varTypeClass(7)); check.isValidSwitchType(varTypeClass(777.7d)); check.isValidSwitchType(varTypeClass((short)7)); check.isValidSwitchType(varTypeClass(new Integer(7))); check.isValidSwitchType(varTypeClass("Java 8 Rocks!")); check.isValidSwitchType(varTypeClass(new Long(7))); check.isValidSwitchType(varTypeClass(true)); check.isValidSwitchType(varTypeClass(java.nio.file.AccessMode.READ));
}
}
Here is the result of executing SwitchTypeChecker:
Primitive type char is a valid switch type.
Primitive type int is a valid switch type.
double is not a valid switch type.
Primitive type short is a valid switch type.
Boxed primitive type Integer is a valid switch type.
String is a valid switch type.
Long is not a valid switch type.
boolean is not a valid switch type.
Enum is a valid switch type.

 

How It Works

How Java collections Works

The switch statement is a control flow statement that allows you to execute different blocks of code based on the value of a switch expression.

 

It is similar to the if-then-else statement, except that the switch statement can have only a single test expression, and the expression type is restricted to one of several different types. When a switch statement executes, it evaluates the expression against constants contained in the switch statement’s case labels.

 

These case labels are branch points in the code. If the value of the expression equals the value of a case label constant, control is transferred to the section of code that corresponds to the matching case label.

 

All code statements from that point on are then executed until either the end of the switch statement is reached or a break statement is reached.

 

The break statement causes the switch statement to terminate, with control being transferred to the statement following the switch statement. Optionally, the switch statement can contain a default label, which provides a branch point for the case when there is no case label constant that equates to the switch expression value.

 

The SwitchTypeChecker isValidSwitchType() method demonstrates the use of a String as the switch test expression. If you study closely the isValidSwitchType() method, you will see that it is testing whether a Class object represents a type that corresponds to one of the valid switch expression types.

 

The method also demonstrates how case labels can be grouped to implement a logical OR conditional test. 

If a case label does not have any associated code to execute, and no break statement, the flow of execution falls through to the next closest case label containing executable statements, thus allowing common code to be executed if the result of the switch expression matches any one of the grouped case constants.

 

The rock paper scissors class implements a command-line Rock-Paper-Scissors game, where you are playing against the computer. There are two methods in this class that demonstrate the switch statement. The getHand() method shows the use of an enum variable in the switch expression.

 

The playHands() method simply intends to show that the switch expression, although often just a variable, can be any expression whose result is of one of the allowed switch types. In this case, the expression is using a ternary operator that returns an int value.

 

Working with Fix-Sized Arrays

Working with Fix-Sized Arrays

Problem

You need a simple data structure that can store a fixed (and possibly large) amount of same-typed data and provide for fast sequential access.

 

Solution

Consider using an array. While Java provides more sophisticated and flexible Collection types, the array type can be useful data structure for many applications. The following example demonstrates the simplicity of working with arrays.

 

The GradeAnalyzer class provides a means for calculating various grade-related statistics, such as the mean (average) grade, minimum grade, and maximum grade.

 

See GradeAnalyzer.java

public class GradeAnalyzer {
The internal grades array private int[] _grades;
public void setGrades(int[] grades) {
this._grades = grades;
}
Return cloned grades so the caller cannot modify our internal grades public int[] getGrades() {
return _grades != null ? _grades.clone() : null;
}
public int meanGrade() {
int mean = 0;
if (_grades != null&& _grades.length > 0) {
int sum = 0;
for (int i = 0; i < _grades.length; i++) {
sum += _grades[i];
}
mean = sum / _grades.length;
}
return mean;
}
public int minGrade() {
int min = 0;
for (int index = 0; index < _grades.length; index++) { if (_grades[index] < min) {
min = _grades[index];
}
}
return min;
}
public int maxGrade() {
int max = 0;
for (int index = 0; index < _grades.length; index++) { if (_grades[index] > max) {
max = _grades[index];
}
}
return max;
}
static int[] initGrades1() {
int[] grades = new int[5];
grades[0] = 77;
grades[1] = 48;
grades[2] = 69;
grades[3] = 92;
grades[4] = 87;
return grades;
}
static int[] initGrades2() {
int[] grades = { 57, 88, 67, 95, 99, 74, 81 }; return grades;
}
static int[] initGrades3() {
return new int[]{ 100, 70, 55, 89, 97, 98, 82 };
}
public static void main(String... args) {
GradeAnalyzer ga = new GradeAnalyzer();
ga.setGrades(initGrades1());
System.out.println("Grades 1:");
System.out.println("Mean of all grades is " + ga.meanGrade());
System.out.println("Min grade is " + ga.minGrade());
System.out.println("Max grade is " + ga.maxGrade());
ga.setGrades(initGrades2());
System.out.println("Grades 2:");
System.out.println("Mean of all grades is " + ga.meanGrade()); System.out.println("Min grade is " + ga.minGrade());
System.out.println("Max grade is " + ga.maxGrade());
ga.setGrades(initGrades3());
System.out.println("Grades 3:");
System.out.println("Mean of all grades is " + ga.meanGrade());
System.out.println("Min grade is " + ga.minGrade());
System.out.println("Max grade is " + ga.maxGrade());
Object testArray = ga.getGrades();
Class testClass = testArray.getClass();
System.out.println("isArray: " + testClass.isArray());
System.out.println("getClass: " + testClass.getName());
System.out.println("getSuperclass: " + testClass.getSuperclass().getName());
System.out.println("getComponentType: " + testClass.getComponentType());
System.out.println("Arrays.toString: " + Arrays.toString((int[])testArray));
}
}
Running this code will result in the following output:
Grades 1:
Mean of all grades is 74
Min grade is 48
Max grade is 92
Grades 2:
Mean of all grades is 80
Min grade is 57
Max grade is 99
Grades 3:
Mean of all grades is 84
Min grade is 55
Max grade is 100
isArray: true
getClass: [I
getSuperclass: class java.lang.Object
getComponentType: int
Arrays.toString: [55, 70, 82, 89, 97, 98, 100]

 

How It Works

How Java collections

The Java array type works a bit differently than Java’s ArrayList (part of the Java Collections Framework). Java arrays hold a fixed amount of data. That is, when an array is created, you must specify how much data it can hold. Once an array has been created, you cannot insert or remove array items or otherwise change the size of the array.

 

However, if you have a fixed amount (and especially a very large amount) of data that you just need to work on while iterating over it sequentially, an array may be a good choice.

 

The first thing you need to know about the Java array type is that it is an Object type. All arrays, regardless of the type of data they contain, have Object as their superclass. The elements of an array may be of any type, as long as all elements are of the same type—either primitive or object reference.

 

Regardless of the array type, the memory for an array is always allocated out of the heap space for the application. The heap is the area of memory used by the JVM for dynamic memory allocation.

 

Note It is possible to create an array of Objects (Object[]) that can hold references to objects of different types; however, this is not recommended, as it requires you to check the type of elements and perform explicit type casting when retrieving elements from the array.

 

There are two steps to completely defining an array object in Java: array variable declaration, which specifies the array element type, and array creation, which allocates the memory for the array.

 

Once an array is declared and the memory is allocated, it can be initialized. There are multiple ways to initialize an array, which are shown in the solution to this recipe.

 

If you know in advance what data you need to store in the array, you can combine array declaration, creation, and initialization in one step using a shortcut syntax you will see demonstrated in the solution.

methods

 

Let’s walk through the GradeAnalyzer class and examine the various ways to declare, create, initialize, and access arrays. First, notice that the class has one instance variable to hold the grades to be analyzed:

private int[] _grades;

 

Like all other uninitialized Object reference instance variables, the _grades array instance variable is automatically initialized to null. Before you can start analyzing grades, you have to set the _grades instance variable to reference the grades data you want to analyze.

 

This is done using the setGrades(int[]) method. Once GradeAnalyzer has a collection of grades to analyze, the mean grade(), minGrade(), and maxGrade() methods can be called upon to compute their respective statistics.

 

Together, these three methods demonstrate how to iterate over the elements of an array, how to access elements of an array, and how to determine the number of elements an array can hold. To determine the number of elements an array can hold, simply access the implicitly defined, final instance variable, length, which is available for all arrays:

_grades.length

 

To iterate over the elements of an array, simply use a for loop, whose index variable goes through all possible indices of the array. Array indices start at 0, so the last array index is always (_grades.length - 1).

 

While iterating over the array, you can access the array element at the current index by using the name of the array variable followed by the current index enclosed in brackets (often called an array subscript):

// From the meanGrade() method:
for (int i = 0; i < _grades.length; i++) {
sum += _grades[i];
}
Alternatively, the enhanced for loop, also known as the foreach loop, could be used to iterate over the array (see Recipe 7-7 for more discussion of the foreach loop):
for (int grade : _grades) {
sum += grade;
}


Notice that to determine the min and max grade, the grades are first sorted in their natural (ascending) order using the utility sort method from the java.util.Arrays class. After sorting, the min grade is the simply the first element (at index 0) of the array, and the max grade is the last element (at index length -1) of the array.

 

The three static class methods in the solution, initGrades1(), initGrades2(), and initGrades3(), demonstrate three different ways of creating and initializing the array data you will use to “seed” the GradeAnalyzer.

 

The initGrades1() method declares and creates an array (using new) that can hold five grades, then manually sets the value at each element index to an integer grade value.

 

The initGrades2() method combines array creation and initialization in one line using the special array initializer syntax:

int[] grades = { 57, 88, 67, 95, 99, 74, 81 };

This syntax creates an array with a length of 7 and initializes the elements from index 0 through index 6 with the integer values shown. Note that this syntax can be used only in an array declaration, so the following is not allowed:

int[] grades;

grades = { 57, 88, 67, 95, 99, 74, 81 }; // won't compile

The initGrades3() method looks very similar to initGrades2(), but is slightly different. This code creates and returns an anonymous (unnamed) array:

return new int[]{ 100, 70, 55, 89, 97, 98, 82 };

 

With this syntax, you use the new keyword with the array element type, but the size of the array is not explicitly specified. Similar to the array initializer syntax shown in the initGrades2() method, the array size is implied by the number of elements given within the initializer brackets. So, again, this code is creating and returning an array with a length of 7.

 

After computing the grade statistics for the three sets of grades data, the remainder of the GradeAnalyzer main() method demonstrates various methods that can be used to determine array type information and to convert an array to a printable String.

 

You see that the code first assigns the array returned from a call to the getGrades() instance method to an Object variable called testArray:

 

Object testArray = ga.getGrades();

You can make this assignment because, as stated previously, an array is an Object. You can also see this by the result from the call to testArray.getSuperclass().

 

The call to testArray.getClass().getName() is also interesting; it returns “I.” The left bracket means “I am an array type”, and the “I” means “with a component type of integer.”

 

This is also backed up by the result from the call to testArray.getComponentType(). Finally, you call the Arrays.toString(int[]) method, which returns a nicely formatted String representation of the array and its contents.

 

Notice that because test Array is an Object reference, it must be cast to an int array for the Arrays.toString(int[]) method. (See the Java documentation for the java.util.Arrays class for other useful utility methods that can be used with arrays.)

 

As you have seen, arrays are simple and easy to work with. There will be times when this simplicity works to your advantage. Recipe shows an alternative to the array type that provides for easy insertion and removal of elements: the ArrayList collection class.

 

Safely Enabling Types or Methods to Operate on Objects of Various Types

Objects Java collections


Problem

Your application makes use of many different object types, and there are containers within your class that are available for holding each of these different types.

 

You are interested in ensuring your application remains bug-free, yet you would like to dynamically change the type of object a particular container may hold. In other words, you would like to define a generic container but have the ability to specify its type each time a new instance of the container is instantiated.

 

Solution

Make use of generic types to decouple the type from the container. Generics are a way to abstract over object types, not explicitly declaring what the type of an object or container should be.

 

You’ll likely first encounter generic types when using the interfaces and classes that are part of the Java Collections Framework (http:// download.oracle.com/javase/tutorial/collections/).

 

The Collections Framework makes heavy use of Java generics. All collection types are parameterized to allow you to specify, at the time of instantiation, the type of elements the collection can hold.

 

The following example code demonstrates how to use generics in a couple of different scenarios. The comments in the code indicating where the generics are utilized.

public class MainClass {
static List<Player> team;
private static void loadTeam() {
System.out.println("Loading team...");
Use of the diamond operator team = new ArrayList<>(); Player player1=new Player("Josh", "Juneau", 5); Player player2=new Player("Duke", "Java", 15); Player player3=new Player("Jonathan", "Gennick", 1); Player player4=new Player("Bob", "Smith", 18); Player player5=new Player("Steve", "Adams", 7); team.add(player1); team.add(player2); team.add(player3); team.add(player4); team.add(player5); } public static void main(String[] args) { loadTeam(); Create a list without specifying a type List objectList=new ArrayList(); Object obj1="none"; objectList.add(obj1); Create a List that can be of type that is any superclass of Player List<? super Player> myTeam = objectList;
for (Object p : myTeam) { System.out.println("Printing the objects..."); System.out.println(p.toString());
}
Create a Map of String keys and String values Map<String, String> strMap = new HashMap<>(); strMap.put("first", "Josh"); strMap.put("last", "Juneau"); System.out.println(strMap.values());
}
}

 

Note  When we talk generally about a collection or a collection type, you can read this as those types that make up the Java Collections Framework. This includes all the classes and interfaces that descend from the Collection and Map interfaces. Collection types generally refer to types that descend from the Collection interface.

 

How It Works

How Java collections Works

The solution code demonstrates some basic use cases for generics. The examples in the GenericsDemo.java file, contained within the recipe sources, go into more detail to demonstrate the use of generics with Java collections versus showing you how to create generic types. Unless you are developing a library API, you probably won’t be creating your own generic types.

 

However, if you understand how generics are used with the Collection interfaces and classes, you will have the knowledge you need to create your own generic types.

 

The first thing to understand and remember about Java generics is that they are strictly a compile-time feature that aids the developer in creating more type-safe code.

 

All the type information that you specify when you parameterize a generic type gets “erased” by the compiler when the code is compiled down to bytecode.

 

You’ll see this described as type erasure. Let’s look at an example of a generic Collection type: the List. The list is an interface defined as follows:

public interface List<E> extends Collection<E> { ... };

 

Now that is a strange syntax, especially because there is no object or type identified as E. As it turns out, the E is known as a type parameter, which is a placeholder to indicate to the compiler that a type will be assigned to the object at runtime.

 

Type parameters are typically uppercased letters that are used to indicate the type of parameter being defined.

 

There are a variety of different type parameters to note, but keep in mind that these are only applicable when defining a generic type. In most cases, generic types are only defined when developing a library or API:

E – Element
K – Key
N- Number
T – Type
V – Value
S, U, V, and so on—second, third, and fourth types

 

To specify the element type for a List (or any Collection type), simply include the type name in angle brackets when declaring and instantiating objects. When you do this, you are specifying a “parameterized type.” 

 

The following code declares List of Integers. A variable, aList, of the parameterized type List<Integer> is declared and then initialized with the reference obtained from the instantiation of the parameterized type, LinkedList<Integer> (also called a “concrete parameterized type”):

List<Integer> aList = new LinkedList<Integer>();
Now that you’ve parameterized these types to restrict the element type to Integers, the List add(E e)
method becomes:
boolean add(Integer e);
If you try to add anything other than an Integer to aList, the compiler will generate an error:
aList.add(new Integer(121));
aList.add(42); // 42 is the same as new Integer(42), due to autoboxing.
aList.add("Java"); // won't compile, wrong type
It’s important to note that it’s the reference type that is checked at compile time, so the following will also result in a compiler error:
Number aNum = new Integer("7"); aList.add(aNum); // won't compile, wrong type

 

This is a compile error because aNum could reference any Number object. If the compiler were to allow this, you could end up with a set that contains Doubles, Floats, and so on, which would violate the Integer parameter constraint that was specified when you created aList.

 

Of course, a simple typecast could get you around the compiler error, but this would surely cause unintended consequences when casting between incompatible Number objects.

 

Generics were designed to reduce the amount of explicit type casting you have to do in your code, so if you find yourself using explicit type casting when using methods of parameterized types, this is a clue of potentially dangerous code.

aList.add((Integer)aNum); // compiles, but don't do this.

 

Other things to watch out for when using generic types are compiler warnings. They may indicate that you’re doing something that is not recommended and it usually indicates that your code has a potential runtime error looming. An example can help to illustrate this. The following code will compile but produce two compiler warnings:

List rawList = new LinkedList();

aList = rawList;

 

First, you’re creating rawList, which is a raw type, a generic type that isn’t parameterized. When generics were introduced into the language, the language designers decided that in order to maintain compatibility with pre-generics code, they would need to allow the use of raw types.

 

However, the use of raw types is strongly discouraged for newer (post–Java 5) code, so compilers will generate a raw type warning if you use them. Next, rawList is assigned to aList, which was created using parameterized types.

 

Again, this is allowed by the compiler (due to generics type erasure and backward compatibility), but an unchecked conversion warning is generated for the assignment to flag potential runtime type incompatibility. Imagine if rawList contained Strings. Later, if you tried to retrieve Integer elements from aList, you would get a runtime error.

 

Regarding type compatibility, it doesn’t apply to generic type parameters. For example, the following is not a valid assignment:

List<Number> bList = new LinkedList<Integer>(); // won't compile; incompatible types

 

Although Integers are Numbers (Integer is a subtype of Number), and LinkedList is a subtype of List, LinkedList<Integer> is not a subtype of List<Number>. Fortunately, this won’t slip by you if you accidentally write code like this; the compiler will generate an “incompatible types” warning.

 

So you may be wondering whether there is a way to achieve a variant subtyping relationship similar to what we tried to do in the previous line of code. The answer is yes, by using a feature of generics called the wildcard. A wildcard is denoted by use of a question mark (?) within the type parameter angle brackets.

 

Wildcards are used to declare parameterized types that are either bounded or unbounded. The following is an example declaration of a bounded parameterized type:

List<? extends Number> cList;

 

When a wildcard is used with the extends keyword, an upper bound is established for the type parameter. In this example, ? extends Number means any type that is either a Number or a subtype of a Number. Therefore, the following would be valid assignments because both Integer and Double are subtypes of Number:

cList = new LinkedList<Number>();
cList = new LinkedList<Integer>();
cList = new LinkedList<Double>();

 

So, cList can hold a reference to any List instance that has an element type that is compatible with Number. In fact, cList could even reference a raw type. Obviously, this makes it a challenge for the compiler to enforce type safety if it were to allow elements to be added to cList.

 

Therefore, the compiler does not allow elements (other than a null) to be added to a collection type that is parameterized with? extends. The following would result in a compiler error:

cList.add(new Integer(5)); // add() not allowed; cList could be LinkedList<Double>

However, you are allowed to get an element from the list without any problem: Number cNum = cList.get(0);

 

The only restriction here is that the reference you get from the list has to be treated like a Number. Remember, cList could be pointing to a list of Integers, a list of Doubles, or list of any other subtype of Number.

A wildcard can also be used with the super keyword. In this case, a lower bound is established for the type parameter: List<? super Integer> dList;

 

In this example,? super Integer means any type that is either an Integer or any supertype of Integer. Therefore, the following would be valid assignments because Number and Object are the only supertypes of Integer:

dList = new LinkedList<Integer>();
dList = new LinkedList<Number>();
dList = new LinkedList<Object>();

 

So, you see that Integer is the lower bound. This lower bound now places a restriction on retrieving elements from the list. Because dList can hold a reference to any one of the previous parameterized types, the compiler would not be able to enforce type safety if an assumption were made about the type of the element being retrieved.

 

Therefore, the compiler must not allow calls to get() on a collection type that is parameterized with? super and the following would result in a compiler error:

Integer n = dList.get(0); // get() not allowed; dList.get(0) could be a Number or Object

 

However, now you can add elements to the list, but the lower bound, Integer, still applies. Only Integers can be added because Integer is compatible with Number and Object:

dList.add(new Integer(5)); // OK
Number dNum = new Double(7);
dList.add(dNum); // won't compile; dList could be LinkedList<Integer>

 

You will see the use of the wildcard with both extends and super throughout the collection types. Most often, you will see them used in method parameter types, such as the addAll() method, which is defined for all Collections.

 

Sometimes you will see the collection types using the wildcard (?) alone as a type parameter, which is called an unbounded wildcard. The Collection removeAll() method is such an example. In most cases, this usage is self-explanatory.

 

You probably won’t be (probably shouldn’t be) defining your own parameterized types using an unbounded wildcard. If you try to do this, you will soon learn it isn’t much you can do with it.

 

If you understand concrete parameterized types, wildcard parameterized types, and the concept of bounded and unbounded types, as described in this recipe, you have most of what you need to work with the generic collection types and create your own generic types if you so chose.

 

Now that we’ve talked a lot about parameterizing types, we’re going to tell you to forget about some of it. When Java 7 was released, a new feature called the diamond (sometimes seen referred to as the diamond operator, although it is not considered to be an operator in Java) was introduced.

 

The diamond allows the compiler to infer the type of argument(s) from the context of the parameterized type usage.

A simple example of the diamond usage follows: List<Integer> eList = new ArrayList<>();

 

Notice there is no type argument specified between the angle brackets when instantiating the ArrayList. The compiler can easily infer the type to be Integer, based on the context of the assignment or initializer.

 

Integer is the only type that would work in this context. In fact, the Java compiler (and most compliant IDEs) will actually warn you if you do not use a diamond where it is possible to use it. Another more complex example shows the benefit even better:

 

Map<Integer, List<String>> aMap = new HashMap<>(); // Nice! The diamond can similarly be used in return statements, as well as in method arguments: // diamond in method return public static List<String> getEmptyList() {
return new ArrayList<>(); } diamond in method argument List<List<String>> gList = new ArrayList<>(); gList.set(0, new ArrayList<>(Arrays.asList("a", "b")));

Note that using the diamond as shown here is not the same as using a raw type. The following is not equivalent to the declaration of a map that uses the diamond; it will result in an “unchecked conversion” warning, and possibly a raw type warning, from the compiler:

Map<Integer, List<String>> bMap = new HashMap(); // compiler warnings; avoid raw types

 

The discussion around why this is different than the diamond example is beyond the scope of this recipe. If you remember to avoid the use of raw types, you shouldn’t need to worry about this. Use the diamond whenever possible to save yourself some typing, as well as to make your code more robust, readable, and concise.

 

Working with Dynamic Arrays

Working with Dynamic Arrays

Problem: You need a flexible data structure that can store a variable amount of data and that allows for easy insertion and deletion of data.

Solution

Consider using an ArrayList. The following example code is the StockScreener class, which allows you to screen a list of stocks or a single stock based on a specific screen parameter (P/E, Yield, and Beta) and screen value.

 

The class makes use of an ArrayList for containing stock Strings. An example screen might be “Tell me which of the stocks in this list has a P/E (price-to-earnings ratio) of 15 or less.” Don’t worry if you’re not familiar with these stock market terms. Whatever you do, don’t use this class to make your stock investment decisions!

See StockScreener.java

public class StockScreener {
enum Screen { PE, YIELD, BETA };
public static boolean screen(String stock, Screen screen, double threshold) { double screenVal = 0;
boolean pass = false;
switch (screen) {
case PE:
screenVal = Math.random() * 25;
pass = screenVal <=threshold; break; case YIELD: screenVal=Math.random() * 10; pass=screenVal>= threshold;
break;
case BETA:
screenVal = Math.random() * 2;
pass = screenVal <= threshold;
break;
}
System.out.println(stock + ": " + screen.toString() + " = " + screenVal);
return pass;

}

/**

Parse through stock listing to determine if each stock passes the screen tests.  If

a particular element does not pass the screen, then remove it.

*/

public static void screen(List<String> stocks, Screen screen, double threshold) { Iterator<String> iter = stocks.iterator();

while (iter.hasNext()) {

String stock = iter.next();

if (!screen(stock, screen, threshold)) {

iter.remove();

}

}

}

public static void main(String[] args) {

List<String> stocks = new ArrayList<>();

stocks.add("ORCL");
stocks.add("AAPL");
stocks.add("GOOG");
stocks.add("IBM");
stocks.add("MCD");
System.out.println("Screening stocks: " + stocks);
if (stocks.contains("GOOG") &&
!screen("GOOG", Screen.BETA, 1.1)) {
stocks.remove("GOOG");
}
System.out.println("First screen: " + stocks);
StockScreener.screen(stocks, Screen.YIELD, 3.5); System.out.println("Second screen: " + stocks); StockScreener.screen(stocks, Screen.PE, 22); System.out.println("Third screen: " + stocks);
System.out.println("Buy List: " + stocks);
}
}
The output from running this code will vary because it is randomly assigning a stock’s screen result value. Here is one sample of output from running the class:
Screening stocks: [ORCL, AAPL, GOOG, IBM, MCD]
GOOG: BETA = 1.9545048754918146
First screen: [ORCL, AAPL, IBM, MCD]
ORCL: YIELD = 5.54002319921808
AAPL: YIELD = 5.282200818124754
IBM: YIELD = 3.189521157557543
MCD: YIELD = 3.978628208965815
Second screen: [ORCL, AAPL, MCD]
ORCL: PE = 3.5561302619951993
AAPL: PE = 13.578302484429233
MCD: PE = 23.504349376296886
Third screen: [ORCL, AAPL]
Buy List: [ORCL, AAPL]

 

How It Works

what is the Java collection

The ArrayList is one of the most often used classes in the Java Collections Framework. The ArrayList class implements the List interface, which, in turn, implements the Collection interface.

 

The Collection interface defines the set of common operations for all Collection types, and the List interface defines the set of operations that are specific to the list-oriented Collection types.

 

The Collections Framework makes heavy use of Java generics. If you are new to generics, it is recommended that you read Recipe, which gives a brief summary of generics and their use with collections.

 

The StockScreener main() method starts by declaring a List of stocks, and specifying with the generic type parameter, that the stocks list elements will be of type String.

 

Notice that the actual list type is an ArrayList that is created using the diamond. The stocks list will hold a variable number of stocks, represented by their stock market symbol (a String):

 

List<String> stocks = new ArrayList<>();

Now that you’ve specified that the stocks list can only hold Strings, all the List methods, in turn, get parameterized to only allow Strings. So, next, the code makes several calls to the ArrayList’s add(String) method to add the stocks to the list.

 

After that, a screen is run on GOOG (Google) based on its Beta (a measure of stock risk); if it does not pass the screen, the List remove(String) method is called to remove the stock from the stock list. Two more screens are then run on the entire stock list to get a list of stocks that have a P/E of 22.0 or less, and a Yield of 3.5% or more.

 

The screen() method used for these screens takes a parameter of type List<String>. It has to iterate over the list, run the screen for each stock in the list, and remove those stocks that do not pass the screen.

 

Note that in order to safely remove an element from a Collection while iterating over it, you must use iterate using the Collection’s Iterator, which can be obtained by calling its iterator() method. Here, we are showing the use of a while loop to iterate over the stocks list (a for loop could similarly be used).

 

As long as you’re not to the end of the list (iter.hasNext()), you can get the next stock from the list (iter.next()), run the screen, and remove the element from the list (iter.remove()) if the screen didn’t pass.

 

Note You may find that calling the list’s remove() method while iterating the list seems to work. The problem is that it’s not guaranteed to work and will produce unexpected results.

 

At some point, the code will also throw a ConcurrentModificationException, regardless of whether you have multiple threads accessing the same list. Remember to always remove elements through the iterator when iterating over any Collection.

 

The ArrayList is a very useful data structure that should normally be used in place of the array type. It provides much more flexibility than a simple array, in that elements can be added and removed dynamically with ease.

 

While it is true that ArrayList uses an array internally, you benefit from optimized add() and remove() operations that are implemented for you. Also, ArrayList implements many other very useful methods.

 

Refer to the online Java documentation for further details (Oracle JDK 9 Documentation docs/api/java/util/ArrayList.html).

 

Making Your Objects Iterable

Making Your Objects Iterable

Problem

You have created a custom collection–based class that wraps (instead of extends) the underlying collection type. Without exposing the internal implementation details of your class, you would like objects of your class to become iterable, especially with the use of a foreach statement.

 

Solution

Have your class extend the Interable<T> interface, where T is the element type of the collection to be iterated. Implement the iterator() method to return the Iterator<T> object from this collection.

 

The example for this recipe is the StockPortfolio class. Internally, StockPortfolio manages a collection of Stock objects. We would like users of our class to be able to treat StockPortfolio objects as iterable objects using a foreach statement. The StockPortfolio class follows:

See StockPortfolio.java and Stock.java
public class StockPortfolio implements Iterable<Stock> {
Map<String, Stock> portfolio = new HashMap<>(); public void add(Stock stock) { portfolio.put(stock.getSymbol(), stock); } public void add(List<Stock> stocks) {
for (Stock s : stocks) {
portfolio.put(s.getSymbol(), s);
}
}
@Override
public Iterator<Stock> iterator() {
return portfolio.values().iterator();
}
public static void main(String[] args) {
StockPortfolio myPortfolio = new StockPortfolio(); myPortfolio.add(new Stock("ORCL", "Oracle", 500.0)); myPortfolio.add(new Stock("AAPL", "Apple", 200.0)); myPortfolio.add(new Stock("GOOG", "Google", 100.0)); myPortfolio.add(new Stock("IBM", "IBM", 50.0)); myPortfolio.add(new Stock("MCD", "McDonalds", 300.0));
foreach loop (uses Iterator returned from iterator() method) System.out.println("====Print using legacy for-each loop===="); for (Stock stock : myPortfolio) {
System.out.println(stock);
}
System.out.println("====Print using Java 8 foreach implementation===="); myPortfolio.forEach(s->System.out.println(s));
}
}
The following code is that of the Stock class:
public class Stock {
private String symbol;
private String name;
private double shares;
public Stock(String symbol, String name, double shares) { this.symbol = symbol;
this.name = name;
this.shares = shares;
}
public String getSymbol() {
return symbol;
}
public String getName() {
return name;
}
public double getShares() {
return shares;
}
public String toString() {
return shares + " shares of " + symbol + " (" + name + ")";
}
}

 

The main() method creates a StockPortfolio and then calls the add() method to add a number of stocks to the portfolio.

 

Both variations of the foreach loop (legacy and forEach implementation) are then used to loop over and print all the stocks in the portfolio. Running the StockPortfolio class results in the following output:

50.0 shares of IBM (IBM)
300.0 shares of MCD (McDonalds)
100.0 shares of GOOG (Google)
200.0 shares of AAPL (Apple)
500.0 shares of ORCL (Oracle)

 

Note The order of the lines in the output may be different when you run the StockPortfolio class in your environment because the underlying implementation uses a HashMap. A HashMap does not guarantee the order of the elements stored in the map, and this extends to its iterators. 

 

If you wanted the iterator to return elements sorted by the stock symbol, you could use one of the sorted collections, such as TreeMap or TreeSet, instead of HashMap. Another option is to utilize a stream on the collection.

 

 

How It Works

How It Works

The Iterable interface was introduced in Java 5 to support the enhanced for loop (also known as the foreach loop) which was introduced at the same time.

 

Along with these enhancements to the language, all Collection classes were retrofitted to implement the Iterable interface, thus allowing Collection classes to be iterable using the foreach loop. The Iterable interface is a generic type defined as follows:

public interface Iterable<T> {

Iterator<T> iterator();

}

Any class that implements Iterable<T> must implement the iterator() method to return an Iterator<T> object. Typically, the Iterator returned is the default iterator of the underlying collection; however, it may also return an instance of a custom Iterator. In the StockPortfolio class, a Map is used to represent the stock portfolio.

 

The key for each map entry is the stock symbol, and the value associated with each key is a Stock object. Maps in Java are not iterable; that is, they are not Collection classes. Therefore, they do not implement Iterable.

 

However, both the keys and the values of a map are Collections and therefore are Iterables. We want our implementation of the Iterable iterator() method to return an Iterator over the values (Stock references) of the portfolio map; therefore, our Iterable implementation is parameterized by the Stock type: public class StockPortfolio implements Iterable<Stock>

 

The Map values() method returns the Collection of map values; in this case, a Collection of Stocks. The iterator() method implementation can then simply return the Iterator for this Collection:

@Override
public Iterator<Stock> iterator() {
return portfolio.values().iterator();
}
With this implementation of Iterable<Stock>, either the legacy a foreach loop, or the forEach implementation can be used to iterate a StockPortfolio instance and print each Stock:
myPortfolio.forEach(s->System.out.println(s));

 

The for Each method was new to the Iterable interface with the release of Java 8. The method performs the specified action for each element within the Iterable until all elements have been processed, or the specified action throws an exception.

 

In this solution, the specified action is a lambda expression, which prints the value of each element within the myPortfolio Iterable.

 

You will notice that StockPortfolio also contains the add(List<Stock>) method, which allows the portfolio to be populated from a List. This method also uses a foreach loop to iterate through the input List.

 

Again, this is possible because Lists are Iterables. (Note that this method is never called in the code; it exists only for illustration purposes.)

 

Note There’s one issue with our implementation of StockPortfolio. We have gone to great lengths to not expose the internal implementation details of our class (the portfolio map). This allows us to change the implementation without affecting the StockPortfolio client code.

 

However, when we implemented Iterable, we effectively exported the underlying portfolio map through the iterator() method, an Iterator allows the underlying collection to be modified by calling its remove() method.

 

Unfortunately, Java does not provide an unmodifiable iterator class that could be used to wrap an Iterator and prevents modification of the underlying Collection.

 

However, it would be simple to implement such a class that forwards the hasNext() and next() calls to the wrapped Iterator but leaves the remove() method unimplemented (per the Iterator Java documentation, UnsupportedOperationException should be thrown).

 

Alternatively, your iterator() method could return the Iterator from an unmodifiable Collection obtained through a call to the Collections. unmodifiableCollection() class method. You are encouraged to explore these two options.

 

To give you a start, one possible implementation of UnmodifiableIterator has been provided in the source code download (see UnmodifiableIterator.java).

 

As you have seen in this recipe, the Iterable interface allows you to create iterable objects that are compatible with a foreach implementation. This is very useful when you want to design a custom collection-based class that encapsulates implementation details.

 

Just keep in mind that in order to enforce the encapsulation and prevent modification of your underlying collection, you should implement one of the solutions mentioned in the preceding note.

 

Iterating Over Collections

Iterating Over Collections

Problem: Your application contains Collection types, and you want to iterate over the elements within them.

Solution

Generate a stream on any type that extends or implements java.util.The collection, and then perform the desired task(s) on each element of the collection. In the following code, an ArrayList loaded with Stock objects is used to demonstrate the concept of streams.

public class StreamExample {
static List<Stock> myStocks = new ArrayList();
private static void createStocks(){
myStocks.add(new Stock("ORCL", "Oracle", 500.0));
myStocks.add(new Stock("AAPL", "Apple", 200.0));
myStocks.add(new Stock("GOOG", "Google", 100.0));
myStocks.add(new Stock("IBM", "IBM", 50.0));
myStocks.add(new Stock("MCD", "McDonalds", 300.0));
}
public static void main(String[] args){
createStocks();
Iterate over each element and print the stock names myStocks.stream()
.forEach(s->System.out.println(s.getName()));
boolean allGt = myStocks.stream()
.allMatch(s->s.getShares() > 100.0);
System.out.println("All Stocks Greater Than 100.0 Shares? " + allGt);
Print out all stocks that have more than 100 shares System.out.println("== We have more than 100 shares of the following:"); myStocks.stream()
.filter(s -> s.getShares() > 100.0)
.forEach(s->System.out.println(s.getName()));
System.out.println("== The following stocks are sorted by shares:"); Comparator<Stock> byShares = Comparator.comparing(Stock::getShares); Stream<Stock> sortedByShares = myStocks.stream()
.sorted(byShares);
sortedByShares.forEach(s -> System.out.println("Stock: " + s.getName() + " - Shares:
" + s.getShares()));
May or may not return a value Optional<Stock> maybe = myStocks.stream()
.findFirst();
System.out.println("First Stock: " + maybe.get().getName());
List newStocks = new ArrayList();
Optional<Stock> maybeNot = newStocks.stream()
.findFirst();
Consumer<Stock> myConsumer = (s) ->
{
System.out.println("First Stock (Optional): " + s.getName());
};
maybeNot.ifPresent(myConsumer);
if(maybeNot.isPresent()){ System.out.println(maybeNot.get().getName());
}
newStocks.add(new Stock("MCD", "McDonalds", 300.0)); Optional<Stock> maybeNow = newStocks.stream()
.findFirst();
maybeNow.ifPresent(myConsumer);
}
}

The results of executing this code demonstrate the concept of using streams. External iteration (for loops) is no longer a requirement for iterating over a collection of data.

 

How It Works

executing this code

Prior to Java 8, iterating over a Collection required some kind of looping block. This is known as external iteration, a.k.a. programmatic looping in sequential order. In most cases, a for a loop was used to work through each element within a Collection, processing each element according to an application’s requirements.

 

While a for loop is a reasonable solution for performing iteration, it is both a nonintuitive and verbose strategy. Since the release of Java 8, the boilerplate of iterating over Collections was removed, along with the requirement to spell out how the iteration is to be completed. The compiler already knows how to iterate over a Collection, so why tell the compiler exactly how to do it?

 

Why not simply tell the compiler: “I would like to iterate over this Collection, and perform this task on each element”? The concept of streams enables this hands-off approach to iteration.

 

Let the compiler take care of the nonintuitive looping, and simply hand the task off to the compiler and tell it what action to perform on each element. This concept is known as internal iteration. With internal iteration, your application determines what needs to be iterated, and the JDK decides how to perform the iteration.

 

Internal iteration not only alleviates the requirement to program the looping logic, but it also has other advantages. One such advantage is that internal iteration is not limited to sequential iteration over elements. Therefore, the JDK decides how to iterate, choosing the best algorithm for the task at hand.

 

Internal iteration also can more easily take advantage of parallel computing. This concept involves subdividing tasks into smaller problems, solving each in a simultaneous manner, and then combining the results.

 

A stream is a sequence of object references that can be generated on all Collection types.

 

The Stream API makes it possible to perform a sequence of aggregate operations upon those object references and either return a result or apply the changes to the objects inline. This is also known as a pipeline. The pseudocode for generation and use of a stream is as follows:

Collection -> (Stream) -> (Zero or More Intermediate Operations) -> (Terminal Operation)

 

Let’s put this pseudocode into a real example. In the solution, a list of Stock objects is used for demonstrating stream iteration. Let’s suppose you want to print out each stock that contains a number of shares that is over a designated threshold (100 shares in this example). You can use the following code to perform this task:

myStocks.stream()
.filter(s -> s.getShares() > 100.0)
.forEach(s->System.out.println(s.getName()));

 

In the previous example, an intermediate operation known as a filter() is used to apply a limitation on the elements, thereby filtering out all of the elements that do not match the supplied predicate. The predicate is written in the form of a lambda expression; it performs the test on each element and returns a Boolean result.

 

The terminal operation in the example uses forEach() to print each of the matching elements. A terminal operation is the last operation in a pipeline, and it produces a nonstream result such as a primitive, collection, or no value at all. In the example case, no result is returned.

 

To generate a stream on a Collection type, call the stream() method, which will return a Stream type. In most cases, the Stream type is not the desired result, so the Stream API makes it possible to invoke zero or more intermediate operations upon a stream, forming a pipeline of operations.

 

For example, in the solution, the list of Stock objects is sorted by the number of shares using the following code. Note that Comparator byShares is applied to each object in the stream and a Stream<Stock> is returned as a result:

Stream<Stock> sortedByShares = myStocks.stream()

.sorted(byShares);

 

In the previous example, a single intermediate operation, sorted(), is performed on the stream. As mentioned previously, there could be more than one intermediate operation chained to this pipeline, thereby performing the next operation upon those objects that meet the criteria of the previous operation. Each of the intermediate operations returns a Stream.

 

Each pipeline can contain a terminal operation, thereby applying the terminal operation to each of the resulting stream objects. As mentioned previously, a terminal operator may or may not return a result. In the previous example, no terminal operation is applied.

 

Note The online documentation for Stream (https://docs.oracle.com/javase/9/docs/api/java/ util/stream/Stream.html) lists all of the intermediate and terminal operations available upon a stream.

 

Streams have been a revolutionary change for the Java programming language. They change the way in which a developer thinks about a program, making the developer more productive and the code more efficient.

 

While legacy iteration techniques such as the for loop are still considered valid procedures, streams are the preferred technique for iteration when you’re using Java 8 or beyond.

 

Iterating Over a Map

Iterating Over a Map

Problem

You are using one of the Map classes, such as HashMap or TreeMap, and you need to iterate over the keys, values, or both. You also want to remove elements from the map while you are iterating over it.

Solution

There are multiple ways to iterate over a Map. The method you choose should depend on which portions of the map you need to access and whether you need to remove elements from the map while iterating.

 

The StockPortfolio class is a continuation of the stock portfolio class shown in the previous recipe. It adds three methods, summary(), alertList(), and remove(List<String>), that demonstrate alternative methods for iterating over the portfolio map:

// See StockPortfolio1.java
Map<String, Stock> portfolio = new HashMap<>(); ... public void summary() { System.out.println("==Legacy technique for traversing Map.Entry=="); for (Map.Entry<String, Stock> entry : portfolio.entrySet()) {
System.out.println("Stock = " + entry.getKey() + ", Shares = " + entry.getValue(). getShares());
}
System.out.println("==Utilization of new foreach and lambda combination=="); portfolio.forEach((k,v)->System.out.println("Stock = " + k + ", Shares = " +
v.getShares()));
}
/**
Utilize for loop to traverse Map keys and apply filter to obtain desired
stocks
@return
*/
public List<Stock> alertListLegacy() {
System.out.println("==Legacy technique for filtering and collecting=="); List<Stock> alertList = new ArrayList<>(); for (Stock stock : portfolio.values()) { if (!StockScreener.screen(stock.getSymbol(), StockScreener.Screen.PE, 20)) { alertList.add(stock); } } return alertList; } /** Utilize stream and filters to obtain desired stocks @return */ public List<Stock> alertList(){
return
portfolio.values().stream()
.filter(s->!StockScreener.screen(s.getSymbol(), StockScreener.Screen.PE, 20)) .collect(Collectors.toList());
}
public void remove(List<String> sellList) {
Iterator<String> keyIter = portfolio.keySet().iterator();
while (keyIter.hasNext()) {
if (sellList.contains(keyIter.next())) {
keyIter.remove();
}
}
}

 

How It Works

Map entries

A Map is an object that contains a collection of key/value pairs. Maps can be beneficial when you need to store an index (key) and associate it with a particular value.

 

A Map must not contain any duplicate keys and each key maps to exactly one value. The source code for the solution (StockPortfolio1.java) demonstrates how to add and remove entries from a Map.

 

It also contains the source that is listed in the solution to this recipe, demonstrating how to iterate over Map entries using legacy techniques, as well as newer syntax that takes advantage of lambda expressions and streams.

 

The summary() method uses a foreach loop implementation to iterate over the portfolio map’s Entry set. To iterate using the legacy code, the Map entrySet() method returns a Set of Map.

 

Entry objects. Within the loop, you then have access to the key and value for the current Map. Entry by calling the respective methods, key() and value(), on that entry. Use this method of iterating when you need to access both the map keys and values while iterating, and you don’t need to remove elements from the map.

 

Taking a look at the newer syntax, you can see that the same iteration can be performed in a single line of code. The newer syntax utilizes the forEach() method, which was added to the Map interface in Java 8. It applies a lambda expression to each entry within the list. The lambda expression takes both the key and value as arguments and then prints them out.

 

The alertListLegacy() method uses a foreach loop implementation to iterate over just the values of the portfolio map. The Map values() method returns a Collection of the map values; in this case, a Collection of Stocks.

 

Use this method of iterating when you only need access to the map values and you don’t need to remove elements from the list. Similarly, if you only need access to the map keys (again, without the need to remove elements), you can iterate using the keySet() method:

for (String symbol : portfolio.keySet()) {
...
}
If you also need to also access the map value while iterating using the key set, avoid the following, as it is very inefficient. Instead, use the method of iteration shown in the summary() method.
for (String symbol : portfolio.keySet()) {
Stock stock = portfolio.get(symbol);
...
}

Taking a look at the alert list() method in the solution, you can see that the same iteration can be performed with much less work using a combination of streams, filters, and collectors.

 

For more details regarding streams and the Stream API. In the alert list(), a stream is generated, and then a filter, in the form of a lambda expression, is applied to that stream. Finally, a collector is applied to the filter, creating a List<Stock> to return.

 

The remove(List<String>) method takes a list of stock symbols representing the stocks to be removed from the portfolio. This method iterates over the portfolio map keys using the keySet() iterator, removing the current map entry if it is one of the stocks specified for removal.

 

Notice that the map element is removed through the iterator’s remove() method. This is possible because the key set is backed by the map, so changes made through the key set’s iterator are reflected in the map. You could also iterate over the portfolio map using its values() iterator:

Iterator<Stock> valueIter = portfolio.values().iterator(); while (valueIter.hasNext()) {
if (sellList.contains(valueIter.next().getSymbol())) { valueIter.remove();
}
}

As with the key set, the values collection is backed by the map, so calling remove() through the values iterator will result in removal of the current entry from the portfolio map.

 

In summary, if you need to remove elements from a map while iterating over the map, iterate using one of the map’s collection iterators and remove map elements through the iterator, as shown in the remove(List<String>) method.

 

This is the only safe way to remove map elements during iteration. Otherwise, if you don’t need to remove map elements, you can make use of a foreach loop and one of the methods of iteration shown in the solution to this recipe.

 

Executing Streams in Parallel

Problem: You want to iterate over a Collection in parallel to distribute the work over multiple CPUs.

Solution

Utilize a stream construct on the Collection, and invoke parallelStream() as the first intermediate operation in order to take advantage of multiple CPU processing. The following class demonstrates multiple uses of the parallelStream() operation:

public class StockPortfolio2 {
static List<Stock> myStocks = new ArrayList();
private static void createStocks(){
myStocks.add(new Stock("ORCL", "Oracle", 500.0));
myStocks.add(new Stock("AAPL", "Apple", 200.0));
myStocks.add(new Stock("GOOG", "Google", 100.0));
myStocks.add(new Stock("IBM", "IBM", 50.0));
myStocks.add(new Stock("MCD", "McDonalds", 300.0));
}
public static void main(String[] args){
createStocks();
Iterate over each element and print the stock names myStocks.stream()
.forEach(s->System.out.println(s.getName()));
boolean allGt = myStocks.parallelStream()
.allMatch(s->s.getShares() > 100.0);
System.out.println("All Stocks Greater Than 100.0 Shares? " + allGt);
Print out all stocks that have more than 100 shares System.out.println("== We have more than 100 shares of the following:"); myStocks.parallelStream()
.filter(s -> s.getShares() > 100.0)
.forEach(s->System.out.println(s.getName()));
System.out.println("== The following stocks are sorted by shares:"); Comparator<Stock> byShares = Comparator.comparing(Stock::getShares); Stream<Stock> sortedByShares = myStocks.parallelStream()
.sorted(byShares);
sortedByShares.forEach(s -> System.out.println("Stock: " + s.getName() + " - Shares:
" + s.getShares()));
// May or may not return a value
Optional<Stock> maybe = myStocks.parallelStream()
.findFirst();
System.out.println("First Stock: " + maybe.get().getName());
List newStocks = new ArrayList();
Optional<Stock> maybeNot = newStocks.parallelStream()
.findFirst();
Consumer<Stock> myConsumer = (s) ->
{
System.out.println("First Stock (Optional): " + s.getName());
};
maybeNot.ifPresent(myConsumer);
if(maybeNot.isPresent()){ System.out.println(maybeNot.get().getName());
}
newStocks.add(new Stock("MCD", "McDonalds", 300.0)); Optional<Stock> maybeNow = newStocks.stream()
.findFirst();
maybeNow.ifPresent(myConsumer);
}
}

 

How It Works

By default, operations are executed in a serial stream. However, you can specify that the Java runtime split the operations between multiple subtasks, thus taking advantage of multiple CPUs for performance. When operations are executed in this manner, they are executed in “parallel.”

 

Streams can be partitioned into multiple substreams by the Java runtime by invoking the parallelStream() intermediate operation.

When this operation is invoked, aggregate operations can process the multiple substreams and then the results will be combined in the end. You can also execute a stream in parallel by invoking the operation BaseStream. parallel.

Recommend