--- /dev/null 2013-09-26 12:31:35.724641065 +0400 +++ new/src/share/demo/extension-methods/ArrayIterator.java 2013-09-27 18:40:59.217577614 +0400 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + */ + + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * The code sample illustrates usage default methods in the JDK 8. Most + * implementations of Iterator don’t provide a useful remove(), however, they + * still have to implement this method just to throw + * UnsupportedOperationException. With default method, we could provide the same + * "default" behavior in interface Iterator itself + */ +public class ArrayIterator { + + public static Iterator iterator(final E[] array) { + return new Iterator() { + /** + * Initial array + * + */ + private final E[] srcArray = array; + + /** + * Index of the current position + * + */ + private int index = 0; + + @Override + public boolean hasNext() { + return (index < srcArray.length); + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return srcArray[index++]; + } + + /** + * We do not need to override this method in JDK 8 + */ + //@Override + //public void remove() { + // throw UnsupportedOperationException("Arrays don't support remove") + //} + }; + } + + public static void main(String args[]) { + Iterator it = ArrayIterator.iterator(new String[]{"one", "two", "three"}); + + while (it.hasNext()) { + System.out.println(it.next()); + } + } +} --- /dev/null 2013-09-26 12:31:35.724641065 +0400 +++ new/src/share/demo/extension-methods/DiamondInheritance.java 2013-09-27 18:40:59.673805633 +0400 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + */ + + +/** + * The code sample diamond inheritance with default methods. If there's + * not already a unique method implementation to inherit, you have to provide + * it. The inheritance diagram like below: + *
+ *                   Animal
+ *                    /   \
+ *                 Horse   Bird
+ *                    \   /
+ *                   Pegasus
+ * 
+ * + * Both {@link Horse} and {@link Bird} interfaces implements go + * method. The {@link Pegasus} class have to override go method. + * + * The new syntax of super-call is used here: + *
+ *     <interface_name>.super.<method>(...);
+ *     e.g.:  Horse.super.go();
+ * 
So, Pegasus goes like a Horse + */ +public class DiamondInheritance { + + /** + * Base interface to illustrate diamond inheritance . + * + * @see DiamondInheritance + */ + public interface Animal { + + void go(); + } + + /** + * Interface to illustrate diamond inheritance. + * + * @see DiamondInheritance + */ + public interface Horse extends Animal { + + @Override + default void go() { + System.out.println(this.getClass().getSimpleName() + " walks on four legs"); + } + } + + /** + * Interface to illustrate diamond inheritance. + * + * @see DiamondInheritance + */ + public interface Bird extends Animal { + + @Override + default void go() { + System.out.println(this.getClass().getSimpleName() + " walks on two legs"); + } + } + + /** + * Class to illustrate diamond inheritance. + * Pegasus have to mix Horse and Bird behavior. + * + * @see DiamondInheritance + */ + public static class Pegasus implements Horse, Bird { + + @Override + public void go() { + Horse.super.go(); + } + } + + public static void main(String[] args) { + new Pegasus().go(); + } +} --- /dev/null 2013-09-26 12:31:35.724641065 +0400 +++ new/src/share/demo/extension-methods/Inheritance.java 2013-09-27 18:41:00.061999648 +0400 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + */ + + +/** + * The sample illustrates rules to resolve conflicts between inheritance + * candidates with default methods. There are two simple rules: + *
    + *
  • Class wins. If the superclass has a concrete or abstract declaration of + * this method, it is preferred over all defaults.
  • + *
  • Subtype wins. If an interface extends another interface, and both provide + * a default, the more specific interface wins.
  • + *
+ */ +public class Inheritance { + + public interface Swimable { + + default void swim() { + System.out.println("I can swim"); + } + } + + /** + * The abstract class that overrides {@link #swim} method + */ + public abstract static class Fish implements Swimable { + + @Override + public void swim() { + System.out.println(this.getClass().getSimpleName() + " swims under water"); + } + } + + /** + * This class is used for illustration rule 1. See the source code of the + * {@link #main} method + *
+     *      new Tuna().swim(); //"Tuna swims under water" output is suspected here
+     * 
+ */ + public static class Tuna extends Fish implements Swimable { + } + + /** + * The interface that overrides {@link #swim} method (subtype of + * {@link Swimable}) + */ + public interface Diveable extends Swimable { + + @Override + default void swim() { + System.out.println("I can swim on a water surface"); + } + + default void dive() { + System.out.println("I can dive"); + } + } + + /** + * This class is used for illustration rule 2. See the source code of the + * {@link #main} method + *
+     *      new Duck().swim(); //"I can swim on a water surface" output is suspected here
+     * 
+ */ + public static class Duck implements Swimable, Diveable { + } + + public static void main(String[] args) { + // Illustrates the rule 1. The Fish.swim() implementation wins + //"Tuna swims under water" output is suspected here + new Tuna().swim(); + + // Illustrates the rule 2. The Diveable.swim() implementation wins + //"I can swim on a water surface" output is suspected here + new Duck().swim(); + } +} --- /dev/null 2013-09-26 12:31:35.724641065 +0400 +++ new/src/share/demo/extension-methods/MixIn.java 2013-09-27 18:41:00.438187662 +0400 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + */ + + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * The example illustrates how we can use default method for mix in + * + * @see MixClass + * @see Debuggable + * @see Equalable + * @see Hashable + */ +public class MixIn { + + /** + * Implement this interface for class that needs in debug print + */ + public interface Debuggable { + + /** + * Print the class name and all data members to string. Reflection is + * used for it. + * + * @return the string formatted like below:
+         * State of the: <Class Name>
+         * <member name> : <value>
+         * ...
+         * 
+ */ + default String toDebugString() { + StringBuilder sb = new StringBuilder(); + sb.append("State of the: ").append(this.getClass().getSimpleName()).append("\n"); + for (Class cls = this.getClass(); cls != null; cls = cls.getSuperclass()) { + for (Field f : cls.getDeclaredFields()) { + try { + f.setAccessible(true); + sb.append(f.getName()).append(" : ").append(f.get(this)).append("\n"); + } catch (IllegalAccessException e) { + } + } + } + return sb.toString(); + } + } + + public interface Equalable { + + /** + * Indicates whether some other object is "equal to" this one. Uses + * reflection to access to data members. Two objects equal if all them + * members (except members from #excludeFields list) are equal. + * + * @param obj object to compare + * @param excludeFields the values of these fields don't affect to the + * return value + * @return {@code true} if this object is the same as the obj argument; + * {@code false} otherwise. + */ + default boolean equalsReflect(Object obj, String... excludeFields) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Set excludes = new HashSet<>(Arrays.asList(excludeFields)); + for (Class cls = this.getClass(); cls != null; cls = cls.getSuperclass()) { + for (Field f : cls.getDeclaredFields()) { + if (excludes.contains(f.getName())) { + break; + } + try { + f.setAccessible(true); + Object thisFieldVal = f.get(this); + Object oFieldVal = f.get(obj); + if (thisFieldVal != null) { + if (!thisFieldVal.equals(oFieldVal)) { + return false; + } + } else if (oFieldVal != null) { + return false; + } + } catch (IllegalAccessException e) { + } + } + } + return true; + } + } + + public interface Hashable { + + /** + * Returns a hash code value for the object. This method uses reflection + * to access to object's data members. Hash code is calculated on + * members hash codes. + * + * @param excludeFields the values of these fields don't affect to the + * return value + * + * @return a hash code value for this object. + */ + default int hashCodeReflect(String... excludeFields) { + int result = 0; + Set excludes = new HashSet<>(Arrays.asList(excludeFields)); + for (Class cls = this.getClass(); cls != null; cls = cls.getSuperclass()) { + for (Field f : cls.getDeclaredFields()) { + if (excludes.contains(f.getName())) { + break; + } + try { + f.setAccessible(true); + Object val = f.get(this); + result = 31 * result + val.hashCode(); + } catch (IllegalAccessException e) { + } + } + } + return result; + } + } + + /** + * Sample class to demonstrate mixin. This class inherit behavior of the + * {@link Debuggable}, {@link Equalable}, {@link Hashable} + */ + public static class MixClass implements Debuggable, Equalable, Hashable { + + private final int n = 28; + private final String strHello = "Hello world"; + + /** + * Use default method from {@link Equalable} to check equals + */ + @Override + public boolean equals(Object o) { + return equalsReflect(o); + } + + /** + * Use default method from {@link Hashable} to calculate hash code + */ + @Override + public int hashCode() { + return hashCodeReflect(); + } + } + + public static void main(String args[]) throws IOException { + MixClass a = new MixClass(); + MixClass b = new MixClass(); + System.out.println(a.toDebugString()); + System.out.println(a.equals(b)); + } +} --- /dev/null 2013-09-26 12:31:35.724641065 +0400 +++ new/src/share/demo/extension-methods/Reflection.java 2013-09-27 18:41:00.838387678 +0400 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + */ + + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; + +/** + * The code sample illustrates changes in reflection API linked + * default methods. Since Java SE 8, a new method is added into class + * java.lang.reflect.Method, with which we could + * reflectively determine if a method is a default method provided by an + * interface or not (Method.isDefault()). + */ +public class Reflection { + + /** Base interface to illustrate new reflection API. + * + * @see Dog + */ + public interface Animal { + + default void eat() { + System.out.println(this.getClass().getSimpleName() + " eats like an ordinary animal"); + } + + default void sleep() { + System.out.println(this.getClass().getSimpleName() + " sleeps like an ordinary animal"); + } + + void go(); + } + + /** + * Dog class to illustrate new reflection API. We can see that: + *
    + *
  • the {@link #go} and {@link #sleep} methods are not default. + * {@link #go} has not default implementation and {@link #sleep} method + * implementation wins as subtype (according with {@link Inheritance} rule + * 2)
  • + *
  • the {@link #eat} is a simple default method that not overridden + * in this class. + *
  • + *
+ */ + public static class Dog implements Animal { + + @Override + public void go() { + System.out.println("Dog walks on four legs"); + } + + @Override + public void sleep() { + System.out.println("Dog sleeps"); + } + } + + public static void main(String[] args) throws NoSuchMethodException { + Method[] methods = {Dog.class.getMethod("eat"), Dog.class.getMethod("go"), Dog.class.getMethod("sleep")}; + final Dog dog = new Dog(); + + Arrays.asList(methods).stream().forEach((m) -> { + System.out.println("Method name: " + m.getName()); + System.out.println(" isDefault: " + m.isDefault()); + System.out.print(" invoke: "); + try { + m.invoke(dog); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + } + System.out.println(); + }); + } +} --- /dev/null 2013-09-26 12:31:35.724641065 +0400 +++ new/src/share/demo/extension-methods/SimplestUsage.java 2013-09-27 18:41:01.310623695 +0400 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + */ + + +/** The sample illustrates the simplest use case of the default methods. + * + */ +public class SimplestUsage { + /** Animal interface provides default implementation of the {@link #eat} method + * */ + public interface Animal { + default void eat() { + System.out.println(this.getClass().getSimpleName() + " eats like an ordinary animal"); + } + } + + /** Dog don't have its own implementation of the {@link #eat} method and + * use the default implementation + * */ + public static class Dog implements Animal { + } + + /** Mosquito implements {@link #eat} method, its own implementation override the + * default implementation + * */ + public static class Mosquito implements Animal { + @Override + public void eat() { + System.out.println("Mosquito consumes blood"); + } + } + + public static void main(String[] args) { + new Dog().eat(); // "Dog eats like an ordinary animal" output is suspected here + // + + new Mosquito().eat(); // "Mosquito consumes blood" output is suspected here + } +}