Preparation for OCJP8 Exam
Andy Chu
http://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=5001&get_params=p_exam_id:1Z0-810
// filename: OuterClass.java
public class OuterClass {
static class InnerClass{}
class InnerClass2{}
public void doStuff(Object obj){
class InnerClass3{}
}
public static void main(String[] args){
new OuterClass().doStuff(new InnerClass4(){});
}
}
class InnerClass4{}
static class InnerClass5{}
private class InnerClass6{}
Which line(s) causes error?
public static void main(String[] args){
new OuterClass().doStuff(new InnerClass4(){});
new InnerClass();
new OuterClass().new InnerClass2();
new InnerClass4();
}
Which line(s) causes error?
public class EffecivelyFinal {
interface InnerClass{void print();}
public void doStuff(InnerClass o){}
public static void main(String[] args){
final int x = 5;
int y = 10;
new EffecivelyFinal().doStuff(new InnerClass() {
@Override
public void print() {
System.out.println(x);
System.out.println(y);
}
});
y = 15;
new EffecivelyFinal().doStuff(new InnerClass() {
@Override
public void print() {
System.out.println(y);
}
});
}
}
Which line(s) causes error?
Define/write functional Interface
Define/write functional Interface
functional interface
@FunctionalInterface
public interface FuncInterface {
void method();
default void func(){}
}
Define/write functional Interface
public class FuncInterfaceEx {
interface Foo{ void foo(); }
@FunctionalInterface
interface Foo2{ void foo(); }
@FunctionalInterface
interface Foo3{ static void foo();}
@FunctionalInterface
interface Foo4 extends Foo3{ void foo();}
@FunctionalInterface
interface Foo5 { default void foo(){};}
@FunctionalInterface
interface Foo6 extends Foo5 { void foo();}
interface Foo7 { default void foo();}
@FunctionalInterface
interface Foo8 extends Foo6 { void foo();}
}
Which line(s) causes error?
Refactor code from anonymous inner class to lambda expression
What is lambda??
y = f(x) = x + 1
if x = 0 ... 9
then y = 1...10
anonymous class
Refactor code from anonymous inner class to lambda expression
interface OnWhateverListener{ void onWhatever(); }
public void doStuff(OnWhateverListener listener){
listener.onWhatever();
}
public static void main(String[] args){
new AnonymousClass().doStuff(new OnWhateverListener() {
@Override
public void onWhatever() {
// do whatever stuff
}
});
}
anonymous class
public static void main(String[] args) {
new AnonymousClass().doStuff(() -> {
// do whatever stuff
});
}
lambda expression
Refactor code from anonymous inner class to lambda expression
f(x) = x + 1
new AnonymousClass().doStuff(new OnWhateverListener() {
@Override
public void onWhatever() {
// do whatever stuff
}
});
new Thread(new Runnable() {
@Override
public void run() {
// do something
}
});
INPUT
OUTPUT
Functional Interface
anonymous class
Refactor code from anonymous inner class to lambda expression
@FunctionalInterface
interface NoArg{ void foo(); }
Functional Interface
Anonymous class
as Lambda expression
() -> System.out.println("")
@FunctionalInterface
interface OneArg{ void foo(String s); }
s -> System.out.println(s)
s -> {
s = s.trim();
System.out.println(s);
}
@FunctionalInterface
interface TwoArg{ void foo(int x, int y); }
(x, y) -> x + y
(int x, int y) -> x + y
Refactor code from anonymous inner class to lambda expression
public class LambdaEx {
@FunctionalInterface
interface NoArg{ void foo(); }
@FunctionalInterface
interface OneArg{ void foo(String s); }
@FunctionalInterface
interface TwoArg{ void foo(int x, int y); }
public void perform(NoArg foo){}
public void perform(TwoArg foo){}
public void perform(OneArg foo){}
public static void main(String[] args) {
LambdaEx obj = new LambdaEx();
obj.perform(()->System.out.println(""));
obj.perform(s->System.out.println(s));
obj.perform((x,y)->System.out.println(x+y));
obj.perform((int x,int y)->System.out.println(x+y));
}
}
Refactor code from anonymous inner class to lambda expression
Think of
JavaScript call, apply functions
Android observer pattern
Thread runnable
Concurrent Future callable
Reactive programming
Strategy pattern
Command object / pattern
Spring IoC
INPUT
OUTPUT
Functional Interface
T
Void
Consumer
n/a
T
Suppiler
T
R
Function
T
boolean
Predicate
T
T
UnaryOperator
T, T
T
BinaryOperator
anonymous class
T
Void
Consumer
public class ConsumerEx{
interface Consumer<T>{
void perform(T t);
}
public void doStuff(Consumer<String> c){}
public void withJava() {
doStuff(new Consumer<String>(){
@Override
public void perform(String t) {
System.out.println(t);
}
});
}
public void withJava8() {
doStuff(s -> System.out.println(s.toLowerCase()));
doStuff(s -> System.out.println(s.toUpperCase()));
}
}
n/a
T
Supplier
public class SupplierEx{
interface Supplier<T>{
T perform();
}
public void doStuff(Supplier<String> s){
System.out.println(s.perform());
}
public void withJava() {
doStuff(new Supplier<String>(){
@Override
public String perform() {
return "Hello World";
}
});
}
public void withJava8() {
doStuff(() -> "Hello World".toLowerCase());
doStuff(() -> {return "Hello World".toUpperCase();});
}
}
T
boolean
Predicate
public class PredicateEx{
interface Predicate<T>{
boolean perform(T t);
}
public void doStuff(Predicate<String> p){
String s = "something";
if(p.perform(s)){System.out.println("do" + s);}
}
public void withJava() {
doStuff(new Predicate<String>(){
@Override
public boolean perform(String s) {
return s != null;
}
});
}
public void withJava8() {
doStuff(s -> s != null);
}
}
T
R
Function
public class FunctionEx{
interface Function<T, R>{
R perform(T t);
}
public void doStuff(Function<Integer, String> f){
System.out.println(f.perform((int)Math.random() * 100));
}
public void withJava() {
doStuff(new Function<Integer, String>(){
@Override
public String perform(Integer s) {
if(s >= 60) return "pass";
else return "fail";
}
});
}
public void withJava8() {
doStuff(score -> {
if(score >= 80) return "pass";
else return "fail";
});
}
}
T
T
UnaryOperator
public class UnaryOpEx{
interface UnaryOp<T>{
T perform(T t);
}
public void doStuff(UnaryOp<String> u){
System.out.println(u.perform("something"));
}
public void withJava() {
doStuff(new UnaryOp<String>(){
@Override
public String perform(String s) {
return "baked " + s;
}
});
}
public void withJava8() {
doStuff(s -> "baked " + s);
doStuff(s -> "eat " + s);
}
}
T, T
T
BinaryOperator
public class BinaryOpEx{
interface BinaryOp<T>{
T perform(T t, T t2);
}
public void doStuff(BinaryOp<Integer> b){
System.out.println(b.perform(2, 1));
}
public void withJava() {
doStuff(new BinaryOp<Integer>(){
@Override
public Integer perform(Integer a, Integer b) {
return a + b;
}
});
}
public void withJava8() {
doStuff((a, b) -> a * b);
doStuff((a, b) -> a - b);
}
}
https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
Develop/use primitive and binary variations of base interface
Function descriptor
T -> boolean
int -> boolean
double -> boolean
T -> R
int -> R
T -> int
Function Interface
Predicate<T>
IntPredicate
DoublePredicate
Function<T, R>
IntFunction<R>
ToIntFunction<T>
Develop/use primitive and binary variations of base interface
Develop/use primitive and binary variations of base interface
public class IntPredicateEx{
interface IntPredicate extends Predicate<Integer>{
boolean perform(int t);
}
public void doStuff(IntPredicate p){
if(p.perform((int) Math.random() * 10)){
System.out.println("Hello World");
}
}
public void withJava() {
doStuff(new IntPredicate(){
@Override
public boolean perform(int t) {
return false;
}
});
}
public void withJava8() {
doStuff(n -> true);
}
}
Which line(s) causes error? How to correct?
Develop/use primitive and binary variations of base interface
public class IntPredicateEx{
// this is not functional interface
interface IntPredicate extends Predicate<Integer>{
boolean perform(int t);
}
public void doStuff(IntPredicate p){
if(p.perform((int) Math.random() * 10)){
System.out.println("Hello World");
}
}
public void withJava() {
// needs to implement both because of autoboxing/unboxing
doStuff(new IntPredicate(){
@Override
public boolean perform(int t) {
return false;
}
@Override
public boolean perform(Integer t) {
return false;
}
});
}
public void withJava8() {
doStuff(n -> true); // can't compile
}
}
Develop/use method reference
ClassName::staticMethodName
// ClassName::staticMethodName
IntFunction<String> f = n -> String.valueOf(n);
IntFunction<String> f = String::valueOf;
// ClassName::new
Supplier<String> f = () -> new String();
Supplier<String> f = String::new;
// ClassName::instanceMethodName
UnaryOperator<String> f = s -> s.trim();
UnaryOperator<String> f = String::trim;
ClassName::new
ClassName::instanceMethodName
// object::instanceMethodName
Integer i = new Integer(1);
Supplier<String> f = () -> i.toString();
Supplier<String> f = i::toString;
object::instanceMethodName
Develop/uses code that iterates a collection by using forEach
public class Apple {
private String color;
private int calory;
public Apple(){
this.color = "red";
this.calory = 300;
}
public Apple(String color) {
this.color = color;
this.calory = 300;
}
public Apple(String color, int calory) {
this.color = color;
this.calory = calory;
}
public String getColor(){
return color;
}
public int getCalory(){
return calory;
}
}
Apple.java
Develop/uses code that iterates a collection by using forEach
public class ExternalIteration{
List<Apple> apples = new ArrayList<Apple>();
public ExternalIteration(){
apples.add(new Apple("green"));
apples.add(new Apple("red"));
apples.add(new Apple("red"));
}
public void withJava() {
for(Apple apple : apples){
if("green".equals(apple)){
System.out.println("I found green apple.");
}
}
}
}
(Active) External iteration
Develop/uses code that iterates a collection by using forEach
public class InternalIteration{
List<Apple> apples = new ArrayList<Apple>();
public InternalIteration(){
apples.add(new Apple("green"));
apples.add(new Apple("red"));
apples.add(new Apple("red"));
}
public void withJava8(Consumer<Apple> c) {
for(Apple apple : apples){
c.accept(apple);
}
}
public void doStuff(){
withJava8(apple -> {
if("green".equals(apple)){
System.out.println("I found green apple.");
}
});
}
}
(passive) Internal iteration
Develop/uses code that iterates a collection by using forEach
public interface Iterable<T> {
public Iterator<T> iterator();
}
Java 5
public interface Iterable<T extends Object> {
public Iterator<T> iterator();
public default void forEach(Consumer<? super T> cnsmr) {
// ...
}
...
}
Java 8
Develop/uses code that iterates a collection by using forEach
public class Iteration{
List<Apple> apples = new ArrayList<Apple>();
public Iteration(){
apples.add(new Apple("green"));
apples.add(new Apple("red"));
apples.add(new Apple("red"));
}
public void withJava8() {
apples.forEach(apple -> {
if("green".equals(apple)){
System.out.println("I found green apple.");
}
});
}
}
Collection, List, Set, Map
Describe the Stream interface and pipelines
public class Pipeline{
List<Apple> apples = new ArrayList<Apple>();
public Pipeline(){
apples.add(new Apple("green", 200));
apples.add(new Apple("red", 300));
apples.add(new Apple("red",50));
}
public void withJava() {
List<Apple> redApples = new ArrayList<Apple>();
for(Apple apple : apples){
if("red".equals(apple)){
redApples.add(apple);
}
}
List<Apple> lowFatRedApples = new ArrayList<Apple>();
for(Apple apple : redApples){
if(apple.getCalory() < 100){
lowFatRedApples.add(apple);
}
}
}
}
Find low fat and red apples
Describe the Stream interface and pipelines
public class Pipeline2{
...
public List<Apple> findRedApples(List<Apple> apples) {
List<Apple> redApples = new ArrayList<Apple>();
for(Apple apple : apples){
if("red".equals(apple)){
redApples.add(apple);
}
}
return redApples;
}
public List<Apple> findLowFatApples(List<Apple> apples) {
List<Apple> lowFatRedApples = new ArrayList<Apple>();
for(Apple apple : apples){
if(apple.getCalory() < 100){
lowFatRedApples.add(apple);
}
}
return lowFatRedApples;
}
public List<Apple> findLowFatAndRedApples(List<Apple> apples) {
return findLowFatAndRedApples(findRedApples(apples));
}
}
What pattern do you see here ?
Describe the Stream interface and pipelines
public class Pipeline3{
...
public Pipeline3 findRedApples() {
List<Apple> redApples = new ArrayList<Apple>();
for(Apple apple : apples){
if("red".equals(apple)){
redApples.add(apple);
}
}
apples = redApples;
return this;
}
public Pipeline3 findLowFatApples() {
List<Apple> lowFatRedApples = new ArrayList<Apple>();
for(Apple apple : apples){
if(apple.getCalory() < 100){
lowFatRedApples.add(apple);
}
}
apples = lowFatRedApples;
return this;
}
public List<Apple> getApples(){return apples;}
public static void main(String[] args) {
new Pipeline3()
.findLowFatApples()
.findRedApples()
.getApples();
}
}
Builder / Decoration Pattern
Describe the Stream interface and pipelines
public class Pipeline4{
...
public Pipeline4 filter(Predicate<Apple> p) {
List<Apple> redApples = new ArrayList<Apple>();
for(Apple apple : apples){
if(p.test(apple)){
redApples.add(apple);
}
}
apples = redApples;
return this;
}
public List<Apple> getApples(){return apples;}
public static void main(String[] args) {
new Pipeline4()
.filter(apple -> "red".equals(apple))
.filter(apple -> apple.getCalory() < 100)
.getApples();
}
}
What else do you see here?
Filter a collection using lambda expression
http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
Stream Interface
public class Pipeline5{
...
public List<Apple> findLowFatAndRedApples(){
return apples.stream()
.filter(apple -> "red".equals(apple))
.filter(apple -> apple.getCalory() < 100)
.collect(Collectors.toList());
}
public static void main(String[] args) {
new Pipeline5().findLowFatAndRedApples();
}
}
Identify lambda operation that are lazy
Operation returns Stream => Lazy
Stream<Apple> s = sapples.stream()
.filter(apple -> {
System.out.println("Log");
return "red".equals(apple)
}) // lazy
List<Apple> redApples = apples.stream()
.filter(apple -> {
System.out.println("Log");
return "red".equals(apple)
})
.collect(Collectors.toList()); // eager
Operation returns something or void => Eager
Collection Operation with Lambda
public class MapEx extends BaseTest{
@Override
public Object withJava() {
List<String> names = new ArrayList<String>();
for(Player p : players){
names.add(p.getName());
}
return names;
}
@Override
public void withJava8(Object expectedResult) {
List<String> names = players.stream()
.map(Player::getName)
.collect(Collectors.toList());
assertEquals(expectedResult, names);
}
}
Collection Operation with Lambda
public class FindAnyEx extends BaseTest{
@Override
public Object withJava() {
List<Integer> ages = new ArrayList<Integer>();
for(Player p : players){
if(p.getAge() == 30)
ages.add(p.getAge());
}
Collections.shuffle(ages);
return ages.get(0);
}
@Override
public void withJava8(Object expectedResult) {
Optional<Player> player = players.stream()
.filter(p -> p.getAge() == 30)
.findAny();
assertEquals(expectedResult, player.get().getAge());
}
}
Collection Operation with Lambda
public class FindFirstEx extends BaseTest{
@Override
public Object withJava() {
List<Integer> ages = new ArrayList<Integer>();
for(Player p : players){
if(p.getAge() == 30)
ages.add(p.getAge());
}
return ages.get(0);
}
@Override
public void withJava8(Object expectedResult) {
Optional<Player> player = players.stream()
.filter(p -> p.getAge() == 30)
.findFirst();
assertEquals(expectedResult, player.get().getAge());
}
}
Collection Operation with Lambda
public class AllMatchEx extends BaseTest{
@Override
public Object withJava() {
for(Player p : players){
if(p.getAge() != 30)
return false;
}
return true;
}
@Override
public void withJava8(Object expectedResult) {
Boolean b = players.stream()
.allMatch(p -> p.getAge() == 30);
assertEquals(expectedResult, b);
}
}
Collection Operation with Lambda
public class NoneMatchEx extends BaseTest{
@Override
public Object withJava() {
for(Player p : players){
if(p.getAge() == 30)
return false;
}
return true;
}
@Override
public void withJava8(Object expectedResult) {
Boolean b = players.stream()
.noneMatch(p -> p.getAge() == 30);
assertEquals(expectedResult, b);
}
}
Collection Operation with Lambda
public class AnyMatchEx extends BaseTest{
@Override
public Object withJava() {
for(Player p : players){
if(p.getAge() == 30)
return true;
}
return false;
}
@Override
public void withJava8(Object expectedResult) {
Boolean b = players.stream()
.anyMatch(p -> p.getAge() == 30);
assertEquals(expectedResult, b);
}
}
Describe the unique characteristics of the Optional
http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
Collection Operation with Lambda
public class CountEx extends BaseTest{
@Override
public Object withJava() {
List<Player> ps = new ArrayList<Player>();
for(Player p : players){
if(p.getAge() == 30)
ps.add(p);
}
return ps.size();
}
@Override
public void withJava8(Object expectedResult) {
long c = players.stream()
.filter(p -> p.getAge() == 30)
.count();
assertEquals(expectedResult, (int)c);
}
}
Collection Operation with Lambda
public class AverageEx extends BaseTest{
@Override
public Object withJava() {
int sum = 0;
int count = 0;
for(Player p : players){
if(p.getAge() == 30){
sum += p.getAge();
count++;
}
}
return (double) sum / count; // return sum
}
@Override
public void withJava8(Object expectedResult) {
OptionalDouble average = players.stream()
.filter(p -> p.getAge() == 30)
.mapToInt(p -> p.getAge())
.average(); // sum()
assertEquals(expectedResult, average.getAsDouble());
}
}
Collection Operation with Lambda
public class SortEx extends BaseTest{
@Override
public Object withJava() {
List<Player> ps = players;
Collections.sort(players, new Comparator<Player>() {
@Override
public int compare(Player p1, Player p2) {
return p1.getName().compareTo(p2.getName());
}
});
return ps;
}
@Override
public void withJava8(Object expectedResult) {
List<Player> ps = players;
ps.sort((p1, p2) -> p1.getName().compareTo(p2.getName()));
assertEquals(expectedResult, ps);
}
}
Collection Operation with Lambda
public class AverageEx2 extends BaseTest{
@Override
public Object withJava() {
int sum = 0;
int count = 0;
for(Player p : players){
if(p.getAge() == 30){
sum += p.getAge();
count++;
}
}
return (double) sum / count;
}
@Override
public void withJava8(Object expectedResult) {
Double average = players.stream()
.filter(p -> p.getAge() == 30)
.collect(Collectors.averagingDouble(p -> (double)p.getAge()));
assertEquals(expectedResult, average);
}
}
Collection Operation with Lambda
public class GroupingByEx extends BaseTest{
@Override
public Object withJava() {
Map<String, List<Player>> ps = new HashMap<String, List<Player>>();
for(Player p : players){
String key = p.getNationality();
if(ps.containsKey(key)){
ps.get(key).add(p);
}else{
List<Player> value = new ArrayList<Player>();
value.add(p);
ps.put(key, value);
}
}
return ps;
}
@Override
public void withJava8(Object expectedResult) {
Map<String, List<Player>> ps = players.stream()
.collect(Collectors.groupingBy(p -> p.getNationality()));
assertEquals(expectedResult, ps);
}
}
Collection Operation with Lambda
public class PartitioningByEx extends BaseTest{
@Override
public Object withJava() {
Map<Boolean, List<Player>> ps = new HashMap<Boolean, List<Player>>();
ps.put(true, new ArrayList<Player>());
ps.put(false, new ArrayList<Player>());
for(Player p : players){
if(p.getAge() > 28){
ps.get(true).add(p);
}else{
ps.get(false).add(p);
}
}
return ps;
}
@Override
public void withJava8(Object expectedResult) {
Map<Boolean, List<Player>> ps = players.stream()
.collect(Collectors.partitioningBy(p -> p.getAge() > 28));
assertEquals(expectedResult, ps);
}
}
Collection Operation with Lambda
public class JoiningEx extends BaseTest{
@Override
public Object withJava() {
StringBuilder sb = new StringBuilder();
int count = 0;
for(Player p : players){
if(count == 0){
sb.append(p.getName());
count++;
}else{
sb.append(", ").append(p.getName());
}
}
return sb.toString();
}
@Override
public void withJava8(Object expectedResult) {
String name = players.stream()
.map(p -> p.getName())
.collect(Collectors.joining(", "));
assertEquals(expectedResult, name);
}
}
Using Collector
class MyCollector extends Collector<Person, Container, Integer>
Input
Output
Accumulator
methods to be implemented
supplier() -> create / initial container
accumulator() -> accumulate input to container
combiner() -> combine accumulators ( for parallel computing)
finisher() -> finalize the type of result
could be any sort of builder class... ex: StringBuilder, to keep track the accumulated result.
Using Collector
class MyCollector implements Collector<Person, Container, Integer>{
@Override
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return EnumSet.of(Characteristics.UNORDERED);
}
@Override
public Supplier<Container> supplier() {
return () -> new Container();
}
@Override
public BiConsumer<Container, Person> accumulator() {
return (c, p) -> c.add(p.getAge());
}
@Override
public BinaryOperator<Container> combiner() {
return (left, right) -> left.merge(right);
}
@Override
public Function<Container, Integer> finisher() {
return (c) -> c.get();
}
}
class Container{
private Integer n = 0;
public void add(Integer n){
this.n += n;
}
public void add(Person p){
this.n += p.getAge();
}
public Integer get(){
return n;
}
public Container merge(Container c){
n += c.get();
return this;
}
}
To calculate sum of all player's ages.
Using Collector
class MyCollector2 implements Collector<Person, Container, Integer>{
@Override
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return EnumSet.of(Characteristics.UNORDERED);
}
@Override
public Supplier<Container> supplier() {
return () -> new Container();
}
@Override
public BiConsumer<Container, Person> accumulator() {
return Container::add;
}
@Override
public BinaryOperator<Container> combiner() {
return Container::merge;
}
@Override
public Function<Container, Integer> finisher() {
return Container::get;
}
}
Integer result = players.stream().collect(new MyCollector());
Integer result2 = players.stream().collect(new MyCollector2());
Using Collector method / Reduction
Integer total = players.stream()
.reduce(
0,
(i, p) -> i += p.getAge(),
(left, right) -> left + right
);
Integer total = players.stream()
.collect(Collectors.reducing
(
0,
(p) -> p.getAge(),
(left, right) -> left + right
)
);
We get the same result by using reduction methods. by reduce (from Stream) or reducing (from Collectors)
Develope/uses parallel streams
public static void main(String... args) {
long sum = IntStream.range(1, 100_000).parallel().sum();
System.out.println("Sum: " + sum);
int x = Arrays.asList(1,2,3,4,5,6,7,8,9,10)
.parallelStream()
.collect(Collectors.summingInt(i -> i));
System.out.println(x);
}
be brief:
change from stream() to parallelStream()
Stream -> parallel()
Collection -> paraelStream()
Develope/uses parallel streams
Implement decomposition, reduction, in streams
public class ReduceParallelStreamEx {
public static void main(String... args) {
List<Person> persons = Stream.generate(
()->new Person( (int)(Math.random()*99)+1 )
)
.limit(10)
.collect(Collectors.toList());
int x = persons.parallelStream()
.mapToInt(p -> p.getAge())
.reduce(0, (a,b) -> b > a ? b : a);
System.out.println("Max: " + x);
}
static class Person{
private int age;
Person(int age){
this.age = age;
}
public int getAge(){
return age;
}
}
}
Using Java8 collection improvements
Using Java8 collection improvements
Collection.removeIf
public class RemoveIfEx extends BaseTest{
@Override
public Object withJava() {
List<Player> ps = getPlayers();
Iterator<Player> iterator = ps.iterator();
while(iterator.hasNext()){
if(iterator.next().getAge() > 30){
iterator.remove();
}
}
return ps;
}
@Override
public void withJava8(Object expectedResult) {
List<Player> ps = getPlayers();
ps.removeIf(p -> p.getAge() > 30);
assertEquals(expectedResult, ps);
}
}
Using Java8 collection improvements
List.replaceAll
public class ReplaceAllEx extends BaseTest{
@Override
public Object withJava() {
List<Player> ps = getPlayers();
for(int i=0; i<ps.size(); i++){
ps.set(i, null);
}
return ps;
}
@Override
public void withJava8(Object expectedResult) {
List<Player> ps = getPlayers();
ps.replaceAll(p -> null);
assertEquals(expectedResult, ps);
}
}
Using Java8 collection improvements
public class MapForEachEx extends BaseTest{
Map<Integer, String> map;
@Override
public void init(){
map = new HashMap<Integer, String>();
map.put(1,"a");
map.put(2,"b");
map.put(3,"c");
}
@Override
public Object withJava() {
Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Entry<Integer, String> entry = iterator.next();
System.out.println("Key:" + entry.getKey() + " Value: " + entry.getValue());
}
return map;
}
@Override
public void withJava8(Object expectedResult) {
map.forEach((k,v) -> System.out.println("Key:" + k + " Value: " + v));
assertEquals(expectedResult, map);
}
}
Using Java8 collection improvements
public class MapComputeIfEx extends BaseTest{
Map<Integer, String> map;
@Override
public void init(){
map = new HashMap<Integer, String>();
map.put(1,"a");
map.put(2,"b");
map.put(3,"c");
}
@Override
public Object withJava() {
String s = map.get(1);
String s2 = map.get(4);
String s3 = map.get(1);
if(s == null){ s = "d"; }
if(s2 == null){ s2 = "e"; }
if(s3 != null){ s3 = "f"; }
System.out.println(s + s2 + s3);
return null;
}
@Override
public void withJava8(Object expectedResult) {
String s = map.computeIfAbsent(1, k -> "d");
String s2 = map.computeIfAbsent(4, k -> "e");
String s3 = map.computeIfPresent(1, (k, v) -> "f");
System.out.println(s + s2 + s3);
}
}
Read files using lambda improvements
public class FileImproveEx {
public static void main(String... args) throws IOException {
Path start = new File(".").toPath();
BiPredicate<Path, BasicFileAttributes> topicDirectoriesMatcher = (path,
basicFileAttributes) -> basicFileAttributes.isDirectory()
&& path.toString().contains("topic6");
System.out.println("Found directories:");
Stream<Path> pathStream = Files.find(start, Integer.MAX_VALUE,
topicDirectoriesMatcher);
pathStream.forEach(System.out::println);
List<Path> paths = Files.walk(start)
.filter(p -> p.toString().contains("FileImproveEx.java"))
.collect(Collectors.toList());
System.out.println("\nFile path: " + paths.get(0));
System.out.println("\nFile content: ");
Files.lines(paths.get(0), Charset.defaultCharset()).forEach(
System.out::println);
}
}
Files.find => find files from the given starting file path
Files.walk => traversal the file tree from the given starting file path
Files.lines => traversal line from the given file path
Use merge, flatMap methods on a collection
public class FlatMapEx extends BaseTest{
@Override
public Object withJava() {
List<String> teamNames = new ArrayList<String>();
for(Tournament t : tournaments){
List<Team> teams = t.getTeams();
if(teams != null){
for(Team team : teams){
teamNames.add(team.getName());
}
}
}
return teamNames;
}
@Override
public void withJava8(Object expectedResult) {
List<String> teamNames = tournaments.stream()
.flatMap(t -> t.getTeams().stream())
.map(team -> team.getName())
.collect(Collectors.toList());
assertEquals(expectedResult, teamNames);
}
}
FlatMap
Use merge, flatMap methods on a collection
public class MergeEx extends BaseTest{
Map<Integer, String> map;
@Override
public void init(){
map = new HashMap<Integer, String>();
map.put(1,"a");
map.put(2,"a");
}
@Override
public Object withJava() {
String s = map.get(1);
map.put(1, "hello " + s);
return map.get(1);
}
@Override
public void withJava8(Object expectedResult) {
String newValue = map.merge(2, "hello", (s1, s2) -> s2 + " " + s1);
assertEquals(expectedResult, newValue);
}
}
Merge
Describe Arrays.stream(), IntStream.range()
public class IntStreamEx {
public static void main(String... args) throws IOException {
int[] nums = IntStream.rangeClosed(1, 3).toArray();
IntStream is = Arrays.stream(nums);
is.forEach(System.out::println);
IntStream.rangeClosed(1, 3)
.forEach(System.out::println);;
}
}
Define and use a default method of a interface, describe the inheritance rules for a default method
interface Foo{ void noo(); }
interface Boo{ void noo(); }
interface Moo{ void noo(); }
class Hoo implements Foo, Boo, Moo{
@Override
public void noo() {}
}
interface Foo2{ default void noo(){System.out.println("foo");}; }
interface Boo2{ void noo(); }
class Hoo2 implements Foo2, Boo2{
@Override
public void noo() {System.out.println("hoo");}
}
abstract class Foo4{ abstract void noo(); }
interface Boo4{ default void noo(){System.out.println("boo");}; }
class Hoo4 extends Foo4 implements Boo4{
@Override
public void noo() {System.out.println("hoo");}
}
abstract class Foo3{ abstract void noo(); }
interface Boo3{ void noo(); }
class Hoo3 extends Foo3 implements Boo3{
@Override
public void noo() {System.out.println("hoo");}
}
abstract class Foo5{ abstract void noo(); }
interface Boo5{ default void noo(){System.out.println("boo");}; }
interface Moo5{ void noo(); }
class Hoo5 extends Foo5 implements Boo5, Moo5{
@Override
public void noo() {System.out.println("hoo");}
}
interface Boo7{ default void noo(){System.out.println("boo");} }
interface Moo7{ default void noo(){System.out.println("moo");} }
class Hoo7 implements Boo7, Moo7{
@Override
public void noo() {System.out.println("hoo");}
}
abstract class Foo6{ abstract void noo(); }
interface Boo6{ default void noo(){System.out.println("boo");} }
interface Moo6{ default void noo(){System.out.println("moo");} }
class Hoo6 extends Foo6 implements Boo6, Moo6{
@Override
public void noo() {System.out.println("hoo");}
}
public static void main(String[] args){
MutiInterfaceEx obj = new MutiInterfaceEx();
obj.new Hoo().noo(); obj.new Hoo2().noo();
obj.new Hoo3().noo(); obj.new Hoo4().noo();
obj.new Hoo5().noo(); obj.new Hoo6().noo();
obj.new Hoo7().noo();
}
point out: 1) compiler error, 2) runtime error, 3) what's output
1
2
3
4
5
6
7
Define and use a default method of a interface, describe the inheritance rules for a default method
public class DefaultInheritEx {
interface Parent{
default void hi(){System.out.println("parent hi");}
}
interface Child{
default void hi(){System.out.println("child hi");};
}
interface Child2 extends Parent{
default void hi(){System.out.println("child2 hi");};
}
class ParentImpl implements Parent{
@Override public void hi(){};
}
class ChildImpl extends ParentImpl implements Child{
@Override public void hi(){System.out.println("child impl hi");}
}
class ChildImpl2 extends ParentImpl implements Child2{
@Override public void hi(){System.out.println("child impl2 hi");}
}
class ChildImpl3 implements Child{
}
class ChildImpl4 implements Child, Child2{
}
class ChildImpl5 extends ParentImpl implements Child, Child2{
}
public static void main(String[] args){
DefaultInheritEx obj = new DefaultInheritEx();
obj.new ChildImpl().hi();
obj.new ChildImpl2().hi();
obj.new ChildImpl3().hi();
obj.new ChildImpl4().hi();
obj.new ChildImpl5().hi();
}
}
Any Error?
1) Comiple error
2) Runtime error
If no error, then what's the possible output ?
Define and use a default method of a interface, describe the inheritance rules for a default method
Rule 1:
classes always win. A method declaration in the class or a superclass takes priority over any default method declaration.
Rule2:
otherwise, sub-interface win. the method win the same signature in the most specific default-providing interface is selected.
Rule3:
if the choice is still ambiguous, the class inheriting from multiple interfaces has to explicitly select which default method implementation to use by overriding it and calling the desired method explicitly.
(reference: book Java 8 in Action.)
Define and use a default method of a interface, describe the inheritance rules for a default method
Example of Rule1:
interface A has a default method.
class B extends class A
(use default method from A)
Example of Rule2: class
interface B extends A, whereas the interface A has a default method
class C implements B, A
(use default method from B)
Example of Rule3:
B and A have the default method with the same signature
class C implements B, A
C explicitly overrides the default method.
(use default method from C)
Adding static methods to interface
Static methods are similar to default methods except that we can’t override them in the implementation classes
public class StaticDefaultEx {
interface Parent{
static void hi(){
// must have body
}
}
class Child implements Parent{
static void hi(){
// complier error
}
}
class Child2 implements Parent{
void hi(){
// ok, this is a class method
}
}
}
Why we need new Date/Time API
Create and manage date-based and time-based events; including combination of date and time into a single object using LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration
public class DateTimeEx {
public static void main(String... args) throws IOException {
/* LocalDate */
LocalDate specificDate = LocalDate.of(2015, 10, 26);
LocalDate todayDate = LocalDate.now();
/* LocalTime */
LocalTime specificTime = LocalTime.of(23, 59, 59);
LocalTime nowTime = LocalTime.now();
/* LocalDateTime */
System.out.println(LocalDate.parse("2015-10-26"));
System.out.println(LocalTime.parse("23:59:59"));
LocalDateTime specificDateTime = LocalDateTime.of(1985, Month.OCTOBER, 26, 23, 59, 29);
LocalDateTime nowDateTime = LocalDateTime.now();
/* Instant */
// 1 Million seconds since the Unix epoch time
Instant oneMSInstant = Instant.ofEpochSecond(1_000_000_000);
Instant nowInstant = Instant.now(); // seconds since the Unix epoch time to now
/* Duration */ // A date-based amount of time
Duration.between(specificTime, nowTime);
/* Period */ // A date-based amount of time
Period.between(specificDate, todayDate);
}
}
Work with dates and times across time-zones and manage changes resulting from daylight savings
public class TimeZoneEx {
public static void main(String... args) throws IOException {
LocalDateTime now = LocalDateTime.now();
ZoneId zid1 = ZoneId.of("Asia/Tokyo");
ZonedDateTime t1 = ZonedDateTime.of(now, zid1);
System.out.println("Time at Tokyo zone now: " + t1);
ZoneId zid2 = ZoneId.of("America/Los_Angeles");
ZonedDateTime t2 = t1.withZoneSameInstant(zid2);
System.out.println("Same time at LA zone: " + t2);
Duration daySaving = zid2.getRules().getDaylightSavings(Instant.now());
System.out.println("LA zone day light saving offset: " + daySaving);
System.out.println("Same time at LA zone with day light saving: " + t2.minusSeconds(daySaving.getSeconds()));
}
}
Define and create timestamps, periods and durations; apply formatting to local and zoned dates and times
public class DateTimeFormatEx {
public static void main(String... args) throws IOException {
LocalDateTime now = LocalDateTime.now();
System.out.println(now.format(DateTimeFormatter.ISO_DATE));
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME));
System.out.println(now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss")));
System.out.println(now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss",Locale.TAIWAN)));
}
}
Evaluated by passing javascript code
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval("print('Hello World!');");
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("script.js"));
Evaluated by passing javascript file
// script.js
var greeting = function(name) {
print('Hello, ' + name);
return "Hello from javascript";
};
// MyJavaClass.java
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("script.js"));
Invocable invocable = (Invocable) engine;
Object result = invocable.invokeFunction("greeting", "Peter");
System.out.println(result);
// output:
// hello, Peter
// Hello from javascript
Develop Javascript code that creates and uses Java members such as Java objects, methods, JavaBeans, Arrays, Collections, Interfaces.
// script.js
var print= function (object) {
print("JS Class Definition: " + Object.prototype.toString.call(object));
};
// MyJavaClass.java
invocable.invokeFunction("print", new Date());
// [object java.util.Date]
invocable.invokeFunction("print", LocalDateTime.now());
// [object java.time.LocalDateTime]
invocable.invokeFunction("print", new Person());
// [object com.winterbe.java8.Person]
// MyJavaClass.java
static String greeting(String name) {
System.out.format("Hello, %s", name);
return "Hello from java";
}
// whatever.js
var MyJavaClass = Java.type('my.package.MyJavaClass');
var result = MyJavaClass.greeting('Juke');
print(result);
// output:
// Hello, Juke
// Hellow from java
// foo.js
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function() {
return this.firstName + " " + this.lastName;
}
}
// MyJavaClass.java
static void fullname(ScriptObjectMirror person) {
System.out.println("Full Name is: " + person.callMember("getFullName"));
}
var p = new Person("Peter", "Parker");
MyJavaClass.fullname(p); // Full Name is: Peter Parker
The javascript method getFullName can be called on the ScriptObjectMirror via callMember()
// whatever.js
var ArrayList = Java.type('java.util.ArrayList');
var list = new ArrayList();
list.add('a');
list.add('b');
list.add('c');
for each (var el in list) print(el); // a, b, c
Collection and For Each
// whatever.js
var map = new java.util.HashMap();
map.put('foo', 'val1');
map.put('bar', 'val2');
for each (var e in map.keySet()) print(e); // foo, bar
for each (var e in map.values()) print(e); // val1, val2
HashMap
Lambda
var list = new java.util.ArrayList();
list.add("aaa2");
// add more el
list
.stream()
.filter(function(el) {
return el.startsWith("aaa");
})
.sorted()
.forEach(function(el) {
print(el);
});
Extending classes
// whatever.js
var Runnable = Java.type('java.lang.Runnable');
var Printer = Java.extend(Runnable, {
run: function() {
print('printed from a separate thread');
}
});
var Thread = Java.type('java.lang.Thread');
new Thread(new Printer()).start();
new Thread(function() {
print('printed from another thread');
}).start();
// printed from a separate thread
// printed from another thread
https://github.com/ajoshow/ocjp8ex