0% found this document useful (0 votes)
339 views68 pages

Nailing 1Z0-808 Free Sample

This document provides an overview of exam objectives for the Oracle Java SE8 Programmer I certification related to working with various Java API classes. It outlines key concepts for manipulating strings using StringBuilder, creating and formatting calendar data using date/time classes, using ArrayLists, and writing lambda expressions. The document emphasizes that String objects are immutable in Java, while StringBuilder can be used to modify string data. It also notes the intern pool that stores unique string literals.

Uploaded by

sergiorocha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
339 views68 pages

Nailing 1Z0-808 Free Sample

This document provides an overview of exam objectives for the Oracle Java SE8 Programmer I certification related to working with various Java API classes. It outlines key concepts for manipulating strings using StringBuilder, creating and formatting calendar data using date/time classes, using ArrayLists, and writing lambda expressions. The document emphasizes that String objects are immutable in Java, while StringBuilder can be used to modify string data. It also notes the intern pool that stores unique string literals.

Uploaded by

sergiorocha
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 68

Practical Guide

to
Oracle Java SE8 Programmer I Certification

by Igor Soudakevitch

FREE SAMPLE
Contains full text of Chapter II.9:
Exam Objectives – Group 9
(Working with Selected Classes from Java API)

The rest of the book is similar


both in structure and approach
Contents
Acknowledgements
Author’s Note
Target Audience
Abbreviations and Acronyms
Preface
Part I: Know Your Enemy
Chapter I.0: Toe Suckers and Guinea Pigs
Chapter I.1: Taking the Heat
Chapter I.2: Lock and Load
External Resources
Part II: Exam Objectives, a.k.a. Pater Noster
Chapter II.0: Opening Remarks
Chapter II.1: Java Basics
Keys & Discussion
Chapter II.2: Working With Java Data Types
Keys & Discussion
Chapter II.3: Using Operators and Decision Constructs
Keys & Discussion
Chapter II.4: Creating and Using Arrays
Keys & Discussion
Chapter II.5: Using Loop Constructs
Keys & Discussion
Chapter II.6: Working with Methods and Encapsulation
Keys & Discussion
Chapter II.7: Working with Inheritance
Keys & Discussion
Chapter II.8: Handling Exceptions
Keys & Discussion
Chapter II.9: Working with Selected Classes from Java API
Keys & Discussion
Appendix A: Registering for the Exam
Appendix B: RWJ.bat
Appendix C: Filter.java
Appendix D: Key Summary

2 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Target Audience
Given the following class definitions (disregard line numbers):

In file C:\Try_Java\tempa\Exam.java:
1 package tempa;
2 import tempb.*;
3
4 public class Exam {
5 protected Exam(Examinee e){}
6 }

In file C:\Try_Java\tempb\Examinee.java:
1 package tempb;
2 import tempa.Exam;
3
4 public class Examinee {
5 String str;
6 protected Examinee(){
7 this.str = "1Z0-808 is tricky!";
8 }
9 protected void exclaim(){
10 System.out.println(str);
11 }
12 }

In file C:\Try_Java\org\xlator\TargetAudience.java:
1 package org.xlator;
2 import tempa.*;
3 import tempb.Examinee;
4
5 public final class TargetAudience extends Examinee {
6 String str = "Then again, maybe not...";
7 TargetAudience(){
8 exclaim();
9 }
10 @Override
11 public void exclaim(){
12 System.out.println(str.substring(0, str.length()));
13 }
14 public static void main(String[] args) {
15 Examinee ta = new TargetAudience();
16 new Exam(ta);
17 }
18 }

What is the result?


A. 1Z0-808 is tricky!
B. Then again, maybe not...
C. Compilation fails
D. StringOutOfBoundsException is thrown at run time

See the correct answer overleaf.

Target Audience 3
Answer to the ‛Target Audience’ question:

The correct answer is option C for the code does not compile.

The fail-safe way to solve problems on the exam is to read question first, then glance at the
available choices to see if some of them can be eliminated immediately because options are
syntactically invalid quite often, and only after that start analyzing code. Let me do it for you:

Prints this, prints that... hmm, a possible comperr... what? StringOutOfBoundsException ?!


Nah, I don’t think so, java.lang has no such thing: it should’ve been SIOOBE → option D is out.
Damn, three more to go. To the code, then.
Line num bers start with 1; full contents, then → need to verify if imports don’t precede
packages... check → all three classes live in different packages → RED ALERT! RED ALERT!
some class members or constructors along the inheritance chain m ay be inaccessible... → aha!
TargetAudience does extend another class! som ething fishy m ust be going on.. . → now to
the main() method... right, an object... hmm, reftype differs from actype... oh, we're calling
another class' constructor, aren’t we now? in a different package, no less? well, you know, that
ctor better be public, otherwise no go.. . → yeap, just as I expected: it’s protected →
LOC16 in TargetAudience won’t work. Done!

And here’s the actual error message produced by the compiler:


C:\Try_Java\org\xlator\TargetAudience.java:16 error: Exam(Examinee) has protected access in Exam
new Exam(ta);
^
1 error

The entire chain of reasoning takes but twenty seconds, and this is what you too will be able to
pull off every single time on the exam regardless of the problem you’re facing – after you
worked your way through this OCA bootcamp with all its obstacle courses, that is.
This book has one sole purpose: to hone your skills for solving exam questions both reliably and
quickly; as such, it doesn’t even attempt to replace a full-fledged Java study guide. Ideally,
Nailing 1Z0-808 should become the beachhead from which you’ll be launching your final
offensive to conquer the coveted ‛Oracle Certified Programmer I’ title. This entire tune-up,
refueling and ammo-stocking phase won’t take more than three weeks. However, to benefit from
it fully you should already know your way around Java basics so grab a solid tutorial, study
online 1 or watch video lessons and so on; Preface lists some reliable titles.

★★★★★

I’d be very much interested in hearing how you fared on the exam. Do find a minute to tell me
your score and what objectives you missed. Comments or suggestions are welcome.
www.igor.host

1
You can find free Java online courses at MIT, UC Berkeley, etc. Stay away from YouTube, though: it has no QC.

4 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Abbreviations and Acronyms
actype – actual object’s type at run time
assop – assignment operator; mostly used metonymically, in the sense of assignment statement
castype – data type specified inside the parentheses for an explicit cast
comperr – compilation error
ctor – constructor
def – definition
dim – dimension
initer – initializer
initing – initializing
paramlist – list of formal parameters in a lambda expression
preditype – data type specified inside the angle brackets of a generified Predicate
reftype – reference type
refvar – reference variable
sout – any printing statement such as System.out.println(), etc.
stat – statement
ternop – ternary operator; often used metonymically to denote a ternary statement
var – variable
AIOOBE – ArrayIndexOutOfBoundsException
CCE – ClassCastException
ChE – checked exception
CSR – the Catch-or-Specify Requirement
DTPE – DateTimeParseException
E – an exception (regardless of the type)
IAE – IllegalArgumentException
IOE – IOException
IOOBE – IndexOutOfBoundsException
LDT – any of the new date/time classes in Java 1.8 (such as LocalDate, LocalTime or LocalDateTime)
LOC – line of code
NFE – NumberFormatException
NPE – NullPointerException
RTE – RuntimeException
SIOOBE – StringIndexOutOfBoundsException
TCF – try-catch-finally construct (not necessarily containing either catch or finally)

Abbreviations and Acronyms 5


Chapter EXAM OBJECTIVES – Group Nine:
Working with Selected Classes
II.9 from Java API
The 1Z0-808 objectives within this group:
9.1 Manipulate data using the StringBuilder class and its methods
9.2 Creating and manipulating Strings
9.3 Create and manipulate calendar data using classes from java.time.LocalDateTime,
java.time.LocalDate, java.time.LocalTime, java.time.format.DateTimeFormatter,
java.time.Period
9.4 Declare and use an ArrayList of a given type
9.5 Write a simple lambda expression that consumes a lambda Predicate expression

CORE RULES (with some Extras):

9.1 Manipulate data using the StringBuilder class and its methods +
9.2 Creating and manipulating Strings:
 Both String and StringBuilder implement the interface CharSequence and use a char
array to store their characters but, unlike StringBuilder objects, String objects are
immutable.
Most important corollary: None of the methods defined in the class String can
modify original String object’s value.
(other wording) If a String method returns a modified String, this object is new.
 In practice, Strings can be created in two ways: by forming a string literal (a sequence of
characters enclosed by double quotes) or by using the keyword new.
 In Java, a string literal is itself an object, which gets interned in a common string pool 2
(as per JLS, §3.10.5, String Literals: "A string literal is a reference to an instance of class
String. Moreover, a string literal always refers to the same instance of class String").
Whenever the code requests creation of a string literal, the pool is scanned and, if a
String object with the same value already exists in the pool, the reference to this object is
returned. String objects created using the keyword new are never placed in the pool of
String objects; same goes for the Strings that are products of methods and, therefore,
computed at run time:
String str1 = "Hello";
String str2 = new String("Hello");
String str3 = new String(new StringBuilder("Hello"));

System.out.println("Hello" == str1); // true → same object


System.out.println(str1 == str2); // false
System.out.println(str2 == str3); // false
System.out.println(str1 == "Hello!".substring(0,5)); // false

2
Do not confuse "string pool" with "constant pool", which is allocated at run time and "…contains several kinds of
constants, ranging from numeric literals known at compile-time to method and field references that must be resolved
at run-time" (JVM Spec, Java SE8 Ed., §2.5.5, Run-Time Constant Pool).

6 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


 Not only all string literals but the string-valued constant expressions (such as "Hello "
+ "world!") are interned, too.
Corollary: Strings computed by concatenation at run time are created anew, hence
distinct:
class Test{
static String gimme(){ return "world!"; }
public static void main(String[] args) {
String str1 = "Hello world!";
String str2 = "Hello " + "world!"; // Constant expressions are computed
// at compile time and then treated
// as if they were literals
String str3 = "Hello " + gimme(); // This one is computed at run time
// and doesn’t get interned

System.out.println(str1 == str2); // true


System.out.println(str1 == str3); // false
}
}

 EXTRA: String pool is common for all the classes from all the packages that are being
used by the running application.
 String constructors likely to appear on the exam (italics: didn’t meet personally):
String(String str)
String(StringBuilder sb)
EXTRA: Although a no-arg constructor String() does exist, it isn’t used in practice
because String objects are immutable in the first place.
 StringBuilder constructors likely to appear on the exam (italics: didn’t meet):
StringBuilder(String str)
StringBuilder() ← Constructs an empty sb with initial capacity of 16 characters.
StringBuilder(int capacity)
 String and StringBuilder methods likely to appear on the exam:
Method args str sb Note
substring() (int start) or (int start, int end)   NB: returns String rather than SB
length() ()  
str: (CS trgt, CS replcmnt) or (oldCh, newCh) NB: diff params for str and sb
replace()  
sb: (int start, int end, String str) no change? → current object
equals() (Object obj)   SB doesn’t override equals()
concat() (String str)   no change? → current object
toLowerCase() ()   no change? → current object
toUpperCase() ()   no change? → current object
trim() ()   no change? → current object
equalsIgnoreCase() (String anotherString)  
append() (all kinds of types including String)  
insert() (int offset, all kinds of types including String)  
delete() (int start, int end)  

REMARK: The table is not exhaustive; it only means that I personally met those
methods on the exam. To be on the safe side, learn the following
methods, as well:
– concat(), endsWith, startsWith() String only
– reverse(), capacity(), ensureCapacity() StringBuilder only
– charAt(), indexOf() String & StringBuilder

Working with Selected Classe from Java API Chapter II.9 7


 Known traps on the exam:
– str[sb].substring(int start, int end) 3 excludes the character at the end position:
System.out.println("Hello".substring(0,4)); // Hell
– although str.replace(), str.trim() and str.substring() seem to modify the value of
a String, they actually return a completely new String object UNLESS there has
been no change:
String str = "Hello";
System.out.println(str == str.replace("Z","z")); // true
System.out.println(str == str.trim()); // true
System.out.println(str == str.substring(0)); // true

– since == tests for ‛physical’ equality, the equality of contents should be tested with
the method equals();
– whereas String and ArrayList override Object’s equals(), StringBuilder does
not → use a workaround: sb1.toString().equals(sb2.toString());
 Easily confused methods (list refers to ArrayList):
Method str sb list Note
insert()    inserts at any position up to length(); returns current SB
append()    attaches to the tail; returns current StringBuilder
add()    returns boolean except void add(int index, E element)
replace()    str: replaces each occurrence; sb: replaces a substring
replaceAll()    String uses regexing; List replaces a Collection
set()    returns the element previously at the specified position
setCharAt()    void
delete()    returns current SB; if start == end → no changes ≡ same object
deleteCharAt()    returns StringBuilder
clear()    void; removes all the elements
remove()    returns the element previously at the specified position
removeAll()    returns true if the list changed as a result of the call
charAt()    returns the char value at the specified index
get()    returns the element at the specified position
contains()    true if obj contains specified CharSeq / or Object (List)
isEmpty()    true if String’s length is 0 / if List contains no elements
size()    returns the # of elements (stops at Integer.MAX_VALUE)
length()    returns the length of this String / char count in case of SB
setLength()    appends null(s) ‛\u0000’ if newLength > oldLength
ensureCapacity()    void
trim()    removes leading and trailing whitespace; same obj if no change
trimToSize()    resizes the buffer if it is larger than currently necessary
reverse()    NB: surrogate pairs are treated as single characters
 Other possible traps:
– str.trim() doesn’t remove whitespace 4 inside the string;
– sb.substring() returns a newly created String without affecting the current sb
object whereas sb.append(), sb.delete() and sb.insert() do change it;
– str[sb].substring() throws SIOOBE if the end arg exceeds str[sb].length():
System.out.println(new StringBuilder("Hi").substring(1,3)); // SIOOBE

– chained methods are to be evaluated left to right;

3
Means either str.substring() or sb.substring().
4
space (0x20), horizontal tab (0x09), form feed (0x0C) and line terminators LF (0x0A), CR (0x0D) and CRLF.

8 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


– only two StringBuilder methods return a String: substring() and toString();
– while substring() can be invoked in similar ways for both StringBuilder and
String – the method is overloaded for (int start) and (int start, int end) in either
class – calls to replace() lead to different results: sb.replace() substitutes a string
between two positions and str.replace() substitutes all occurrences of a char or a
CharSequence.
 EXTRA: str[sb].indexOf() returns -1 if no match was found.
 EXTRA: sb.insert() doesn’t throw a SIOOBE when inserting at the index i = sb.length();
the result simply mimics sb.append().
 The + op is overloaded for String, so if either operand of a + expression is a String,
concatenation is used; otherwise, addition is used.
Corollary: + accepts anything when assigning to a String:
String a = "";

a = 1 + 10 + a; // 11

// all of the following compile since each means a = a + smth


a += 2; // 112
a += 'a'; // 112a
a += true; // 112atrue

 The principal operations on a StringBuilder object are the append() and insert()
methods, which are overloaded so as to accept data of any type. Each effectively converts
a given datum to a string.
Corollaries: append()ing and insert()ing a null object won't throw an NPE.
EXTRA: When a null object (such as String, etc.) is passed in as a parameter to these
two methods, it will be converted to the four characters ‛null’.
EXTRA: However, append(null) and insert(null) won’t compile as the reference is
ambiguous: null can refer to either char[] or CharSequence
 Useful reminders:
■ charAt(), indexOf(), substring(), and length() work in the same way both in String
and StringBuilder.
■ append() adds only to the end of the current StringBuilder object whereas insert()
allows to put in one or multiple characters at a specified position
→ sb.insert(sb.length(),"***") behaves as sb.append("***");
■ StringBuilder uses a char array and throws a SIOOBE rather than AIOOBE.
■ StringBuilder doesn’t have remove(); it’s delete().

Working with Selected Classe from Java API Chapter II.9 9


EXERCISES (for Key Summary ref.to App.D):

Problem 9.1 Given:


class Hello {
public static void main(String[] args) {
String str = "Hello";
StringBuilder sb = new StringBuilder(str);
str.replace("o", "");
System.out.print(str + " ");
System.out.print(str.replace("o","") + " ");
System.out.print(sb.append("?").equals(sb.append("!")) + " ");
System.out.println(str.replace("o","").equals(str.replace("o","")));
}
}

What is the result?


A. Hell Hell false false
B. Hell Hell true true
C. Hello Hell false false
D. Hello Hell true true
E. Hello Hell false true
F. Hello Hell true false

Problem 9.2 Given:


class OurPets {
static String checkPets(StringBuilder myPet, StringBuilder yourPet){
return myPet == yourPet ? "same" : "different";
}
static String checkNames(StringBuilder myPet, StringBuilder yourPet){
return myPet.equals(yourPet) ? "same" : "different";
}
public static void main(String[] args) {
StringBuilder myPet = new StringBuilder("Fluffy");
StringBuilder yourPet = new StringBuilder("Fluffy");
System.out.print(checkPets(myPet, yourPet) + " pets, ");
System.out.println(checkNames(myPet, yourPet) + " names");
}
}

What is the result?


A. same pets, same names
B. different pets, same names
C. same pets, different names
D. different pets, different names
E. Compilation fails

Problem 9.3 Given:


class TheFifthElement {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("1"); // earth
sb.append("2"); // water
sb.append("3"); // air
sb.append("4"); // fire
sb.replace(4,4,"Leeloo");
System.out.println(sb);
}
}

10 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


What is the result?
A. 1234Leeloo
B. Compilation fails
C. The code throws a run-time exception

Problem 9.4 Given the following class:


class Test {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
String str = null;
for(int e : arr){ str += e; }
System.out.println(str);
}
}

What is the result:


A. _12345 (where _ denotes an empty space)
B. 12345
C. null12345
D. Compilation fails
E. A NullPointerException is thrown

Problem 9.5
Hoping to land a job as a junior programmer at a local bank, you came to a Java interview and
were asked to complete the following class that masks 20-digit account numbers so that only the
last five digits will be visible to the user while each of the first 15 digits is replaced with an
asterisk:
public class AccountMasker {
public static String maskAccount(String accNum) {
String lead = "***************"; // contains 15 asterisks in a row

// your code goes here

public static void main(String[] args) {


String accNum = args[0];
System.out.println(maskAccount(accNum.replace(" ","")));
}
}

Specifically, your task is to finish up the method maskAccount(String accNum) so that the class
AccountMasker will output ****************67541 when run with the following command:
java AccountMasker "34296 01853 49820 67541"
Which two LOCs, when used independently, will achieve this requirement?
A. return (new StringBuilder(accNum)).substring(15, 20).toString();
B. return lead + accNum.substring(15, 20);
C. return new StringBuilder(accNum).append(lead, 15, 20).toString();
D. return new StringBuilder(accNum).insert(0, lead).toString();
E. return new StringBuilder(lead).append(accNum, 15, 20).toString();

Working with Selected Classe from Java API Chapter II.9 11


Problem 9.6
Which statement initializes a StringBuilder to a capacity of 256?
A. StringBuilder sb = new StringBuilder(new String(256));
B. StringBuilder sb = StringBuilder.setCapacity(256);
C. StringBuilder sb = StringBuilder.setLength(256);
D. StringBuilder sb = new StringBuilder(256);

Problem 9.7 Given the code fragment:


StringBuilder sb = new StringBuilder();
String exam = "1Z0";
int code = 808;

Which two options will output the following:


I’ll pass 1Z0-808
A. System.out.println(sb.append("I’ll pass " + exam + "-" + code));
B. System.out.println(sb.insert("I’ll pass ").append(exam + "-" + code));
C. System.out.println(sb.insert("I’ll pass ").insert(exam).insert("-").insert(code));
D. System.out.println(sb.append("I’ll pass ").append(exam).append("-").append(code));

Problem 9.8 Given:


public static void main(String[] args) {
String a = "B ";
a = a.concat("U ");
String b = "L ";
a = a.concat(b);
a.replace('U', 'A');
a = a.concat(b);
System.out.println(a);
}

What is the result?


A. BALL
B. BLA
C. BULL
D. BUA
E. BUAL

Problem 9.9 Given:


public class Simple{
public static void main (String[] args){
char c = 6;
System.out.println("Hello".charAt(c));
}
}

What is the result?


A. There is no output
B. Compilation fails
C. The code throws an IndexOutOfBoundsException
D. The code throws a NullPointException

12 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.10 Given:
StringBuilder bucket = new StringBuilder("Empty me!");

Which statement(s) will empty the contents of the bucket object?


A. bucket.empty();
B. bucket.clear();
C. bucket.delete(0, bucket.size());
D. bucket.delete(0, bucket.length());
E. bucket.deleteAll();
F. bucket.remove(0, bucket.length());
G. bucket.removeAll();

Problem 9.11 Given:


class PoorGirl {
public static void main(String[] args) {
String name = "Javeline";
System.out.println("Hi! I’m " + name.replace("e", "a"));
}
}

What is the result?


A. Hi! I’m Javaline
B. Hi! I’m Javalina
C. Hi! I’m Jevaline
D. Hi! I’m Jeveline

Problem 9.12 Given the following main() method:


public static void main(String[] args) {
String str = " ";
str.trim();
System.out.println(str.equals("") + " " + str.isEmpty());
}

What is the result?


A. true true
B. true false
C. false true
D. false false

Problem 9.13 Given:


StringBuilder sb = new StringBuilder();
sb.append("Duke");

And the following LOCs:


System.out.println(sb.insert(0, "Hello "));
System.out.println(sb.append(0, "Hello "));
System.out.println(sb.add(0, "Hello "));
System.out.println(sb.set(0, "Hello "));

Working with Selected Classe from Java API Chapter II.9 13


How many of them print Hello Duke?
A. None
B. One
C. Two
D. Three

Problem 9.14 Given the following code fragment:


String str1 = "null";
String str2 = new String("NULL");
System.out.println(str1.equalsIgnoreCase(str2.toLowerCase()));
System.out.println(str2 == str2.replace('L','l').toLowerCase());
System.out.println(str1 == str1.replace('L','l').toLowerCase());

How many times the code prints true?


A. Not a single time
B. Once
C. Twice
D. Three times

Problem 9.15 Given:


public class TheMatrix {
public static void main(String[] args) {
String movie = "The";
movie.concat(" ").concat("MATRIX".toLowerCase());
System.out.print(movie.substring(5,6));
}
}

What is the result?


A. a
B. at
C. Compilations fails
D. An exception is thrown at run time

Problem 9.16 Given:


public class TheMatrixReloaded {
static void reload(StringBuilder sb) {
sb.append(" Matrix");
sb.insert(" Reloaded", sb.length());
}
public static void main (String[] args) {
StringBuilder sb = new StringBuilder("The");
reload(sb);
System.out.println(sb);
}
}

What is the result?


A. The
B. The Matrix Reloaded
C. Compilation fails
D. An exception is thrown at run time

14 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.17 Given the code fragment:
public static void main (String[] args) {
String[] str = new String[2];
int i = 0;
for (String e : str)
System.out.print(e.concat(" " + i++).trim());
}

What is the result?


A. 01
B. 01
C. 01
D. Compilation fails
E. An exception is thrown at run time.

Problem 9.18 Given:


public class Exam {
String str = "";
static void pass(String str) {
str.concat("Passed");
}
public static void main(String[] args) {
String str = "Failed ";
pass(str);
System.out.println(str);
}
}

What is the result?


A. Passed
B. Failed
C. Failed Passed
D. Compilation fails
E. An exception is thrown at runtime

Problem 9.19 Given:


public class AnotherExam {
public static void main (String[] args) {
StringBuilder sb = new StringBuilder("Passed");
System.out.print(sb + ": ");
System.out.println(sb.replace(0,4,"Fail") ==
sb.delete(0,666).insert(0,"Failed"));
}
}

What is the result?


A. Passed: false
B. Passed: true
C. Failed: false
D. Failed: true
E. Compilation fails
F. The code throws IndexOutOfBoundsException

Working with Selected Classe from Java API Chapter II.9 15


Problem 9.20 Given:
public class Capricchio {
public static void main (String[] args) {
Object obj = null;
StringBuilder sb = new StringBuilder();
sb.append(obj);
System.out.println(sb.length());
}
}

What is the result?


A. 1
B. 4
C. 16
D. Compilations fails
E. A NullPointerException is thrown at run time

Problem 9.21 Given:


public class HowAboutThisOne {
public static void main (String[] args) {
String str = null;
StringBuilder sb = new StringBuilder(str += str);
sb.delete(0,sb.length());
System.out.println(sb.capacity());
}
}

What is the result?


A. 8
B. 16
C. 24
D. Compilations fails
E. A NullPointerException is thrown at run time

Problem 9.22 Given:


class Slogan {
public static void main(String[] args) {
String str = "String Beans Forever!";
// line XXX: only a single LOC goes in here!
}
}

And the following LOCs:


System.out.println(str.delete(6,11));
str = str.delete(6,11); System.out.println(str);
str.replace(" Bean",""); System.out.println(str);
System.out.println(new StringBuilder(str).remove(" Bean").toString());

How many LOCs, when inserted independently at line XXX, will make the code print
Strings Forever!?
A. None
B. One
C. Two
D. Three

16 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.23 Given:
final String str = "";
while(str.equals("")) System.out.print(str+1);

What is the result?


A. 1
B. No visible output at all
C. Code compiles but enters endless loop at run time
D. Compilation fails because of an unreachable statement
E. Compilation fails because str+1 attempts to create a new object but str is final
F. Compilation fails because the expression str+1 is illegal

Problem 9.24 Given:


"a".replace("a","b");
"a".replace('a','b');
"a".replace(0,"a".length(),"b");
"a".replace(new StringBuilder('a'),"");
"a".replace(new StringBuilder('a'), new StringBuilder("b"));
new StringBuilder("a").replace("","b");
new StringBuilder("a").replace('a','b');
new StringBuilder("a").replace(0,1,"b");

How many LOCs fail compilation?


A. Two
B. Three
C. Four
D. Five

Problem 9.25 Given:


public class Dissonance{
public static void main(String[] args) {
Object obj = "Quartet No. 19 in C Major, K. 465";
System.out.println(obj.getClass().getSimpleName() + " " + obj);
}
}

Is it true that the code prints String Quartet No. 19 in C Major, K. 465?
A. true
B. false

Working with Selected Classe from Java API Chapter II.9 17


CORE RULES (with some Extras):

9.3 Create and manipulate calendar data using classes from java.time.LocalDateTime,
java.time.LocalDate, java.time.LocalTime, java.time.format.DateTimeFormatter,
java.time.Period
 All of the LDT-related classes are immutable.
 None of the LDT-related classes (incl. DTF and Period) have public constructors.
Corollary: All three primary classes are instantiated with now() or of(), e.g.:
LocalTime.now(); // 09:10:11.123 @ 9:10:11.123 a.m.
LocalDateTime.now(); // 2016-06-13T09:10:18.429
LocalDate.of(2016, Month.JUNE, 13); // 2016-06-13
LocalDateTime.of(2016,6,13,23,59); // 2016-06-13T23:59

NB: Months can be specified in two ways (see above).


Months start with 1 rather than zero (January is 01).
EXTRA: The overloaded of() that accepts months as words rather than numbers,
uses the enum Month defined in java.time together with most of the
other LDT-related classes.
EXTRA: The class DateTimeFormatter is defined in java.time.format.
 LocalDate doesn’t contain time-related fields whereas LocalTime doesn’t contain
date-related fields.
Known trap on the exam: A missing or unexpected field → comperr or RTE
LocalDate.of(2016,6,13,23,59); // INVALID: unexpected time
LocalDateTime.of(2016,6,13); // INVALID: missing time
LocalDateTime.parse("2016-06-13"); // DTPE: missing time
LocalTime.parse("2016-06-13T10:12"); // DTPE: unexpected date

 The methods likely to appear on the exam:


Class Methods
minusHours(long hoursToSubtract) plusHours(long hoursToAdd)
LocalTime
minusMinutes(long minutesToSubtract) plusMinutes(long minutesToAdd)
minusDays(long daysToSubtract) plusDays(long daysToAdd)
minusMonths(long monthsToSubtract) plusMonths(long monthsToAdd)
LocalDate
minusWeeks(long weeksToSubtract) plusWeeks(long weeksToAdd)
minusYears(long yearsToSubtract) plusYears(long yearsToAdd)
LocalDateTime all of the above
now() accesses the system clock in the default time-zone
of() LocalDateTime also has of(LocalDate, LocalTime)
Methods common parse(CharSeq) / parse(CharSeq, DateTimeFormatter) same args for all three classes
to all 3 classes format(DateTimeFormatter)
equals() only LT overrides Object’s equals() directly; other two implement interfaces
toString() Generates string in ISO-8601 format (e.g., 2016-06-13T23:29:50)

Known trap on the exam: Since the classes are immutable, adding or subtracting
time units becomes meaningless unless the code uses
the values returned by these methods (similarly to the
methods invoked on String objects).
LocalDate ld = LocalDate.of(2016, Month.JUNE, 13);
ld.plusDays(2);
System.out.println(ld); // still 2016-06-13...

18 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


 plusXXX() or minusXXX() methods are used to manipulate date and time values.
EXTRA: Method chaining for minusXXX() and plusXXX() works properly:
LocalDate date = LocalDate.of(2016, Month.SEPTEMBER, 30)
.plusMonths(-3)
.plusYears(20); // 2036-06-30

 parse(CharSequence) and parse(CharSequence, DataFormatter) methods are


used to obtain a date & time object from a text string.
Known trap on the exam: parse() needs appropriate number of components in
the text string (both date & time for LocalDateTime,
time only for LocalTime, date only for LocalDate),
otherwise a DateTimeParseException is thrown:
LocalTime lt = LocalTime.parse("10:12");
System.out.println(lt); // 10:12
LocalDateTime ldt = LocalDateTime.parse("2016-06-13T10:12");
System.out.println(ldt); // 2016-06-13T10:12
LocalDate ld = LocalDate.parse("2016-06-13T10:12"); // DTPE: unexp time

NB: Days, months, hours and minutes should be specified with TWO digits,
otherwise a DateTimeParseException is thrown; this rule isn’t applicable to
the method of().
LocalDate ld = LocalDate.parse("2016-6-13"); // throws DTPE
System.out.println(LocalDate.parse("2016-06-13")); // 2016-06-13
LocalTime lt = LocalTime.parse("1:2"); // throws DTPE
System.out.println(LocalDateTime.of(2017,1,1,1,1)); // 2017-01-01T01:01

 The class Period represents a number of days, months, weeks, or years, which can
be added to or subtracted from a LocalDate or a LocalDateTime object:
LocalDate someDate = LocalDate.of(2001, Month.JANUARY, 1)
.plus(Period.ofMonths(-3))
.minus(Period.ofYears(5)); // 1995-10-01

 EXTRA: Chaining for Period’s ofXXX() methods doesn’t work properly 5:


LocalDate ld1 = LocalDate.of(2000, Month.JANUARY, 1);
ld1 = ld1.minus(Period.ofDays(1)
.ofMonths(2)
.ofYears(3)); // 1997-01-01

→ instead of Period.ofDays(1).ofMonths(2).ofYears(3) use Period.of(3, 2, 1):


LocalDate ld2 = LocalDate.of(2000, Month.JANUARY, 1);
ld2 = ld2.minus(Period.of(3,2,1)); // 1996-10-31

 EXTRA: Period.parse("P1Y2M3D") is the same as Period.of(1, 2, 3).


 DateTimeFormatter is used to output dates and times in the desired format.
Possible trap: All DTF formatters that are likely to appear on the exam, start with
ISO, e.g.: ISO_DATE, ISO_TIME, ISO_LOCAL_DATE,
ISO_LOCAL_DATE_TIME, and so on → any other form 6 leads to
a comperr:
String today = LocalDate.parse("2016-09-20")
.format(DateTimeFormatter.LOCAL_DATE); // INVALID

EXTRA: Difference between ISO_**** and ISO_LOCAL_**** is the offset (e.g.,


ISO_DATE can output either ‛2011-12-03’ or ‛2011-12-03+01:00’ if the
offset is available while ISO_LOCAL_DATE outputs only ‛2011-12-03’).

5
Because Period’s ofXXX() methods are static; all they do is just return a newly created Period object.
6
Something like ofLocalizedTime(timeStyle) or RFC_1123_DATE_TIME is obviously out of scope for 1Z0-808.
Working with Selected Classe from Java API Chapter II.9 19
EXERCISES (for Key Summary ref.to App.D):

Problem 9.26 Given the following code fragment:


LocalDate today = LocalDate.of(2016, Month.JUNE, 13);
today.plusHours(24);
System.out.println(today);

What is the result?


A. 2016-06-14
B. 2016-06-13
C. Compilation fails
D. An exception is thrown at run time

Problem 9.27 Given:


public static void main(String[] args) {
String date = LocalDate.parse("2016-07-13")
.plusDays(31)
.format(DateTimeFormatter.ISO_DATE_TIME);
System.out.println(date);
}

What is the result?


A. 2016-07-13
B. 2016-07-14
C. 2016-07-15
D. Compilation fails
E. An exception is thrown at run time

Problem 9.28 Given:


LocalDate ld = LocalDate.of(2016, 6, 13);
ld.plusMonths(6).format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(ld);

What is the result?


A. December 13, 2016
B. June 13, 2015
C. 2016-12-13
D. 2016-06-13

Problem 9.29
Which two LOCs fail compilation?
A. LocalDateTime.of(2016,6,13);
B. LocalDate.of(2016, Month.JUNE, 50);
C. LocalDateTime.of(2016,06,13,14,15);
D. LocalDate ld = new LocalDate(2016,6,13);
E. LocalTime.now().format(DateTimeFormatter.ISO_DATE);

20 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.30 Given:
System.out.println(LocalDate.now().plus(Period.of(0,0,0)));
System.out.println(LocalDate.of(2016, Month.JUNE, 13)
.format(DateTimeFormatter.ISO_LOCAL_DATE));
System.out.println(LocalDate.parse("2016-06-13", DateTimeFormatter.ISO_DATE));

What is the result if the system date is June 13, 2016?


A. 2016-06-13
2016-06-13
2016-06-13
B. Compilation fails.
C. A DateParseException is thrown at runtime.

Problem 9.31 Given the full contents of the file JavaBirthday.java:


1 package birthday;
2 import java.time.LocalDate;
3 import java.time.format.DateTimeFormatter;
4
5 public class JavaBirthday {
6 public static void main(String[] args) {
7 LocalDate birthday = LocalDate.of(1995, Month.MAY, 23);
8 DateTimeFormatter formatter =
9 DateTimeFormatter.ofPattern("MMM dd, YYYY");
10 System.out.println("Java was born on " + birthday.format(formatter));
11 }
12 }

One of the LOCs fails compilation. Which two modifications, used independently, will
make the code print Java was born on May 23, 1995?
A. Replace line 2 with import java.time.*;
B. Replace line 3 with import java.time.format.*;
C. Replace Month.MAY on line 7 with Month.May
D. Replace Month.MAY on line 7 with 05

Working with Selected Classe from Java API Chapter II.9 21


CORE RULES (with some Extras):

9.4 Declare and use an ArrayList of a given type:


 ArrayList implements List, which extends Collection and Iterable → that’s why:
■ ArrayList works with reference types only:
– can accept a mixture of types when used without generics;
– primitives get autoboxed and unboxed as needed;
Corollary: for-each with a primitive loop var throws an NPE at null element.
■ is structurally mutable and resembles a resizable array:
– ArrayLists are zero-based like ordinary arrays;
– unlike arrays, initial size of an ArrayList cannot be specified;
– internally, the elements are stored in an Object[] array → throws AIOOBE
■ is ordered and iterable:
– allows positional (indexed) access to the elements;
– enhanced for loop returns the elements in the order they were added;
EXTRA: for-each cannot remove elements; use Iterator or ListIterator;
■ allows duplicates;
■ allows nulls;
■ can be made type-safe by using generics, for example, if Vehicle ← SUV:
List<Vehicle> al = new ArrayList<>();
SUV s = al.get(0); // INVALID because SUV is narrower than Vehicle
SUV s = (SUV)al.get(0); // OK but throws AIOOBE ’cause al isn’t populated

NB: Empty diamond on the left is not allowed.


NB: contains() is comperr-proof even if the List is generified:
List<String> list = new ArrayList<>();
list.add("hello");
System.out.println(list.contains(666)); // prints false

 ArrayList constructor likely to appear on the exam:


ArrayList() → constructs an empty list with an initial capacity of ten
 Methods likely to appear on the exam:
Method Function
add(E element) appends; returns true if successful
add()
add(int index, E element) inserts at the specified position; void
get() get(int index) returns the element at the specified position
set() set(int index, E e) modifies the elem at the spec’d position; returns what was before
remove(int indx) deletes the elem at the specified position (returns the deleted elem)
remove()
remove(Object obj) deletes 1st occurrence of obj (returns true if obj was present)
clear() Empties the list by setting its size to zero and each element to null
isEmpty() Returns true if the list contains no elements
contains() contains(Object obj) returns true if the list contains at least one obj
indexOf() indexOf(Object obj) returns the index of the 1st occurrence of obj (-1 if not found)
size() Returns the number of elements in this list (up to Integer.MAX_VALUE)
equals() Returns true if both lists contain the same elements in the same order
toString() Returns smth like ‛[elem1, elem2, elem3]’ (note square brackets and spaces after commas)

22 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Possible trap on the exam: Easily confused methods
StringBuilder ArrayList
length() size()
insert() add()
delete() remove()
replace() set()
capacity() –

 One more way to create a List is with the method Arrays.asList():


List<String> list = java.util.Arrays.asList("one",
"two",
"three");

Remarks: 1. The reftype must be List rather than ArrayList.


2. Unlike the lists created with a constructor defined in a List-
implementing class, this particular list is structurally immutable
(i.e., it cannot change its size 7).
3. I met this idiom on both sittings but only in the question that
was related to lambdas so the first two points are probably not
terribly important for our exam…
 EXTRA: List and ArrayList don’t have a simple sort() method; their sort() needs
a comparator → to sort an ArrayList, use java.util.Collections.sort(al) 8:
List<String> myList = new ArrayList();
myList.add("Hi");
myList.add("G'bye");
java.util.Collections.sort(myList);
System.out.println(myList); // [G'bye, Hi]

(Just a reminder:) To sort a regular array, use java.util.Arrays.sort(arr):


Integer[] arrInt = {1,3,4,2};
java.util.Arrays.sort(arrInt);
for(Integer E : arrInt) System.out.print(E); // 1234

7
Citing the Arrays API docs: "static <T> List<T> asList(T... a) returns a fixed-size list backed by the specified
array".
8
Being a utility class, Collections is made up entirely of static methods; same goes for java.util.Arrays.
Working with Selected Classe from Java API Chapter II.9 23
EXERCISES (for Key Summary ref.to App.D):

Problem 9.32 Given the following class definition:


class LangsToLearn {
public static void main(String[] args) {
List<String> langs = new ArrayList<>();
langs.add("Ruby");
langs.add("Perl");
langs.add("Perl");
langs.add("Closure");
if (langs.remove("Perl")) langs.add("Emacs Lisp");
System.out.println(langs);
}
}

What is the result?


A. [Ruby, Perl, Closure, Emacs Lisp]
B. [Ruby, Closure, Emacs Lisp, Emacs Lisp]
C. [Ruby, Closure, Emacs Lisp]
D. Compilation fails

Problem 9.33 Given:


ArrayList<String> someTypes = new ArrayList<>();
someTypes.add("byte");
someTypes.add("long");
someTypes.add("int");

Which two expressions evaluate to 3?


A. someTypes.size();
B. someTypes.capacity();
C. someTypes.length();
D. someTypes.get(2).size;
E. someTypes.get(2).length;
F. someTypes.get(2).length();

Problem 9.34 Given the following code fragment:


ArrayList<Integer> list = new ArrayList(); // a1
list.add(1); // a2
System.out.println(list.get(list.size())); // a3

What is the result?


A. 1
B. Compilation fails on line a1
C. Compilation fails on line a2
D. Compilation fails on line a3
E. An IndexOutOfBoundsException is thrown at run time

Problem 9.35 Given:


class TestingArrayList {
public static void main (String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 5; i++) list.add("" + i);
System.out.println(list.remove(list.indexOf("4")));
}
}

24 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


What is the result?
A. true
B. 4
C. [0, 1, 2, 3, 4]
D. Compilation fails

Problem 9.36 Given:


public class MutatisMutandis {
public static void main(String[] args) {
List list = new ArrayList();
list.add(new StringBuilder(""));
list.add("");
for (Object e : list )
if (e instanceof StringBuilder) ((StringBuilder)e).append("OK");
else ((String)e).concat("OK");
System.out.println(list);
}
}
What is the result?
A. [OK, OK]
B. [OK, ]
C. Compilations fails
D. A RuntimeException is thrown

Problem 9.37 Given:


class Birdies{
public static void main(String[] args) {
List aviary = new ArrayList<>(); // line b1
aviary.add("kinglet");
aviary.add("finch");
aviary.add("titmouse");
aviary.add(aviary.set(0,"jay")); // line b2
System.out.println(aviary);
}
}
What is the result?
A. [jay, finch, titmouse, kinglet]
B. [jay, finch, titmouse, true]
C. Compilation fails on line b1
D. Compilation fails on line b2

Problem 9.38 Given:


class Sweet16 {
public static void main(String[] args) {
List<Integer> ages = new ArrayList<>();
ages.add(16);
ages.add(null);
for (int i = 0; i < ages.size(); i++) System.out.print(ages.get(i));
for (int i : ages) System.out.println(i);
}
}
What is the result?
A. 16null16
B. 16null16null
C. 16null16 and a NullPointerException
D. Compilation fails

Working with Selected Classe from Java API Chapter II.9 25


CORE RULES (with some Extras):

9.5 Write a simple lambda expression that consumes a lambda Predicate expression:
 The abstract method test() declared in the interface Predicate returns a boolean
and takes an argument of type Object.
 Since there’s only one formal parameter (which corresponds to test()’s arg), its type
and enclosing parentheses are optional.
 If the method body contains a single boolean-returning stat, the braces can be
omitted UNLESS the stat uses an explicit return – in which case we must apply
the Semirebra 9 Rule.
 The Semirebra Rule:
Semicolon, return and braces in lambda method body always go together.
Traps! – empty parameter list, or
– return without semicolon and braces, or
– semicolon without return and braces, or
– the method body does not return a boolean.
Typical invalid patterns likely to appear on the exam:
( ) -> whatever // param list is empty
(x,y) -> whatever // too many params
(x) -> System.out.print(x) // System.out.print() is void
x -> { return "" + x; } // String instead of a boolean
str -> return str.isEmpty(); // return and ; need {}
str -> { return str.isEmpty() } // return and {} need ;
str -> str.isEmpty(); // ; needs both return and {}
whtvr -> return true // missing both ; and {}
 What Predicate is typed to must be consistent with the parameter’s type.
Consider the following:
static String check(List list, Predicate p){
return p.test(list)? "Empty" : "Not empty"; }
public static void main(String[] args) {
ArrayList list = new ArrayList();
System.out.println(check(list, al -> al.isEmpty())); // INVALID
}

The above example fails to compile because p isn’t generified → its type is therefore
Object → and Object doesn’t have the method isEmpty(). On the other hand, the
code would have compiled if al.isEmpty() were replaced, say, with al.equals("").
Better yet, cast the formal param to List or ArrayList (e.g., ((List)al).isEmpty()) as
this wouldn’t break the logic behind the code, which happens with equals("").
Let’s have another example that doesn’t compile:
static String check(List list, Predicate<ArrayList> p){
return p.test(list)? "Empty" : "Not empty"; // INVALID
}
public static void main(String[] args) {
List list = new ArrayList();
System.out.println(check(list, al -> al.isEmpty()));
}

9
Just an acronym: ‛semi’ for ‛semicolon’, ‛re’ for ‛return’, and ‛bra’ for ‛braces’. As the Semirebra Rule is
specifically tailored to java.util.function.Predicate, it is meant to be used on the 1Z0-808 exam only.

26 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Here, Predicate is typed to ArrayList while the object it must work with is of type
List. In other words, the method test() was promised that its argument is going to
have everything that is typical for an ArrayList; instead, test() gets just a List,
which is not sufficient.
Alright, let’s flip the types in the check() method’s signature:
static String check(ArrayList list, Predicate<List> p){
return p.test(list)? "Empty" : "Not empty";
}

public static void main(String[] args) {


List list = new ArrayList();
System.out.println(check(list, al -> al.isEmpty())); // INVALID
}

Did it help? Nope, the comperr just moved to the printing stat’s line: although test()
is perfectly happy now because it expected a toy of type List while what it’s gonna
get will be even more sophisticated and amusing, the actual call to check() provides
the same unrefined, boring List. If the available options prevent us from touching
the check() method’s signature, we could change list’s reftype:
ArrayList list = new ArrayList();

Another way to deal with this problem involves casting list to ArrayList:
System.out.println(check((ArrayList)list, al -> al.isEmpty()));

After all, the actual type of the object at run time is ArrayList, so this quick’n’dirty
hack will even work…
 EXTRA: Watch out for already declared vars in lambdas: while the parameter list
does declare new vars to be used in the body part of the lambda expression, these
variables won’t get new scope and, therefore, cannot shadow the previously declared
vars:
List al = new ArrayList();
System.out.println(check(al, al -> al.isEmpty())); // INVALID

Working with Selected Classe from Java API Chapter II.9 27


EXERCISES (for Key Summary ref.to App.D):

Problem 9.39 Given the following class definitions:


class Examinee {
private String name;
private int score;
public Examinee(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() { return name; }
public int getScore() { return score; }
}
class ReleasingResults{
public static void checkScore(List<Examinee> list, Predicate<Examinee> p){
for (Examinee e : list) {
if (p.test(e)) {
System.out.print(e.getName() + ", ");
}
}
}
public static void main(String[] args) {
List<Examinee> list = Arrays.asList(new Examinee("Alice", 98),
new Examinee("Bob", 48),
new Examinee("Charlie", 62),
new Examinee("Doug", 88));
System.out.print("Passed: ");
// line r1
}
}

Which LOC, when inserted at line r1, enables the code to print Passed: Alice, Doug, ?
A. checkScore(list, () -> e.getScore() > 65);
B. checkScore(list, Examinee e -> e.getScore() > 65);
C. checkScore(list, e -> e.getScore() > 65);
D. checkScore(list, (Examinee e) -> { e.getScore() > 65; });

Problem 9.40
Let sb refer to a StringBuilder object. Which of the following fail(s) compilation?
A. sb -> sb.toString()
B. StringBuilder sb -> sb.toString()
C. (StringBuilder sb) -> return sb.length();
D. (StringBuilder sb) -> { return sb.length(); }

Problem 9.41 Given:


class Test {
String check(List list, Predicate p){ // line t1
return p.test(list)? "Empty" : "Populated";
}
void run() {
ArrayList list = new ArrayList(); // line t2
System.out.println(
check(list, list -> list.isEmpty())); // line t3
}
public static void main(String[] args) {
new Test().run();
}
}

28 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Which two options can make the code compile and run successfully?
A. Replace line t3 with check(list, myList -> list.isEmpty()));

B. Replace line t2 with List list = new ArrayList();

and replace line t3 with check(list, myList -> myList.isEmpty()));

C. Replace line t1 with String check(List list, Predicate<ArrayList> p){

and line t3 with check(list, myList -> myList.isEmpty()));

D. Replace line t1 with String check(ArrayList list, Predicate<ArrayList> p){

line t2 with List mist = new ArrayList();

and line t3 with check(mist, list -> list.isEmpty()));

E. Replace line t1 with String check(List list, Predicate<List> p){

and line t3 with check(list, myList -> myList.isEmpty()));

Problem 9.42 Given:


class Suspect {
private String name;
private boolean statement;

public Suspect (String name) {


this.name = name;
this.statement = Math.random() < 0.5 ? false : true;
}

public boolean getStatement() { return statement; }


public String getName() { return name; }
}

class Interrogation {

private static void interrogate(List<Suspect> perps){


for(Suspect e : perps)
if (e.getStatement() != true)
System.out.println(e.getName() + " is lying!");
}

public static void main(String[] args) {


List<Suspect> roundUp = new ArrayList();
roundUp.add(new Suspect("Alice"));
roundUp.add(new Suspect("Bob"));
roundUp.add(new Suspect("Charlie"));
roundUp.add(new Suspect("Doug"));
roundUp.add(new Suspect("Eugine"));
roundUp.add(new Suspect("Frances"));

interrogate(roundUp);
}
}

Working with Selected Classe from Java API Chapter II.9 29


Which modification will achieve the same result?
A. Overload the method interrogate() with the following code fragment:
private static void interrogate(List<Suspect> perps, Predicate p){
for(Suspect s : perps)
if(!p.test(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with the following LOC:


interrogate(roundUp, perps -> perps.getStatement());

B. Overload the method interrogate() with the following code fragment:


private static void interrogate(List perps, Predicate<Suspect> p){
for(Suspect s : perps)
if(!p.test(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with the following LOC:


interrogate(roundUp, perps -> perps.getStatement());

C. Add the following interface:


interface LieDetector {
default boolean test(Suspect s){ return s.getStatement(); }
}

then overload the method interrogate() with the following code fragment:
private static void interrogate(List<Suspect> perps, LieDetector ld){
for(Suspect s : perps)
if(!ld.test(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with the following LOC:


interrogate(roundUp, perps -> perps.getStatement());

D. Add the following interface:


interface LieDetector { boolean analyze(Suspect s); }

then overload the method interrogate() with the following code fragment:
private static void interrogate(List<Suspect> perps, LieDetector ld){
for(Suspect s : perps)
if(!ld.analyze(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with the following LOC:


interrogate(roundUp, perps -> perps.getStatement());

Problem 9.43
Which one is true?
A. Functional interface may not contain more than one method.
B. Any interface that has a single abstract method is therefore functional.
C. Functional interface cannot have superinterfaces.
D. Functional interface cannot be extended.
E. None of the above.

30 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Keys & Discussion:

Problem 9.1 – D
Given:
class Hello {
public static void main(String[] args) {
String str = "Hello";
StringBuilder sb = new StringBuilder(str);
str.replace("o", ""); // h1
System.out.print(str + " "); // h2
System.out.print(str.replace("o","") + " "); // h3
System.out.print(sb.append("?").equals(sb.append("!")) + " "); // h4
System.out.println(str.replace("o","").equals(str.replace("o",""))); // h5
}
}

What is the result?


A. Hell Hell false false
B. Hell Hell true true
C. Hello Hell false false
D. Hello Hell true true
E. Hello Hell false true
F. Hello Hell true false

The first thing coming to your mind whenever you see a String object on the exam should be
something like "Ah! This animal is immutable, so I’d better be careful…" Naturally, there are
also some quirky methods to watch out for but, basically, this is it.
Now please list the immutable classes that are on our exam; we mentioned them when discussing
the solution to Problem 4.3… Did you get them all 10? Good.
Back to String. Since str is immutable, line h1 doesn’t change the original object; instead, a new
object is created – and wasted because the reference to it isn’t used in any way, so line h2 prints
the same old ‛Hello’. With a trailing space, of course. On the other hand, line h3 outputs ‛Hell ’
because the printing stat acts on the object that was returned by replace().
As for line h4, StringBuilder doesn’t override Object’s equals() → hence the method simply
compares two identical references and returns true. We should always keep in mind that
methods act on objects through a reference, so that’s why when the second append() completes
its job, both operands will contain the same sequence of characters, namely ‛Hello?!’. Let’s have
a simple illustration of this principle, this time with a class that does override equals():
class General{
int stars = 1;
General bePromoted(int stars){
this.stars += stars;
return this;
}
@Override
public String toString(){ return "" + stars; }
}
class ChiefOfStaff {
public static void main(String[] args) {
General g = new General();
System.out.println(g.bePromoted(1).equals(g.bePromoted(2))); // true
System.out.println(g); // 4
}
}

10
String + all LDTs + all Wrappers such as Byte, etc. + structurally-immutable List created by Arrays.asList().
Working with Selected Classe from Java API Chapter II.9 31
In the above example, the object is always the same, and any change made to it through a
reference gets reflected on both sides of equals().
Next step (we are getting back to the current Problem 9.1, by the way); what happens when we
have a mirror situation: the class String that, unlike StringBuilder, is not only immutable but
also overrides equals()? Line h5 answers that by printing true, but why? Specifically, is it
because String is immutable or for some other reason?
Alright, the first operand, namely str.replace("o",""), creates an identical twin to str, changes its
contents, delivers this freshly baked object to equals(), who grabs it, peeks inside and sees…
hmm… it sees Hell.
The second operand in its own turn takes the reference to the original and immutable str, which
still reads "Hello", does its thing and returns another new object that again contains "Hell". So on
both palms of equals() lie pointers to two different objects, which just happen to be made of the
same hellish stuff. Compare it to the situation with the mutable StringBuilder where append()
each time acts on and returns reference to the same object…
And what about an immutable object in a class that does not overrides equals()? Here we go:
class General{

int stars = 1;

General bePromoted(int stars){ // 'stars' denotes rank itself


if (stars - this.stars != 0) { // so bePromoted(2) means
General g = new General(); // promotion to two-star general
g.stars += stars; // rather than three-star
return g;
}
else return this; // returns same obj if no change in rank
}

General beDemoted(int stars){


if (this.stars - stars != 0) {
General g = new General();
g.stars -= stars;
return g;
}
else return this;
}

// @Override
// public String toString(){ return "" + stars; }
}

class ChiefOfStaff {

public static void main(String[] args) {


General g = new General();
System.out.println(g.bePromoted(2).equals(g.bePromoted(2))); // false
System.out.println(g.stars); // 1
System.out.println(g.beDemoted(1).equals(g.beDemoted(1))); // true
System.out.println(g.stars); // 1
}
}

Our brave general became unsinkable although unpromotable!

32 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.2 – D
Given:
class OurPets {
static String checkPets(StringBuilder myPet, StringBuilder yourPet){
return myPet == yourPet ? "same" : "different";
}
static String checkNames(StringBuilder myPet, StringBuilder yourPet){
return myPet.equals(yourPet) ? "same" : "different";
}
public static void main(String[] args) {
StringBuilder myPet = new StringBuilder("Fluffy");
StringBuilder yourPet = new StringBuilder("Fluffy");
System.out.print(checkPets(myPet, yourPet) + " pets, ");
System.out.println(checkNames(myPet, yourPet) + " names");
}
}

What is the result?


A. same pets, same names
B. different pets, same names
C. same pets, different names
D. different pets, different names
E. Compilation fails

Since StringBuilder doesn’t override equals(), checkNames() is virtually identical to


checkPets(): it simply compares references.

Problem 9.3 – A
Given:
class TheFifthElement {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("1"); // earth
sb.append("2"); // water
sb.append("3"); // air
sb.append("4"); // fire
sb.replace(4,4,"Leeloo"); // line t1
System.out.println(sb);
}
}

What is the result?


A. 1234Leeloo
B. Compilation fails
C. The code throws a run-time exception

StringBuilder does have a constructor that accepts a String, and its append() is overloaded for
all imaginable types.
Now, unlike the class String, StringBuilder’s replace() isn’t overloaded: its only version takes
three args, namely (int start, int end, String replacementString). In short, the code is perfectly
valid.
As with all the other methods in String and StringBuilder that accept two indices to limit a
specific part of the character sequence (such as str.substring(int beginIndex, int endIndex),
sb.append(CharSequence s, int start, int end), etc.), the first index is inclusive while the second

Working with Selected Classe from Java API Chapter II.9 33


one is exclusive → the substring on line t1 starts with the 5th element and ends with the element
number 4. Looks mighty suspicious.
The code, however, doesn’t throw a RuntimeException (a SIOOBE, to be exact) because –
according to the StringBuilder API docs – the exception is generated "if start is negative,
greater than length(), or greater than end".
And what replace() does, then? It
…replaces the characters in a substring of this sequence with characters in the specified String. The substring
begins at the specified start and extends to the character at index end - 1 or to the end of the sequence if no
such character exists. First the characters in the substring are removed and then the specified String is inserted
11
at start. (This sequence will be lengthened to accommodate the specified String if necessary.)

Problem 9.4 – C
Given the following class:
class Test {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
String str = null; // line t1
for(int e : arr){ str += e; }
System.out.println(str);
}
}

What is the result:


A. _12345 (where _ denotes an empty space)
B. 12345
C. null12345
D. Compilation fails
E. A NullPointerException is thrown

String is a reference type and, as such, can be null, so the assop on line t1 is valid.
What about the next LOC? Let’s run the entire logical chain:
Step 1. str += e actually means str = str + e;
Step 2. JLS, §15.18, Additive Operators: "If the type of either operand of a + operator is
String, then the operation is string concatenation".
Step 3. JLS, §5.1.11, String Conversion: "If the reference is null, it is converted to the
string "null" (four ASCII characters n, u, l, l)".
→ so there’s neither a comperr nor RTE → this is why the first iteration results in ‛null1’ – and
everything after that is trivial.

11
Quoting from the StringBuilder API docs.

34 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.5 – BE
Hoping to land a job as a junior programmer at a local bank, you came to a Java interview
and were asked to complete the following class that masks 20-digit account numbers so that
only the last five digits will be visible to the user while each of the first 15 digits is replaced
with an asterisk:
public class AccountMasker {
public static String maskAccount(String accNum) {
String lead = "***************"; // contains 15 asterisks in a row

// your code goes here

public static void main(String[] args) {


String accNum = args[0];
System.out.println(maskAccount(accNum.replace(" ","")));
}
}

Specifically, your task is to finish up the method maskAccount(String accNum) so that the
class AccountMasker will output ****************67541 when run with the following
command:
java AccountMasker "34296 01853 49820 67541"
Which two LOCs, when used independently, will achieve this requirement?
A. return (new StringBuilder(accNum)).substring(15, 20).toString();
B. return lead + accNum.substring(15, 20);
C. return new StringBuilder(accNum).append(lead, 15, 20).toString();
D. return new StringBuilder(accNum).insert(0, lead).toString();
E. return new StringBuilder(lead).append(accNum, 15, 20).toString();

As usual, we start our analysis by looking at the available options: what if some of them can be
eliminated right away? It happens a lot on the exam, and this time is not an exception.
The output must contain asterisks (disguised as the var lead) → option A doesn’t even mention
that var → A is immediately out.
What about B? substring() works in the same way for both String and StringBuilder: it returns
a String and is overloaded for (int start) and (int start, int end) → we have the second version,
which returns whatever sits between index 15 inclusive and index 20 exclusive → what does this
method receive? → it receives the object returned by replace(" ", "") → to wit, a 20-digit
sequence now void of spaces because String’s replace() acts on each occurrence of the target
char or CharSequence → substring contains 67541 → it gets prepended with lead → bingo.
Now to option C. maskAccount()’s arg, represented by the local var accNum, contains 20 digits
without spaces → a new StringBuilder object gets created → it contains accNum → then
append() attempts to add to it five characters taken from lead → but in doing so it goes too far,
beyond the last available value since lead contains only 15 characters → an IOOBE.
Option D: insert() places lead at the first position in the StringBuilder object thus shifting to
the right entire bunch of whatever the object used to contain, namely a 20-digit string → the
result is way too long.
And since what’s left is just option E, we accept it without even analyzing its logic → but at the
Review stage we must do it → append() adds to lead a five-digit string extracted from
accNum’s tail → then converts the whole works to String and returns it → yeap, looks fine.

Working with Selected Classe from Java API Chapter II.9 35


Problem 9.6 – D
Which statement initializes a StringBuilder to a capacity of 256?
A. StringBuilder sb = new StringBuilder(new String(256));
B. StringBuilder sb = StringBuilder.setCapacity(256);
C. StringBuilder sb = StringBuilder.setLength(256);
D. StringBuilder sb = new StringBuilder(256);

Since the answer to the problem is obvious, we can afford to spend a minute to take a look at the
bigger picture.
Only two classes on our exam have something that relates – either directly or indirectly – to this
particular creature called capacity, namely StringBuilder and ArrayList:

ArrayList StringBuilder
ArrayList() StringBuilder()
Constructs an empty list with an initial capacity Constructs a string builder with no characters in it
of ten. and an initial capacity of 16 characters.
Constructors ArrayList(int initialCapacity) StringBuilder(int capacity)
Constructs an empty list with the specified Constructs a string builder with no characters in it
initial capacity. and an initial capacity specified by the capacity
argument.
void ensureCapacity(int minCapacity) void ensureCapacity(int minimumCapacity)
Increases the capacity of this ArrayList Ensures that the capacity is at least equal to the
instance, if necessary, to ensure that it can hold specified minimum.
at least the number of elements specified by the
minimum capacity argument.
Methods void trimToSize() void trimToSize()
Trims the capacity of this ArrayList instance to Attempts to reduce storage used for the character
be the list’s current size. sequence.
int capacity()
Returns the current capacity.

Although it may sound so, capacity is not an upper limit of how much we can put into the
StringBuilder or ArrayList; it’s a value defining a boundary beyond which the internal array
must be reallocated to accommodate the necessary number of elements (in case of ArrayList) or
the CharSequence’s length (in case of StringBuilder). Whereas StringBuilder lets both get
and set its capacity, ArrayList does not provide a direct read access.
Back to our problem; option A doesn’t compile because String defines no constructor that would
take an int as its only arg; now please list the String constructors that are likely to appear on the
exam 12.
As for options B and C, they are just plain wrong. First of all, StringBuilder doesn’t have static
methods so the name of the class cannot be used in any invocation. Secondly, setCapacity()
doesn’t even exist in StringBuilder; lastly, either method would have to return a StringBuilder
object, and setters in a mutable class are usually void – just as setLength() is…

12
String(String str) and String(StringBuilder sb) + String(), which is virtually useless because the object is
immutable.

36 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.7 – AD
Given the code fragment:
StringBuilder sb = new StringBuilder();
String exam = "1Z0";
int code = 808;

Which two options will output the following:


I’ll pass 1Z0-808
A. System.out.println(sb.append("I’ll pass " + exam + "-" + code));
B. System.out.println(sb.insert("I’ll pass ").append(exam + "-" + code));
C. System.out.println(sb.insert("I’ll pass ").insert(exam).insert("-").insert(code));
D. System.out.println(sb.append("I’ll pass ").append(exam).append("-").append(code));

Of all the core Java classes we are supposed to learn for the exam only StringBuilder defines
insert() – which is indeed our case. However, this insert() in all its overloaded versions requires
at least two args (we need to specify what is to be inserted and where) → options B and C are
immediately eliminated.

Problem 9.8 – C
Given:
public static void main(String[] args) {
String a = "B ";
a = a.concat("U "); // line X
String b = "L ";
a = a.concat(b); // line XX
a.replace('U', 'A'); // line XXX
a = a.concat(b); // line XXXX
System.out.println(a);
}

What is the result?


A. BALL
B. BLA
C. BULL
D. BUA
E. BUAL

We are dealing with String, which is immutable → the LOC on line XXX is immaterial as it
doesn’t assign the newly created object back to the var a. What is left for us is imitate the work
of lines X, XX and XXXX on paper → line X results in B U → then line XX appends ‛L’ to
what a holds → and line XXXX does the same.

Problem 9.9 – C
Given:
public class Simple{
public static void main (String[] args){
char c = 6;
System.out.println("Hello".charAt(c));
}
}

Working with Selected Classe from Java API Chapter II.9 37


What is the result?
A. There is no output
B. Compilation fails
C. The code throws an IndexOutOfBoundsException
D. The code throws a NullPointException

String’s charAt() takes an int, and Java treats char as an integral type representing values from
0 to 65535 inclusive → there is no comperr.
As for what happens at run time, since ‛Hello’ contains only five characters, the code attempts to
access something that doesn’t exist → IOOBE (or, to be more precise, a SIOOBE).

Problem 9.10 – D
Given:
StringBuilder bucket = new StringBuilder("Empty me!");

Which statement(s) will empty the contents of the bucket object?


A. bucket.empty();
B. bucket.clear();
C. bucket.delete(0, bucket.size());
D. bucket.delete(0, bucket.length());
E. bucket.deleteAll();
F. bucket.remove(0, bucket.length());
G. bucket.removeAll();

This problem is obviously about one of the easily confused methods. Consult this table among
the rules that relate to Exam Objectives 9.1 & 9.2 to refresh your memory, when in doubt.
Neither String nor StringBuilder nor ArrayList has an empty() method. The method clear()
belongs to ArrayList, and same goes for remove() and removeAll() → we are left to choose
among the three versions of delete().
deleteAll() is there to confuse you; there’s no such method, it simply bears a resemblance to
ArrayList’s removeAll().
Finally, as size() is defined in ArrayList while StringBuilder – together with String – uses
length(), we arrive at the correct conclusion that the answer to our Problem 9.10 is option D.

Problem 9.11 – B
Given:
class PoorGirl {
public static void main(String[] args) {
String name = "Javeline";
System.out.println("Hi! I’m " + name.replace("e", "a"));
}
}

What is the result?


A. Hi! I’m Javaline
B. Hi! I’m Javalina
C. Hi! I’m Jevaline
D. Hi! I’m Jeveline

38 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


The method replace() is defined in both String (where it is overloaded and takes two args –
target followed by replacement – in both cases) and StringBuilder (where it is not overloaded
and accepts three args). One of the most remarkable features of replace() in String is that it
substitutes each occurrence of the target → every ‛e’ in Javeline gets replaced with an ‛a’.

Problem 9.12 – D
Given the following main() method:
public static void main(String[] args) {
String str = " ";
str.trim();
System.out.println(str.equals("") + " " + str.isEmpty());
}

What is the result?


A. true true
B. true false
C. false true
D. false false

The Strings created with double quotes are placed into a common string pool; everything else –
such as Strings instantiated with the new keyword or computed at run time – isn’t…
The above sentence is just a reminder; it’s not directly relevant to our Problem because
str.trim() returns a completely new object (but only if there were changes, that is), which in our
case doesn’t get used at all → str still points to the same object.
Now, it is immaterial whether or not the Strings " " and "" live in a common pool: they are
definitely distinct → and since equals() is overridden in String, it compares different contents.

Problem 9.13 – B
Given:
StringBuilder sb = new StringBuilder();
sb.append("Duke");

And the following LOCs:


System.out.println(sb.insert(0, "Hello "));
System.out.println(sb.append(0, "Hello "));
System.out.println(sb.add(0, "Hello "));
System.out.println(sb.set(0, "Hello "));
How many of them print Hello Duke?
A. None
B. One
C. Two
D. Three

The first printing stat appears quite natural. As for append(), it works with the tail only, so even
its args look suspicious.
add() gets used so often that by now we should remember that it is a dweller of the ArrayList
realm.

Working with Selected Classe from Java API Chapter II.9 39


The method set() is a rarer bird but its logic dictates that it would simply replace the very first
element with Hello – and the very first element in our StringBuilder is just ‛D’. Still, it would
have worked if only it were invoked on a proper object because set() also belongs to
ArrayList…

Problem 9.14 – C
Given the following code fragment:
String str1 = "null";
String str2 = new String("NULL");
System.out.println(str1.equalsIgnoreCase(str2.toLowerCase())); // line 1
System.out.println(str2 == str2.replace('L','l').toLowerCase()); // line 2
System.out.println(str1 == str1.replace('L','l').toLowerCase()); // line 3

How many times the code prints true?


A. Not a single time
B. Once
C. Twice
D. Three times
Alright, as we start reading the code, here comes immediate realization that both objects are
immutable and that str1 is a member of a common string pool whereas str2 isn’t. But is it
important? We don’t know yet; need to analyze further.
Next step: str2.toLowerCase() on line 1 returns ‛null’ and equalsIgnoreCase() compares it with
str1’s ‛null’.
Line 2 uses ==, which compares references only → str2.replace('L', 'l') returns a completely new
object on which toLowerCase() is then invoked resulting in yet another object. All in all, on
both sides of == sit different objects so it’s no wonder that line 2 outputs false.
Line 3 resembles line 2 so damn much that it’s tempting to assume both LOCs lead to identical
results, which would be a disaster. As str1 is made up of letters in lowercase from the very
beginning, replace() – finding not a single match – returns reference to the same object. Then
toLowerCase() follows its steps → in the end, on either palm of == sits the same object.
When reviewing you answers, pay close attention so something like option A, which might mean
that the code doesn’t compile. In our case, the only point of concern is probably the invocation of
replace() that uses chars as the method’s args.
You’ll do mighty well remembering that String overloads replace() and that this method indeed
can take chars as its args. The overloaded version accepts CharSequence… What about
StringBuilder? and ArrayList? 13

Problem 9.15 – D
Given:
public class TheMatrix {
public static void main(String[] args) {
String movie = "The";
movie.concat(" ").concat("MATRIX".toLowerCase());
System.out.print(movie.substring(5,6));
}
}

13
ArrayList has no replace(): it uses set(int index, E element) instead. StringBuilder defines replace(int start, int
end, String str) and doesn’t overload it.

40 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


What is the result?
A. a
B. at
C. Compilations fails
D. An exception is thrown at run time

A String? and the reference to it doesn’t get reassigned? → same object all along.
And whoever wrote that substring() invocation was obviously half asleep for the method wants
to grab the 6th character while movie still has only three.

Problem 9.16 – C
Given:
public class TheMatrixReloaded {
static void reload(StringBuilder sb) {
sb.append(" Matrix");
sb.insert(" Reloaded", sb.length());
}
public static void main (String[] args) {
StringBuilder sb = new StringBuilder("The");
reload(sb);
System.out.println(sb);
}
}

What is the result?


A. The
B. The Matrix Reloaded
C. Compilation fails
D. An exception is thrown at run time

Many people prefer to read code starting from the main() method and then just following the
program’s business logic. The questions on our exam aren’t long (with a possible exception of
lambda-related problems – soon you’ll see what I mean) so it is also possible to start on the top
and then work your way to the bottom. Either way, you should notice that the invocation of
insert() is wrong: its args switched places.
Otherwise the answer would have been option B because StringBuilder is mutable, and we do
remember that Java is pass-by-value.

Problem 9.17 – E
Given the code fragment:
public static void main (String[] args) {
String[] str = new String[2];
int i = 0;
for (String e : str)
System.out.print(e.concat(" " + i++).trim());
}

Working with Selected Classe from Java API Chapter II.9 41


What is the result?
A. 01
B. 01
C. 01
D. Compilation fails
E. An exception is thrown at run time

str is an array, and arrays, when allocated, always get inited with default values in their slots. In
our case, the slots are of type String, which is a reference type, hence the default value is null.
Invoking a method on a null object is one of the most typical NPE-throwing scenarios on the
exam.

Problem 9.18 – B
Given:
public class Exam {
String str = ""; // line e1
static void pass(String str) {
str.concat("Passed");
}
public static void main(String[] args) {
String str = "Failed ";
pass(str);
System.out.println(str);
}
}

What is the result?


A. Passed
B. Failed
C. Failed Passed
D. Compilation fails
E. An exception is thrown at runtime

The var str declared in the method main() is local and, therefore, shadows the instance var str
on line e1, which is a good thing because pass() is static → the code doesn’t throw a comperr.
The method concat() is invoked correctly: it is overloaded for any data type so accepting a
String isn’t a problem, and the object itself isn’t null.
If the class String were mutable, the method pass() would have returned ‛Failed Passed’ – but it
isn’t, so str.concat() dutifully creates a new object, which is then simply wasted.

Problem 9.19 – B
Given:
public class AnotherExam {
public static void main (String[] args) {
StringBuilder sb = new StringBuilder("Passed");
System.out.print(sb + ": ");
System.out.println(sb.replace(0,4,"Fail") ==
sb.delete(0,666).insert(0,"Failed"));
}
}

42 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


What is the result?
A. Passed: false
B. Passed: true
C. Failed: false
D. Failed: true
E. Compilation fails
F. The code throws IndexOutOfBoundsException

StringBuilder’s replace() is not overloaded, takes three args (int start, int end, String str) and
returns the reference to the current object, so the left-hand side of == is valid → the object
contains now ‛Failed’.
Now to the right-hand side: StringBuilder’s delete() isn’t overloaded, either, and takes two args,
namely (int start, int end). A question arises: is it OK if the end index is way beyond the object’s
boundary? won’t the code throw an IOOBE?
No, says the API documentation: "[the method] throws StringIndexOutOfBoundsException if
start is negative, greater than length(), or greater than end" → the method successfully deletes
the entire string → and then insert() – which is overloaded, by the way – slips in ‛Failed’ at the
first position.
Whatever the object contains is, however, immaterial as == compares references and we are
dealing here with a mutable data type → the last printing stat outputs true.

Problem 9.20 – B
Given:
public class Capricchio {
public static void main (String[] args) {
Object obj = null;
StringBuilder sb = new StringBuilder(); // line c1
sb.append(obj);
System.out.println(sb.length());
}
}

What is the result?


A. 1
B. 4
C. 16
D. Compilations fails
E. A NullPointerException is thrown at run time

Line c1 creates a StringBuilder object with no characters in it and an initial capacity of 16. As
for the method append(), it is overloaded for all imaginable types → its operation is therefore
successful.
But what exactly does it append? The mike goes to the API documentation:
append(Object obj) appends the string representation of the Object argument.
Next question: how this ‛string representation’ thingy is obtained? In a traditional way, that is, by
calling toString() on obj? If so, this will surely throw an NPE… Option E, then?

Working with Selected Classe from Java API Chapter II.9 43


Not at all; let’s listen further to the API docs for StringBuilder’s append(Object obj):
The overall effect is exactly as if the argument were converted to a string by the method
String.valueOf(Object), and the characters of that string were then appended to this character
sequence.
And String.valueOf(Object) pipes in with this:
If the argument is null, then a string equal to "null"; otherwise, the value of obj.toString() is
returned.
In short, our StringBuilder contains now the string ‛null’ – which is four characters long.

Problem 9.21 – C
Given:
public class HowAboutThisOne {
public static void main (String[] args) {
String str = null;
StringBuilder sb = new StringBuilder(str += str);
sb.delete(0,sb.length());
System.out.println(sb.capacity());
}
}

What is the result?


A. 8
B. 16
C. 24
D. Compilations fails
E. A NullPointerException is thrown at run time

Every LOC is valid so there’s no comperr:


– str is a refvar and can be assigned null;
– str += str means str = str + str, and the + op is overloaded for String resulting in
‛nullnull’;
– StringBuilder indeed have an overloaded constructor that accepts a String;
– delete() is invoked correctly → no RTE, and
– StringBuilder class does define an instance field named capacity.
Now we only have to choose among options A, B and C. The StringBuilder API documentation
defines capacity in this way: "The capacity is the amount of storage available for newly inserted
characters, beyond which an allocation will occur". As for length, it’s a character count.
Unfortunately, this information is not enough to arrive at the correct answer; we really need to
look at the definition of the StringBuilder constructor that accepts a String:
Constructs a string builder initialized to the contents of the specified string. The initial capacity of
the string builder is 16 plus the length of the string argument.
QED.

44 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.22 – A
Given:
class Slogan {
public static void main(String[] args) {
String str = "String Beans Forever!";
// line XXX: only a single LOC goes in here!
}
}

And the following LOCs:


System.out.println(str.delete(6,11));
str = str.delete(6,11); System.out.println(str);
str.replace(" Bean",""); System.out.println(str);
System.out.println(new StringBuilder(str).remove(" Bean").toString());

How many LOCs, when inserted independently at line XXX, will make the code print
Strings Forever!?
A. None
B. One
C. Two
D. Three

First and foremost – please do pay attention, this one is important – String has neither delete()
nor insert(); they belong to StringBuilder. The only methods that appear to change a String
structurally are concat(), replace() and trim() → the first two LOCs are definitely out.
LOC number three, while valid, isn’t what we need: it does remove the string " Bean" but the
computed result gets wasted because the hasty slogan writer forgot to assign it back to str.
Now, I don’t know about you, but in my eyes the last line of code looks entirely logical: it first
constructs an SB by passing a String object to the correctly chosen constructor, them remove()
gets rid of an extra " Bean" after which toString() converts the result to a String and assigns it to
str which then gets printed → this one should apparently work… only it doesn’t because
StringBuilder has no remove() → the last LOC is invalid.
Rather confusing, if you ask me. So, when preparing for the exam, I tried to come up with a
single logical rule:
No delete() or insert() in String → they are defined in StringBuilder only → remove() would
be totally redundant in SB because the class already has delete() that takes care of the task.
Or on a lighter note,
Rules for String are mean ’n tough,
Learn by heart this bloody stuff:
No delete() and no insert() –
That’s the way to Java cert.
add() to List to feel no pain,
Use remove() – or clear() its brain.
And remember that replace()
Can explode right in your face:
While in String it overloads,
SB follows other roads.

HTH.

Working with Selected Classe from Java API Chapter II.9 45


Problem 9.23 – C
Given:
final String str = "";
while(str.equals("")) System.out.print(str+1);

What is the result?


A. 1
B. No visible output at all
C. Code compiles but enters endless loop at run time
D. Compilation fails because of an unreachable statement
E. Compilation fails because str+1 creates a new object but str is final
F. Compilation fails because the expression str+1 is illegal

Although it is a fact that something like while(true) may lead to a comperr if the loop is
followed by other statements, which become therefore unreachable, it doesn’t happen in our case
because the evaluation of equals() happens at run time.
The expression str+1 is also valid since the + op is overloaded for String; it simply appends 1
to the already existing string at each iteration, creating another String object – every time anew:
final String str = "";
int a = 0;
while(str.equals("")) {
System.out.println((str+1).hashCode()); // same number over and over again
a++;
if (a > 4) break;
}

As for the final keyword, it is actually irrelevant since the new object never gets assigned to the
original reference – unlike, for example, the following code snippet, which throws a comperr
because str was declared final:
final String str = "";
// System.out.print(str+=1); // INVALID: ’cannot assign a value
// to final variable str’

One more word of caution: Java doesn’t require braces around loop bodies, which not only might
break business logic if the coder isn’t attentive but also can create endless loops when a
semicolon is placed behind, for example, while(smth_that_evaluates_to_true) out of habit:
final String str = "";
while(str.equals(""));
System.out.println(str+1);

Similarly to our Problem 9.23, this code fragment also compiles and runs indefinitely although
without any visible output. What a nasty, well hidden trap… Fortunately, the exam seems not to
abuse semicolons but you should be on your guard just the same.

Problem 9.24 – B
Given:
"a".replace("a","b"); // line 1
"a".replace('a','b'); // line 2
"a".replace(0,"a".length(),"b"); // line 3
"a".replace(new StringBuilder('a'),""); // line 4
"a".replace(new StringBuilder('a'), new StringBuilder("b")); // line 5
new StringBuilder("a").replace("","b"); // line 6
new StringBuilder("a").replace('a','b'); // line 7
new StringBuilder("a").replace(0,1,"b"); // line 8

46 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


How many LOCs fail compilation?
A. Two
B. Three
C. Four
D. Five

The literal "a" is a full-fledged String object → does String have the method replace()? → yes,
it does but there are only two overloaded versions, either of which takes two args → line 3 is
definitely invalid. It would have been fine, though, if it were invoked on a StringBuilder object
because StringBuilder does have replace() that accepts three args: two ints – start and end –
and a String.
What about line 4? It looks mighty odd: the args are of different – and even incompatible
types… Will it compile? To find out what’s going to happen, we need to test our knowledge of
the replace() method in String. Please answer: what are the arguments for replace() in String?
By looking at our code (lines 1 and 2), it is tempting to say: "two Strings and two chars".
Close, very close – but no cigar… because the API actually defines replace(char oldChar, char
newChar) and replace(CharSequence target, CharSequence replacement).
String and StringBuilder both implement the interface CharSequence (we have already met
this when discussing Problem 6.34); this is precisely why we can use Strings as arguments in
str.replace() – and same goes for StringBuilder objects. What’s more, StringBuilder does
define a constructor that accepts a CharSequence → line 4 is valid. By the same token, line 5
also compiles.
Alright, what can be said about line 6? Ah, but this one should be easy by now: StringBuilder
has no replace() that would take two args → line 6 is invalid → line 7 fails compilation, as well.
As for the last LOC, it looks clean: three args of correct types in correct places…
One more thing about replace() that you might find useful on the exam is that the method returns
a reference to the same object if there was no change:
String str = "h";
System.out.println(str == str.replace('Z','a')); // true
System.out.println(str); // h
System.out.println(
str == str.replace(new StringBuilder("Z"), new StringBuilder("a"))); // true
System.out.println(str); // h

Boring, eh? Getting on your nerves already… Alright, let’s play with replace() for the very last
time. Please riddle me this:
Given:
String str = "_";
str = str.replace(new StringBuilder('Z'), new StringBuilder("^"));
System.out.println(str);

What is the result?


Do run this code; it may brighten up your day14…

14
As there’s no StringBuilder constructor that would take a char per se, 'Z' gets widened to int, so new
StringBuilder('Z') creates just an empty StringBuilder with capacity of 90. Effectively, the replace() invocation
reads replace("","^") – and "" matches boundaries of "_" because of the way the regex engine works…
Working with Selected Classe from Java API Chapter II.9 47
Problem 9.25 – A
Given:
public class Dissonance{
public static void main(String[] args) {
Object obj = "Quartet No. 19 in C Major, K. 465"; // line D1
System.out.println(obj.getClass().getSimpleName() + " " + obj); }
}

Is it true that the code prints String Quartet No. 19 in C Major, K. 465?
A. true
B. false

The question strongly hints on the most famous string quartet by Mozart so answering it should
be easy. A bit harder is figuring out why the code compiles and works as intended because we
get used to the idea that employing double quotes as the way to create objects is reserved for
Strings only, from which sort of follows that the reftype must be also String – and this is not so.
As soon as we realize that the double-quoted literal "String" is just a handy replacement 15 for
char string[] = {'S', 't', 'r', 'i', 'n', 'g'};
String str = new String(string);

it becomes clear as day that there’s nothing wrong with line D1.

Problem 9.26 – C
Given the following code fragment:
LocalDate today = LocalDate.of(2016, Month.JUNE, 13);
today.plusHours(24);
System.out.println(today);

What is the result?


A. 2016-06-14
B. 2016-06-13
C. Compilation fails
D. An exception is thrown at run time
LocalDate contains only date → the second stat is invalid.

Problem 9.27 – E
Given:
public static void main(String[] args) {
String date = LocalDate.parse("2016-07-13")
.plusDays(31)
.format(DateTimeFormatter.ISO_DATE_TIME);
System.out.println(date); }

What is the result?


A. 2016-07-13
B. 2016-07-14
C. 2016-07-15
D. Compilation fails
E. An exception is thrown at run time

15
Ref.to the API javadoc's preambule for the class String.

48 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Once again: LocalDate cannot contain time but formatter wants to extract time out of that
object, so the code should apparently misbehave, that much is clear. What’s not so clear is what
it’s gonna throw: a comperr or an RTE?
As a rule of thumb for the exam: improperly applied format() throws an RTE whereas incorrect
invocations of parse() and plus/minusXXX() usually lead to a comperr.

Problem 9.28 – D
Given:
LocalDate ld = LocalDate.of(2016, 6, 13);
ld.plusMonths(6).format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(ld);

What is the result?


A. December 13, 2016
B. June 13, 2015
C. 2016-12-13
D. 2016-06-13

Now all the LOCs are clean, and the code does output the date contained in the object ld – which
is, of course, immutable but we already know that. The only question is what form this date will
be printed in: after all, the code compiles as can be easily deduced from the list of options.
Alright, the API documentation defines the class LocalDate in the following way:
A date without a time-zone in the ISO-8601 calendar system, such as 2007-12-03.
This is it; by default, the date is output as YYYY-MM-DD; notice two mandatory digits for both
months and days. To get something like option A or B, we’d need to call on our LocalDate
object the method format() with an appropriate DateTimeFormatter as its argument…
I wonder what are you going to make out of this little gem?

This is oh-so-praised Kaplan: the software officially endorsed by both Oracle and Pearson Vue.
That’s how those guys propose – quoting – "to prepare you to pass the 1Z0-808 exam". Well
then, be prepared…

Working with Selected Classe from Java API Chapter II.9 49


Problem 9.29 – AD
Which two LOCs fail compilation?
A. LocalDateTime.of(2016,6,13);
B. LocalDate.of(2016, Month.JUNE, 50);
C. LocalDateTime.of(2016,06,13,14,15);
D. LocalDate ld = new LocalDate(2016,6,13);
E. LocalTime.now().format(DateTimeFormatter.ISO_DATE);

Option A needs time (no pun intended) but gets none.


Option B is fine as far as the compiler is concerned although the LOC throws
java.time.DateTimeException: Invalid value for DayOfMonth (valid values 1 - 28/31): 50
Option C is also valid because it provides both components (14 denotes hours and 15, minutes).
As for option D, it’s a trap. We are so used to calling constructors that this LOC appears totally
innocent. But please do remember:
LDTs don’t have public constructors. None of ’em has.
The LDT objects are usually created by invoking static methods such as of(), now() or
parse().
And finally, option E. It does nothing illegal although its desire to format the LocalTime object
with something that also concerns date will be frowned upon by the JVM:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: Year

Problem 9.30 – A
Given:
System.out.println(LocalDate.now().plus(Period.of(0,0,0)));
System.out.println(LocalDate.of(2016, Month.JUNE, 13)
.format(DateTimeFormatter.ISO_LOCAL_DATE));
System.out.println(LocalDate.parse("2016-06-13", DateTimeFormatter.ISO_DATE));

What is the result if the system date is June 13, 2016?


A. 2016-06-13
2016-06-13
2016-06-13
B. Compilation fails.
C. A DateParseException is thrown at runtime.

All three LOCs correctly create their corresponding LocalDate objects. Yes, it is that simple.
And even a simpler version of this question you are going to meet on the exam. Congrats.

Problem 9.31 – AD
Given the full contents of the file JavaBirthday.java:
1 package birthday;
2 import java.time.LocalDate;
3 import java.time.format.DateTimeFormatter;
4

50 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


5 public class JavaBirthday {
6 public static void main(String[] args) {
7 LocalDate birthday = LocalDate.of(1995, Month.MAY, 23);
8 DateTimeFormatter formatter =
9 DateTimeFormatter.ofPattern("MMM dd, YYYY");
10 System.out.println("Java was born on " + birthday.format(formatter));
11 }
12 }

One of the LOCs fails compilation. Which two modifications, used independently, will
make the code print Java was born on May 23, 1995?
A. Replace line 2 with import java.time.*;
B. Replace line 3 with import java.time.format.*;
C. Replace Month.MAY on line 7 with Month.May
D. Replace Month.MAY on line 7 with 05

The LDT classes often borrow things from other classes and even different packages, such as
DateTimeFormatter, which is defined in java.time.format. By using fully qualified names
rather than wildcards in imports, the code can create a situation when something is amiss.
That’s exactly what’s happening here: line 7 invokes the method of(), which takes as its second
arg a constant that is defined in the enum Month, which belongs to java.time. Using a
‛wildcarded’ import stat restores the compilability of the class.
Another way to get rid of the comperr is to use a two-digit int for the desired month instead of
the enum constant.

Problem 9.32 – A
Given the following class definition:
class LangsToLearn {
public static void main(String[] args) {
List<String> langs = new ArrayList<>();
langs.add("Ruby");
langs.add("Perl");
langs.add("Perl");
langs.add("Closure");
if (langs.remove("Perl")) langs.add("Emacs Lisp");
System.out.println(langs);
}
}

What is the result?


A. [Ruby, Perl, Closure, Emacs Lisp]
B. [Ruby, Closure, Emacs Lisp, Emacs Lisp]
C. [Ruby, Closure, Emacs Lisp]
D. Compilation fails

There is no reason for the compilation to fail since all methods are invoked correctly and the
object itself is also created in a valid way. Note, however, that it can contain only Strings. And
don’t forget that unlike StringBuilder, ArrayList defines remove() rather than delete().
Another important thing to keep in mind is that remove() acts on the first match only (compare it
to replace() in String).
This useful functionality is possible because List is an ordered collection. Which can also be
sorted. By the way, what’s the difference between ‛ordered’ and ‛sorted’? This is what the List
API documentation says:
Working with Selected Classe from Java API Chapter II.9 51
public interface List<E> extends Collection<E>
An ordered collection (also known as a sequence). The user of this interface has precise control over
where in the list each element is inserted. The user can access elements by their integer index
(position in the list), and search for elements in the list.
In other words, ‛ordered’ means in practice ‛addressable’ while ‛sorted’ implies that the elements
are physically placed in a certain order, which is imposed by the interface Comparable and is
referred to as ‛natural ordering’. The natural ordering of elements is specific for each class that
implements Comparable. For example, Strings are sorted lexicographically:
List<String> list = new ArrayList<>();
list.add("1"); list.add("03");
list.add("20"); list.add("123");
list.add("ah"); list.add("Zed");
Collections.sort(list);
System.out.println(list); // [03, 1, 123, 20, Zed, ah]

Back to our Problem 9.32; ArrayList’s remove(Object obj) returns true if the list contained
the specified object → "Emacs Lisp" gets added to the list.

Problem 9.33 – AF
Given:
ArrayList<String> someTypes = new ArrayList<>();
someTypes.add("byte");
someTypes.add("long");
someTypes.add("int");
Which two expressions evaluate to 3?
A. someTypes.size();
B. someTypes.capacity();
C. someTypes.length();
D. someTypes.get(2).size;
E. someTypes.get(2).length;
F. someTypes.get(2).length();

ArrayList doesn’t have the method capacity() (which is StringBuilder’s member) although it
defines ensureCapacity(); length() belongs to both String and StringBuilder.
As for the method get(), it returns the element at the specified position, and we then invoke
length() on it because, after all, our ArrayList is generified to String.
Let’s note in passing that option D wouldn’t have compiled even if someTypes were generified
to List and contained three three-element-long Lists because the number of elements in
someTypes must be computed by calling a method rather than by accessing a field.
As for option E, it would have worked, for example, in the following case:
ArrayList someTypes = new ArrayList();
Object obj = new Object();
int[] arrInt = new int[0];
String[] arrStr = {"","",""};
someTypes.add(obj);
someTypes.add(arrInt);
someTypes.add(arrStr);
System.out.println( ((String[])someTypes.get(2)).length ); // 3

52 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.34 – E
Given the following code fragment:
ArrayList<Integer> list = new ArrayList(); // a1
list.add(1); // a2
System.out.println(list.get(list.size())); // a3

What is the result?


A. 1
B. Compilation fails on line a1
C. Compilation fails on line a2
D. Compilation fails on line a3
E. An IndexOutOfBoundsException is thrown at run time

Even though the right-hand side of the list-creating LOC is missing angle brackets, it’s OK
because the compiler can infer our intentions.
As type safety via generics is provided at compile time, the compiler looks at the reftype only
and disregards the diamond op on the right:
List list1 = new ArrayList(); // accepts anything
List list2 = new ArrayList<>(); // ditto
List list3 = new ArrayList<String>(); // ditto

On the other hand, the diamond on the left may not be empty → otherwise a comperr:
// List<> list4 = new ArrayList(); // INVALID
// List<> list5 = new ArrayList<>(); // INVALID
// List<> list6 = new ArrayList<String>(); // INVALID

List<String> list7 = new ArrayList(); // accepts Strings only


// list7.add(new Object()); // INVALID
// list7.add(1); // INVALID
list7.add("");
list7.add(null);
List<String> list8 = new ArrayList<>(); // accepts Strings only
List<String> list9 = new ArrayList<String>(); // ditto

All in all, option B is incorrect as line a1 is valid.


Line a2 is also fine as primitives get autoboxed because List works with reference types only.
(Reminder: using something like list.add((byte)1); at line a2 would have thrown a comperr
since the compiler would have autoboxed byte to Byte, and then what? Byte can’t be converted
to Integer implicitly…)
Now to option D; both methods are invoked correctly but list.get(1) will definitely throw an
RTE as it wants to look at the second element while list has only one.

Problem 9.35 – B
Given:
class TestingArrayList {
public static void main (String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 5; i++) list.add("" + i);
System.out.println(list.remove(list.indexOf("4")));
}
}

Working with Selected Classe from Java API Chapter II.9 53


What is the result?
A. true
B. 4
C. [0, 1, 2, 3, 4]
D. Compilation fails

The invocation list.add("" + i) works correctly because our list is generified to String and
the op + is overloaded for Strings. The methods indexOf() and remove() are also called in valid
ways → option D is out.
remove() receives an int whose value is 4 (since elements are enumerated starting with zero) →
remove(int index) strips list of the element at the specified position and returns it (the element,
that is) → the code prints 4.
In short, it is important to remember that remove(int index) returns what was taken out from the
List and not, for example, a boolean as if to say ‛Alright boss, I successfully did what you have
requested’. Because it doesn’t need to: it either removes an element or reports a failure by
throwing an IOOBE, that’s all. On the contrary, the overloaded version of the method, namely
remove(Object obj), does return a boolean…
Please also note what kind of loop was used to populate the list. It may be tempting to employ an
enhanced for, like this:
List<String> list = new ArrayList<>();
int i = 0;
while(i<5)
for (String e : list) list.add("" + i++);
System.out.println(list.remove(list.indexOf("4")));

but it won’t work: list is still empty, there’s no elements to iterate over → for won’t run, and the
code will enter an endless loop because the loop var i has no chance to increment…

Problem 9.36 – B
Given:
public class MutatisMutandis {
public static void main(String[] args) {
List list = new ArrayList();
list.add(new StringBuilder(""));
list.add("");
for (Object e : list )
if (e instanceof StringBuilder) ((StringBuilder)e).append("OK");
else ((String)e).concat("OK");
System.out.println(list);
}
}

What is the result?


A. [OK, OK]
B. [OK, ]
C. Compilations fails
D. A RuntimeException is thrown

As list isn’t generified, it accepts any object. Casts ensure that the code may call methods
specific for either StringBuilder or String. And finally, since String is immutable, invoking the
method concat() doesn’t affect the original String object, which remains empty.

54 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.37 – A
Given:
class Birdies{
public static void main(String[] args) {
List aviary = new ArrayList<>(); // line b1
aviary.add("kinglet");
aviary.add("finch");
aviary.add("titmouse");
aviary.add(aviary.set(0,"jay")); // line b2
System.out.println(aviary);
}
}

What is the result?


A. [jay, finch, titmouse, kinglet]
B. [jay, finch, titmouse, true]
C. Compilation fails on line b1
D. Compilation fails on line b2

Using an empty diamond in the right-hand side of the stat on line b1 doesn’t affect code’s
compilability, so aviary gets successfully populated with virtual birds whose reftype is Object
and the actype String. Line b2 is valid, as well; it replaces the first element with String "jay",
and since the method set() returns what was replaced, add() appends "kinglet" to the list.

Problem 9.38 – C
Given:
class Sweet16 {
public static void main(String[] args) {
List<Integer> ages = new ArrayList<>();
ages.add(16); // line s1
ages.add(null);
for (int i = 0; i < ages.size(); i++) System.out.print(ages.get(i));
for (int i : ages) System.out.println(i);
}
}

What is the result?


A. 16null16
B. 16null16null
C. 16null16 and a NullPointerException
D. Compilation fails

List autoboxes primitive args, so line s1 actually appends an Integer. Adding null to ages isn’t
problematic, either. What happens next, however, is: the first for loop behaves itself but the
enhanced for throws an NPE. Let’s see why.
As get(i) returns an Integer, the printing stat receives what Integer’s toString() returns → the
first for outputs 16null. The enhanced for successfully unboxes the first element and assigns it
to a primitive, but a similar attempt with null fails. Replacing int with a compatible reference
type would have cleared up the problem.
Conclusion: using a primitive loop var in an enhanced for can lead to an NPE when iterating
over a List → always make sure that the loop var is suitable for the task.

Working with Selected Classe from Java API Chapter II.9 55


Problem 9.39 – C
Given the following class definitions:
class Examinee {
private String name;
private int score;

public Examinee(String name, int score) {


this.name = name;
this.score = score;
}
public String getName() { return name; }
public int getScore() { return score; }
}

class ReleasingResults{
public static void checkScore(List<Examinee> list, Predicate<Examinee> p){
for (Examinee e : list) {
if (p.test(e)) {
System.out.print(e.getName() + ", ");
}
}
}

public static void main(String[] args) {


List<Examinee> list = Arrays.asList(new Examinee("Alice", 98),
new Examinee("Bob", 48),
new Examinee("Charlie", 62),
new Examinee("Doug", 88));
System.out.print("Passed: ");

// line r1

}
}

Which LOC, when inserted at line r1, enables the code to print Passed: Alice, Doug,?
A. checkScore(list, () -> e.getScore() > 65);
B. checkScore(list, Examinee e -> e.getScore() > 65);
C. checkScore(list, e -> e.getScore() > 65);
D. checkScore(list, (Examinee e) -> { e.getScore() > 65; });

The Problem looks rather demanding but, in fact, lambda-related questions are arguably among
the easiest ones on the exam. As always, we start our analysis by glancing at the list of available
options, and a bunch of lambda expressions immediately indicates what the question is about.
The exam requires us to work with predicative lambdas; we just need to make sure if this is the
case; the checkScore() method’s signature confirms it.
Since the interface Predicate’s test() method takes a single arg, option A is out. Option B is also
invalid because the explicit use of the parameter type requires parentheses.
Option D fails compilation because semicolon, braces and return should be used together 16 –
but return is missing.

16
One more time: please keep in mind that this rule is applicable only on our exam where we are supposed to deal
with predicative lambdas. The interface Predicate’s test() returns a boolean → hence return is mandatory → but
when the functional method is void, the Semirebra rule won’t work.

56 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Problem 9.40 – BC
Let sb refer to a StringBuilder object. Which of the following fail(s) compilation?
A. sb -> sb.toString()
B. StringBuilder sb -> sb.toString()
C. (StringBuilder sb) -> return sb.length();
D. (StringBuilder sb) -> { return sb.length(); }

The question hints that the list of options may contain more than one invalid LOC so we’ll be
needing to check every option. All four cases indicate that the lambda method takes a single arg
of type StringBuilder and returns either a String or an int – and this info is enough to start the
analysis.
Option A: the formal parameter has no explicit data type but this is OK; the method body
contains a single String-returning stat so braces, semicolon and return aren’t necessary →
option A looks perfectly compilable.
What about option B? While the method body appears to be correct, the parameter list is missing
parentheses, which are now mandatory because of the explicitly stated data type.
Option C is also invalid since it is omitting braces; option D, on the other hand, dutifully follows
all the rules: the parentheses around the paramlist are in place, and the method body is written in
its full form, with braces, return and semicolon → only options B and C fail compilation.
Let’s see if our conclusion is indeed correct:
interface Lambdable1{ String run(StringBuilder sb); }
interface Lambdable2{ int run(StringBuilder sb); }
class Test{
static void test1(Lambdable1 l){
System.out.println(l.run(new StringBuilder("lambda")));
}
static void test2(Lambdable2 l){
System.out.println(l.run(new StringBuilder("lambda")));
}
public static void main(String[] args) {
test1( sb -> sb.toString() ); // lambda
// test1( StringBuilder sb -> sb.toString() ); // INVALID
// test2( (StringBuilder sb) -> return sb.length() ); // INVALID
test2( (StringBuilder sb) -> { return sb.length(); } ); // 6
}
}

Problem 9.41 – AE
Given:
class Test {
String check(List list, Predicate p){ // line t1
return p.test(list)? "Empty" : "Populated";
}
void run() {
ArrayList list = new ArrayList(); // line t2
System.out.println(
check(list, list -> list.isEmpty())); // line t3
}
public static void main(String[] args) {
new Test().run();
}
}

Working with Selected Classe from Java API Chapter II.9 57


Which two options can make the code compile and run successfully?
A. Replace line t3 with check(list, myList -> list.isEmpty()));

B. Replace line t2 with List list = new ArrayList();


and replace line t3 with check(list, myList -> myList.isEmpty()));
C. Replace line t1 with String check(List list, Predicate<ArrayList> p){
and line t3 with check(list, myList -> myList.isEmpty()));

D. Replace line t1 with String check(ArrayList list, Predicate<ArrayList> p){


line t2 with List mist = new ArrayList();
and line t3 with check(mist, list -> list.isEmpty()));
E. Replace line t1 with String check(List list, Predicate<List> p){
and line t3 with check(list, myList -> myList.isEmpty()));

First of all, we need to see why the original code doesn’t compile. All options mention line t3; is
this LOC problematic? Indeed, it is: its paramlist clashes with the already declared variable list.
Renaming the parameter saves the day → option A (incidentally, it completely disregards the
functional method's argument and accesses list directly, then prints Empty) is in.
What about option B? It changes the object’s reftype to a wider one but how can this help when
myList is passed to test() that sees it as an Object only? After all, Object has no isEmpty()
method…
All the other options hint that there may be something wrong with the compatibility of the data
types in the signature of the check() method and its invocation.
Why? Because line t1 specifies ungenerified List and Predicate → they will accept any object
→ expect illegal implicit downcasts and CCEs at run time.
We can use the following rule of thumb:
A predicative lambda? Check its type first! Object, Predicate and the formal parameter are ideally
should be of the same type; no sub/superclasses combos for Predicate and the parameter.
Let’s see how the rule works in practice; we’ll start with something simpler: will this print true?
class Test{
public static boolean checkList(List list, Predicate<List> p){
return p.test(list); // line X
}
public static void main(String[] args) {
boolean boo = checkList(new ArrayList(), (ArrayList al) -> al.isEmpty());
System.out.println(boo);
}
}

The answer is ‛No’ because the code fails compilation. Reason: Predicate is generified to List
→ Predicate’s test() expects List → but checkList() offers ArrayList al → won’t work; after
all, lambda expression’s ultimate raison d’être is to override the functional method…
Very well; what if we change Predicate<List> to Predicate<ArrayList>? Now lambda’s body
does override the method test() but the code still won’t compile since the invocation
p.test(list) specifies an arg of type List → we have an implicit downcast from List to
ArrayList on line X, which is illegal. On the other hand, an explicit cast such as
p.test(<ArrayList>list) works, and the code prints true.
Re-capping: Predicate<T> and paramlist (T param) must be of the same type T and the object
must be assignable to that type (or use a cast).

58 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Please also note that removing <> from Predicate<> means that we will have to remove type
from the paramlist, too – and that automatically makes Predicate of Object – which doesn’t
have isEmpty() method, so we’ll be needing something that returns a boolean; for example:
class Test{
public static boolean checkList(List list, Predicate p){
return p.test(list);
}
public static void main(String[] args) {
boolean boo = checkList(new ArrayList(), al -> al instanceof List ); //true
System.out.println(boo);
}
}

Now we can get back to our Problem 9.41; option C makes test() expect an ArrayList but
delivers a List → which cannot be converted to ArrayList implicitly → a comperr. Doing the
same thing with a cast in a strategic place would have helped, though:
String check(List list, Predicate<ArrayList> p){
return p.test((ArrayList)list)? "Empty" : "Populated"; }

Option D resolves the conflict of types between the check() method’s signature and the test()
method’s invocation; however, the fact that this option also changes the object’s reftype on line
t2 to List leads to the same problem: an illegal implicit downcast in the check() method’s
invocation. Casting mist would have cleared the problem:
check((ArrayList)mist, list -> list.isEmpty()));

Option E finally restores balance: the signature of check() specifies a List for both its args, and
the object created on line t2 is of type ArrayList, which IS-A List…

Problem 9.42 – D
Given:
class Suspect {
private String name;
private boolean statement;

public Suspect (String name) {


this.name = name;
this.statement = Math.random() < 0.5 ? false : true;
}

public boolean getStatement() { return statement; }


public String getName() { return name; }
}

class Interrogation {
private static void interrogate(List<Suspect> perps){
for(Suspect e : perps)
if (e.getStatement() != true)
System.out.println(e.getName() + " is lying!");
}
public static void main(String[] args) {
List<Suspect> roundUp = new ArrayList();
roundUp.add(new Suspect("Alice"));
roundUp.add(new Suspect("Bob"));
roundUp.add(new Suspect("Charlie"));
roundUp.add(new Suspect("Doug"));
roundUp.add(new Suspect("Eugine"));
roundUp.add(new Suspect("Frances"));

interrogate(roundUp);
}
}

Working with Selected Classe from Java API Chapter II.9 59


Which modification will achieve the same result?
A. Overload the method interrogate() with the following code fragment:
private static void interrogate(List<Suspect> perps, Predicate p){
for(Suspect s : perps)
if(!p.test(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with the following LOC:


interrogate(roundUp, perps -> perps.getStatement());

B. Overload the method interrogate() with the following code fragment:


private static void interrogate(List perps, Predicate<Suspect> p){
for(Suspect s : perps)
if(!p.test(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with the following LOC:


interrogate(roundUp, perps -> perps.getStatement());

C. Add the following interface:


interface LieDetector {
default boolean test(Suspect s){ return s.getStatement(); }
}

then overload the method interrogate() with the following code fragment:
private static void interrogate(List<Suspect> perps, LieDetector ld){
for(Suspect s : perps)
if(!ld.test(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with the following LOC:


interrogate(roundUp, perps -> perps.getStatement());

D. Add the following interface:


interface LieDetector { boolean analyze(Suspect s); }

then overload the method interrogate() with the following code fragment:
private static void interrogate(List<Suspect> perps, LieDetector ld){
for(Suspect s : perps)
if(!ld.analyze(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with the following LOC:


interrogate(roundUp, perps -> perps.getStatement());

As the available options make use of not only predicative lambdas but also lambdas in general,
you will not meet such a question on the exam; practicing with fundamental principles, however,
can be beneficial, so let’s do it unhurriedly and methodically.
To have a lambda, we’ll be needing a functional interface, in other words, an interface with a
single abstract method. Although this handy definition isn’t entirely correct – as you’ll see in the
very next Problem 9.43 – it’s good enough in practice.

60 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


What else do we need? Obviously, a properly written lambda expression (LE). An LE is made up
of three basic components:

① A comma-separated list of formal parameters enclosed in parentheses…


Reminder: We can omit the LE params’ data types – and also get rid of the
parentheses altogether if there is only one param.

② … the arrow token, ->

③ … and a body, which can consist of a single expression or a statement block.


Reminder: Single expression doesn’t require braces REGARDLESS of whether the
method is void or not.
Also let’s not forget that return in a lambda expression can’t live without its pals Semicolon
and the Braces brothers.
In short, all of the following can work if the functional method is void, and the last LOC is also
valid for a functional method that returns a String:
m1(arg, s -> { System.out.println(s); } );
m2(arg, s -> System.out.println(s) );
m3(arg, s -> s += 1 );

Example 1:
interface Lambdable{
void doStuff(String str);
}
interface AnotherLambdable{
String doStuff(String str);
}

class Test {
static String str = "hello";
static void run1(String str, Lambdable l){
l.doStuff(str);
}
static String run2(String str, AnotherLambdable al){
return al.doStuff(str);
}

public static void main(String[] args) {


run1(str, p -> System.out.println(p) ); // hello
run1(str, p -> { System.out.println(p); } ); // hello
run1(str, p -> { p += 1; System.out.println(p); } ); // hello1
// run1(str, p -> {return p;}); // INVALID
run1(str, p -> {return;});
System.out.println(run2(str, p -> { return p + "2"; } )); // hello2
System.out.println(run2(str, p -> p + "2" )); // hello2
}
}

In Example 1 we defined our own functional interfaces; one of them, Lambdable, has a void
method → no invocation of run1() may mention return that actually returns something; the
fourth, invalid invocation would have worked if run1() were replaced with run2().
Time to play with the interface Predicate. Coming from the field of linguistics, I couldn’t at first
get the whole notion through my skull because to me a predicate meant either a verb or a verb
phrase. For example, in the sentence ‛It doesn’t compute’ the predicate is ‛doesn’t compute’, and
in ‛Lambdas are weird’ the predicate is ‛are weird’. And how exactly can it help to conquer those
LEs? As for the attempt to get enlightened by asking Wiki, it only made my head spin…

Working with Selected Classe from Java API Chapter II.9 61


The real breakthrough came after I had found a short, workable definition of predicate in the
Dictionary of Logic by Nikolay Kondakov 17; basically it says that "…a predicate is an utterance
that affirms or negates something about an object… It reflects presence or absence of a certain
feature… In mathematical logic, the predicate is a logical function that is defined for a specific
task and whose value can be either true or false".
And that was it. From this definition it immediately follows that 1) predicate needs an object,
and 2) it returns a boolean. Exactly as it is with the method boolean test(T t) defined in the
interface java.util.function.Predicate… Everything fell into place.
Example 2 (with Predicate):
class Panda {
int age;
public static void main(String[] args) {
Panda pa = new Panda();
pa.age = 1;
check(pa, p -> p.age < 5); // simplified form
check(pa, (Panda p) -> {return p.age < 5;}); // full form
// check(pa, p -> {p.age < 5}); // missing ; and return
// check(pa, p -> {p.age < 5;}); // missing return
}
static void check(Panda panda, java.util.function.Predicate<Panda> pred) {
String result = pred.test(panda) ? "younger" : "older";
System.out.println(result);
}
}

Getting back to our Problem. Option A suggests to overload the method interrogate() with:
private static void interrogate(List<Suspect> perps, Predicate p){
for(Suspect s : perps)
if(!p.test(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with:


interrogate(roundUp, perps -> perps.getStatement());

The code compilability analysis on the exam should start with the verification of the lambda
method body followed by signature check. Yes, in this order because the exam question will
most likely test you on the correctness of the lambda expression rather than the compatibility of
the involved objects.

Verifying the lambda expression:


Step 1. Since we are overriding test() in Predicate, a single formal parameter is
mandatory:
– is it in place?
– does it have its type specified?
if ‛yes’, the paramlist must be enclosed in parentheses;
if ‛no’, parentheses are optional;
– what about the param’s name? does it clash with any of the previously
declared vars that are still in scope?
Step 2. Is the lambda token in place?

17
Not available in English; there’s a German translation, though: Wörterbuch der Logik von N.I.Kondakow. The
book is awesome, it helped me untold number of times…

62 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


Step 3. test() in Predicate is supposed to return a boolean, therefore:
– does the method body specify a single statement?
if ‛yes’, does it use return?
if ‛yes’, it must end with a semicolon and be enclosed in braces;
if ‛no’, the body must be ‛naked’ (neither braces nor semicolon);
if ‛no’, the body must be written in a full form, with braces and semicolons.
– does it indeed return a boolean?
Step 4. See if the same lambda expression is used in other options. For example, in our
current case (Problem 9.42) it is → since the expression is valid, we don’t have to
bother ourselves with validating it anymore.

Verifying the signature:


Use this rule: If the object, predicate and formal parameter are of the same data type → OK
If they aren’t… (sigh) well, expect all kinds of trouble.
Let’s see what we’ve got:
private static void interrogate(List<Suspect> perps, Predicate p){

The signature specifies an ungenerified Predicate → as the result, the method test() sees only an
Object instead of the promised Suspect → Object has no getStatement() method → a comperr.
Now to option B; it wants us to overload the method interrogate() with the following:
private static void interrogate(List perps, Predicate<Suspect> p){
for(Suspect s : perps)
if(!p.test(s))
System.out.println(s.getName() + " is lying");
}

and use the same method invocation as in option A (which we have already ascertained as being
valid) → skipping the lambda expression verification → applying signature verification rule →
Predicate is generified to Suspect whereas the object perps’ reftype is an ungenerified List →
but the enhanced for will want to use perps’ elements as Suspects rather than Objects → a
comperr because of an implicit downcast from Object to Suspect, which is illegal.
If we only had a carte blanche, we still could, theoretically speaking, save the day by making the
enhanced for to iterate over Objects rather than Suspects and then apply a couple of casts in
strategic places, like this:
private static void interrogate(List perps, Predicate<Suspect> p){
for(Object s : perps) // line X
if(!p.test((Suspect)s)) // XX
System.out.println(((Suspect)s).getName() + " is lying"); // XXX
}

Line X gets rid of the comperr that reads ‛incompatible types: Object cannot be converted to
Suspect’; the cast on line XX gives the method test() what it wants; and the cast on line XXX
allows to invoke getName(). Option B, however, isn’t that flexible so we mark it as incorrect.
Now, option C. Ah, but this is fun! We get to create our own interface that should mimic
Predicate in java.util.function:
interface LieDetector {
default boolean test(Suspect s){ return s.getStatement(); }
}

Wait a minute… How come the method test() in LieDetector is declared as default?! it must
be abstract! No, this won’t do: our brand new interface isn’t functional → option C isn’t what
we need, either…

Working with Selected Classe from Java API Chapter II.9 63


During the initial pass, we stop our analysis at this point because we have arrived at the correct
answer by the process of elimination. The Review stage, however, is different: we will have to
verify our conclusion by checking option D, too.
Alright, so we add a new interface:
interface LieDetector { boolean analyze(Suspect s); }

then overload the method interrogate() with the following:


private static void interrogate(List<Suspect> perps, LieDetector ld){
for(Suspect s : perps)
if(!ld.analyze(s))
System.out.println(s.getName() + " is lying");
}

and replace the call to interrogate() with this:


interrogate(roundUp, perps -> perps.getStatement());

As we saw when analyzing option A, the invocation is valid. The interface is indeed functional:
it declares a single abstract method. The signature, however, looks suspicious because
LieDetector isn’t generified… Hmm… what could that mean?.. Ah! unlike test() in Predicate,
the method analyze() declares that it will accept only objects of type Suspect → this is a perfect
match with List<Suspect> → the enhanced for is valid → this option is indeed correct.
Now, what’s the story with Predicate’s test() and how it differs from our analyze()? Compare
the definitions:
interface Predicate<T> { boolean test(T t); /* plus four other non-abstract methods */ }
interface LieDetector { boolean analyze(Suspect s); }

In its current form, our LieDetector cannot be generified because <T> is missing; that’s why the
method analyze() was specifically tailored to Suspect. After making LieDetector generifiable,
we could use the already familiar idiom with the generified List and LieDetector in the method's
signature :
interface LieDetector<T> { boolean analyze(T t); }
class Interrogation {
// other necessary LOCs
private static void interrogate(List<Suspect> perps, LieDetector<Suspect> ld){
// enhanced for, printing stat, etc.
}

Problem 9.43 – E
Which one is true?
A. Functional interface may not contain more than one method.
B. Any interface that has a single abstract method is therefore functional.
C. Functional interface cannot have superinterfaces.
D. Functional interface cannot be extended.
E. None of the above.

64 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


The following code answers the question by illustrating how available options work:
interface Inter{}
interface Interable extends Inter{
void walk();
int run(StringBuilder sb);
}

@FunctionalInterface
interface Lambdable extends Interable{
default void walk(){}; // must override super’s walk to make it non-abstract;
// int run(); // when uncommented, makes Lambdable non-functional
boolean equals(Object obj);
}

@FunctionalInterface
interface Omegable extends Lambdable{}

class Test{
static void test(Lambdable l){
System.out.println(l.run(new StringBuilder("lambda")));
}
static void protest(Omegable o){
System.out.println(o.run(new StringBuilder("omega")));
}
public static void main(String[] args) {
test(sb -> sb.length()); // prints 6
protest(sb -> { sb.delete(0, sb.length()); // 5
return sb.append("alpha").length();
});
}
}

The program has two functional interfaces, namely Lambdable and its child, Omegable →
options C and D are incorrect.
Option A is obviously incorrect as Lambdable (and, therefore, Omegable) has three methods
(default walk() plus abstract equals() plus inherited abstract run(StringBuilder sb)), yet it
works as intended (just look at the @FunctionalInterface annotations to which the compiler
doesn’t object) → options A and B are also incorrect…
We were taught that
Conceptually, a functional interface has exactly one abstract method 18
which is a bit disconcerting as Lambdable has two abstract methods. As usual, to understand
what the heck is going on, we have to turn to the JLS (§9.8, Functional Interfaces):

The definition of functional interface excludes methods in an interface that are also public methods in Object.
This is to allow functional treatment of an interface like java.util.Comparator<T> that declares multiple abstract
methods of which only one is really "new" - int compare(T,T). The other method - boolean equals(Object) - is an
explicit declaration of an abstract method that would otherwise be implicitly declared, and will be automatically
implemented by every class that implements the interface.

So for an interface to define an abstract method that has its public namesake in Object
doesn't count toward being functional.
Well, basically this is it for lambdas. Since our book is also at its end, how about adding a couple
of extra touches to the discussion? and then we’ll call it quits…
Consider the following program, which tests certain animal species for their ability to swim, hop
or fly 19:

18
https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html
19
You can find its listing without line numbers in Appendix C.
Working with Selected Classe from Java API Chapter II.9 65
1 package org.xlator;
2 import java.util.ArrayList;
3 import java.util.List;
4 import java.util.function.Predicate;
5
6 class Animal{
7 private String species;
8 private boolean canHop;
9 private boolean canSwim;
10 private boolean canFly;
11 boolean getHop() { return canHop; }
12 boolean getSwim(){ return canSwim; }
13 boolean getFly() { return canFly; }
14
15 public Animal(String species, boolean canHop, boolean canSwim, boolean canFly){
16 this.species = species;
17 this.canHop = canHop;
18 this.canSwim = canSwim;
19 this.canFly = canFly; }
20
21 @Override
22 public String toString(){ return species; }
23 }
24
25 @FunctionalInterface
26 interface CheckTrait{ boolean test(Animal a); }
27
28 class TestHopper implements CheckTrait{
29 public boolean test(Animal a){ return a.getHop(); }
30 }
31
32 public class Filter {
33
34 public static void main(String[] args) {
35 List<Animal> animals = new ArrayList<>();
36 // swimmer hopper flier
37 animals.add(new Animal("fish", false, true, true ));
38 animals.add(new Animal("kangaroo", true, false, false ));
39 animals.add(new Animal("cat", true, false, false ));
40 animals.add(new Animal("dog", true, true, false ));
41 animals.add(new Animal("bird", true, true, true ));
42 animals.add(new Animal("turtle", false, true, false ));
43 animals.add(new Animal("rabbit", true, false, false ));
44 animals.add(new Animal("ladybug", false, false, true ));
45
46 Predicate<Animal> hop = a -> a.getHop();
47 Predicate<Animal> swim = a -> a.getSwim();
48 Predicate<Animal> fly = a -> a.getFly();
49
50 System.out.println("Can hop (old school):\n--------");
51 filterOldWay(animals, new TestHopper());
52
53 System.out.println("\nCan swim (with lambdas):\n--------");
54 filterNewWay(animals, a -> a.getSwim());
55 // filterNewWay(animals, swim); // more compact
56
57 System.out.println("\nCan fly (with .stream):\n--------");
58 animals.stream().filter(fly).forEach(a -> System.out.println(a));
59
60 System.out.println("\nCan both hop and fly (complex filter):\n--------");
61 animals.stream().filter(a -> hop.and(fly).test(a))
62 .forEach(a -> System.out.println(a));
63 }
64
65 static void filterOldWay(List<Animal> animals, CheckTrait checker){
66 for (Animal a : animals){
67 if(checker.test(a))
68 System.out.println(a); }
69 }
70
71 static void filterNewWay(List<Animal> animals, Predicate<Animal> checker){
72 animals.stream().filter(a -> checker.test(a))
73 .forEach(a -> System.out.println(a)); }
74 }

66 NAILING 1Z0-808: Practical Guide to Oracle Java SE8 Programmer I Certification


And this is what the code outputs:
Can hop (old school):
--------
kangaroo
cat
dog
bird
rabbit

Can swim (with lambdas):


--------
fish
dog
bird
turtle

Can fly (with .stream):


--------
fish
bird
ladybug

Can both hop and fly (complex filter):


--------
bird

Several approaches are being used to check the traits: the ability to hop is tested in the old-school
fashion, so to speak, by explicitly creating an object that has a getter method that returns a
boolean; then we use a lambda expression to check animals for their ability to swim; note that it
can take two forms: we either write the LE directly on the LOC with the method invocation (line
54), or use the Predicate<Animal> var that holds the appropriate LE (the commented-out line
55). The two last checks (for the ability to fly and, after that, the ability to both fly and hop)
demonstrate the use of streams and complex, multi-stage filters, which are possible thanks to the
additional methods that the interface Predicate defines.
For example, replacing line 61 with the following:
animals.stream().filter(a -> hop.or(fly).test(a))

would have selected only those animals that can either hop or fly (i.e., fish, kangaroo, cat, dog,
bird, rabbit, and ladybug), while this LOC
animals.stream().filter(a -> hop.and(fly.negate()).test(a))

would have chosen those who can hop but are unable to fly (namely, kangaroo, cat, dog, and
rabbit). This is where our decision to assign the LEs to separately declared Predicate variables
comes in handy as the code becomes less cluttered and, therefore, more readable and
maintainable…

FREE SAMPLE ENDS HERE


get whole book: www.igor.host

Working with Selected Classe from Java API Chapter II.9 67

You might also like