From f32982255044a7883bbd801987d61a84dd0c0a16 Mon Sep 17 00:00:00 2001 From: Esteban Herrera Date: Wed, 18 May 2016 18:59:36 -0500 Subject: [PATCH] Added some topics to Appendix 1. --- ch31.html | 420 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 364 insertions(+), 56 deletions(-) diff --git a/ch31.html b/ch31.html index df4ee8a..73ba43d 100644 --- a/ch31.html +++ b/ch31.html @@ -2,71 +2,379 @@ - - - - Java 8 Programmer II Study Guide: Exam 1Z0-809 - - - - - - - + + + + Java 8 Programmer II Study Guide: Exam 1Z0-809 + + + + + + + - + + +
+
+
-
-
-
- -

Appendix A
+

Appendix A
From Java 6/7 to Java 8

-


+


-

Exam Objectives

+

Exam Objectives

-

Develop code that uses Java SE 8 collection improvements, including Collection.removeIf(), List.replaceAll(), Map.computeIfAbsent(), and Map.computeIfPresent() methods.
Develop code that uses String objects in the switch statement, binary literals, and numeric literals, including underscores in literals.
Use Lock, ReadWriteLock, and ReentrantLock classes in the java.util.concurrent.locks.
Format dates, numbers, and currency values for localization with the NumberFormat and DateFormat classes, including number and date format patterns.
Recursively access a directory tree by using the DirectoryStream and FileVisitor interfaces
Find a file by using the PathMatcher interface.
Observe the changes in a directory by using the WatchService interface.

+

Develop code that uses Java SE 8 collection improvements, including Collection.removeIf(), List.replaceAll(), Map.computeIfAbsent(), and Map.computeIfPresent() methods.
Develop code that uses String objects in the switch statement, binary literals, and numeric literals, including underscores in literals.
Use Lock, ReadWriteLock, and ReentrantLock classes in the java.util.concurrent.locks.
Format dates, numbers, and currency values for localization with the NumberFormat and DateFormat classes, including number and date format patterns.
Recursively access a directory tree by using the DirectoryStream and FileVisitor interfaces
Find a file by using the PathMatcher interface.
Observe the changes in a directory by using the WatchService interface.

-
-
- - - -
- -
- - -

Soon...

- - - - - -
- - - -
-
- - - +
+
+ + + +
+ +
+ + +

New Methods on Collections

+

Java 8 brings some new helper methods for Collections to write less verbose code.

+ +

The first one is forEach() (we talked about it earlier):

+ +

default void forEach(Consumer<? super T> action)

+ +

That calls the accept() method on each element of the collection. So instead of having something like:

+ +

for(int i = 0; i < list.size(); i++) {
+     System.out.println(list.get(i));
+ }

+ +

Or:

+ +

for(String s : list) {
+     System.out.println(s);
+ }

+ +

Now we can have it as (without creating a stream):

+ +

list.forEach(System.out::println);

+ +

Another one is removeif():

+ +

default boolean removeIf(Predicate<? super E> filter)

+ +

That iterates over the elements of the collection and removes an element if it matches the given predicate (if the implementation of the Collection doesn't support removal, an UnsupportedOperationException is thrown). So instead of having something like:

+ +

Iterator<String> it = list.iterator();
+ while (it.hasNext()) {
+     String s = it.next();
+     if(s != null && s.length() < 3) {
+         it.remove();
+     }
+ }

+ +

Now we can have just:

+ +

list.removeIf( s -> s != null && s.length() < 3 );

+ +

We also have replaceAll():

+ +

default void replaceAll(UnaryOperator<E> operator)

+ +

That replaces each element of this list with the result of applying the operator to the element. So instead of having something like:

+ +

Iterator<String> it = list.iterator();
+ while (it.hasNext()) {
+     String s = it.next();
+     it.set(s.toUpperCase());
+ }

+ +

Now we just have:

+ +

list.replaceAll(s -> s.toUpperCase());

+ + +

New Methods on Maps

+

Java 8 also brings new helper methods to Maps. There's two interesting methods in particular.

+ +

One is computeIfAbsent():

+ +

default V computeIfAbsent(
+         K key,
+         Function<? super K,? extends V> mappingFunction)

+ +

This method calculates the value of the given key, and adds it to the map only if:

+ +
    +
  • The key is not already in the map
  • + +
  • The key has a null value associated
  • + +
  • If the calculated value is different than null
  • +
+ +

For example:

+ +

Map<String, String> letters = new HashMap<>();
+ letters.put("a", "a");
+ letters.put("b", null);
+
+ Function<String, String> func = k -> {
+     if(k.startsWith("d")) return null;
+     return k.toUpperCase();
+ };
+
+ // Won't update,already in map

+ letters.computeIfAbsent("a", func);
+ // Will update
 letters.computeIfAbsent("b", func);
+ // Will add
+ letters.computeIfAbsent("c", func);
+ // Won't add
+ letters.computeIfAbsent("d", func);
+ // Yes, there's also a forEach in Maps
+ letters.forEach( (key, value) ->
+     System.out.format("%s-%s;", key, value)
+ );

+ +

The output:

+ +

a-a;b-B;c-C;

+ +

The other method is computeIfPresent():

+ +

default V computeIfPresent(
+         K key,
+         BiFunction<? super K,? super V,? extends V> remappingFunction)

+ +

This method updates the value of a given key only if:

+ +
    +
  • The key is already in the map
  • + +
  • The key has a non-null value associated and the function also returns a non-null value
  • +
+ +

If the key has a non-null associated and the function returns null, the key is removed from the map. For example:

+ +

Map<String, String> letters = new HashMap<>();
+ letters.put("a", "a");
+ letters.put("b", null);
+ letters.put("d", "d");
+
+ BiFunction<String, String, String> func = (k, v) -> {
+     if(k.startsWith("d")) return null;
+     return k.toUpperCase();
+ };
+
+ // Will update
+ letters.computeIfPresent("a", func);
+ // Won't update 
+ letters.computeIfPresent("b", func);
+ // Won't add 
+ letters.computeIfPresent("c", func);  
+ // Will remove
+ letters.computeIfPresent("d", func);  
+ letters.forEach( (key, value) ->
+     System.out.format("%s-%s;", key, value)
+ );

+ +

In this case, the output will be:

+ +

a-A;b-null;

+ + +

Switch statement

+

A switch statement is another way to represent an if-else statement. This is its syntax:

+

switch(expression) {
+    case constant_value_1:
+       statements;
+    case constant_value_2:
+       statements;
+    default:
+       statements;
+ }

+ +

The switch expression must evaluate to one of the following types:

+
    +
  • byte, short, char, int
  • +
  • enum
  • +
  • String
  • +
+

Anything else, like a float, will generate a compiler error.

+ +

Here's an example of a switch statement:

+ +

String s = "Jack";
+ switch(s) {
+    case "Mike":
+       System.out.println("Good morning Mr. " + s);
      break;
+    case "Laura":
+       System.out.println("Good morning Mrs. " + s);
      break;
+    default:
+       System.out.println("Good morning " + s);
+ }

+ +

There are many things to take into account with a switch statement.

+

First, each case needs either a constant value or a final variable initialized at declaration. Otherwise, a compile time error will be generated:

+

final int goodFinal = 2;
+ final int badFinal;
+ badFinal = 3;
+ int var = 1;
+
+ switch(var) {
+    case 1:               // OK
+       var *= 2;
      break;
+    case goodFinal:       // OK
+       var++;
      break;
+    case badFinal:        // Compiler error!
+       var--;
+ }

+ +

It's not valid to have more than case with the same value:

+

final int goodFinal = 2;
+ int var = 1;
+
+ switch(var) {
+    case 1:                // OK
+       var *= 2;
      break;
+    case 2:                // Compiler error!
+       var++;
      break;
+    case goodFinal:        // Compiler error!
+       var--;
+ }

+ +

Besides, case labels are evaluated from top to down beginning from the first case constant that matches the switch expression. This means that all the subsequent statements will be executed until the end of the switch statement, or a break is found. For example:

+

int var = 1;
+
+ switch(var) {
+    case 1:
+       System.out.println("Shirt");
+    case 2:
+       System.out.println("Pants");
+    case 3:
+       System.out.println("Shoes");
+ }

+ +

Will output:

+

Shirt
+ Pants
+ Shoes +

+ +

Because of this, we can have a switch statement like the following:

+

int var = 1;
+
+ switch(var) {
+    case 1:
+    case 2:
+       System.out.println("Pants");
      break;
+    case 3:
+       System.out.println("Shoes");
+ }

+ +

Where, if var is 1 or 2, execution will fall through, and Pants will be printed.

+ +

Also, notice that default doesn't need a break because it's the last element of the switch statement. However, default can appear in any position, so watch for it.

+ + Finally, it may be obvious, but switch statement can only test for equality. This is important when using a String expression because we have to take into account the meaning of object equality. In other words, this won't match: +

String s = "a";
+
+ switch(s) {
+    case "A": // Strings are case-sensitive, so this case won't match
+    ...
+ }

+ + +

Numeric Literals

+

In Java, integers numbers are by default of type int and floating-point numbers are by default of type double.

+ +

Integer numbers are the ones with types byte, short, int, and long and generally expressed in decimal base. However, they can also be expressed as hexadecimal or binary numbers.

+ +

Hexadecimal numbers consist of numbers 0 through 9 and letters A through F. To specify a hexadecimal number, you add the 0x or 0X prefix.

+

int hex = 0x2B; // The number 43 +

+ +

Binary numbers consist of the numbers 0 and 1. To specify a binary number, you add the 0b or 0B prefix.

+

int bin = 0b0010110; // The number 22 +

+ +

These numbers can be cast to float or double types, but we can't express these types as hexadecimal or binary numbers. For example:

+

float goodFloat = 0xF2;             // OK, number 242.0
+ double goodDouble = 0b11110110; ;   // OK, number 246.0
+ float badFloat = 0xF2f;             // Compilation error!
+ double badDouble = 0b11110110d; ;   // Compilation error! +

+ +

From Java 7, you can place any number of underscores between the digits of numbers to separate groups of digits and improve readability.

+ +

You cannot put underscores in the following places:

+
    +
  • At the beginning or end of a number
  • +
  • Adjacent to a decimal point in a floating point literal
  • +
  • Before an F or L suffix
  • +
  • In positions where a string of digits is expected
  • +
+ +

Here are some examples:

+

int i = 34_765;             // OK
+ float f = 43.987_876;       // OK
+ short s = 0b0000____0101;   // OK
+ int i2 = 100_;              // Compilation error!
+ int i3 = 0_x1D;             // Compilation error!
+ int i4 = 0x_1D;             // Compilation error!
+ float f2 = 8945.40_f;       // Compilation error!
+ float f3 = 8945_.40f;       // Compilation error!
+

+ +

java.util.concurrent.locks

+

Soon...

+ + +

Formatting dates, numbers, and currency values

+

Soon...

+ + +

DirectoryStream and FileVisitor interfaces

+

Soon...

+ + +

PathMatcher

+

Soon...

+ + +

WatchService

+

Soon...

+ + + + + +
+ + + +
+
+ + + - + + \ No newline at end of file