Java 8 on Android

Java 8 on Android

Video: https://skillsmatter.com/skillscasts/8696-java-8-on-android

Java 8 features have finally made their way to the Android world and if you haven't been trying them, you are missing out. This talk is all about getting you up to speed on all of these new features and how to use them. It will be a great primer if you've never looked into them or a refresher if it's been a while.

E59595853b7c88a88b0300bdcc226302?s=128

Alex Florescu

October 26, 2016
Tweet

Transcript

  1. 2.

    Outline • Backward compatible features • Lambdas, method references etc.

    • Android N+ only features • Streams, default methods etc. • Setup: how to get this working • Other useful tidbits and analysis
  2. 5.

    API support • Official website
 “Also available on API level

    23 and lower” • Google I/O 2016
 “Backward compatible with Gingerbread”
  3. 8.

    Functional interface • Has exactly one abstract method • Can

    annotate with @FunctionalInterface • Not necessary for using lambdas with it
  4. 10.

    Functional interface • A lot of standard ones added in

    java.util.function • Consumer<T> — an operation that accepts a single input argument and returns no result • Function<T,R> — a function that accepts one argument and produces a result • Predicate<T> — a predicate (boolean-valued function) of one argument • Supplier<T> — a supplier of results
  5. 13.

    Setting listener button1.setOnClickListener(new View.OnClickListener() {
 @Override public void onClick(View v)

    {
 Snackbar.make(mainPanel, "Click listener
 triggered", Snackbar.LENGTH_SHORT).show();
 }
 });
  6. 14.

    Setting listener button1.setOnClickListener(new View.OnClickListener() {
 @Override public void onClick(View v)

    {
 Snackbar.make(mainPanel, "Click listener
 triggered", Snackbar.LENGTH_SHORT).show();
 }
 });
  7. 18.

    Example with params participantRedList.setAdapter(
 new ParticipantAdapter(
 
 filterParticipants(participants,
 new FilterCondition<Participant>()

    {
 @Override
 public boolean accept(Participant candidate) {
 return candidate.getTeamColour() == TeamColour.RED;
 }
 })));
  8. 19.

    Example with params participantRedList.setAdapter(
 new ParticipantAdapter(
 
 filterParticipants(participants,
 new FilterCondition<Participant>()

    {
 @Override
 public boolean accept(Participant candidate) {
 return candidate.getTeamColour() == TeamColour.RED;
 }
 })));
  9. 20.

    Example with params participantRedList.setAdapter(
 new ParticipantAdapter(
 
 filterParticipants(participants,
 new FilterCondition<Participant>()

    {
 @Override
 public boolean accept(Participant candidate) {
 return candidate.getTeamColour() == TeamColour.RED;
 }
 })));
  10. 23.

    Syntax p -> p.getAge() >= 18 (a,b) -> a.getAge() <

    b.getAge() () -> Timber.d(“Ping”) (p) -> {
 Timber.d(“Participant age : %d”, p.getAge());
 return p.getAge() < 18;
 }
  11. 24.

    Syntax p -> p.getAge() >= 18 (a,b) -> a.getAge() <

    b.getAge() () -> Timber.d(“Ping”) (p) -> {
 Timber.d(“Participant age : %d”, p.getAge());
 return p.getAge() < 18;
 }
  12. 25.

    Syntax p -> p.getAge() >= 18 (a,b) -> a.getAge() <

    b.getAge() () -> Timber.d(“Ping”) (p) -> {
 Timber.d(“Participant age : %d”, p.getAge());
 return p.getAge() < 18;
 }
  13. 26.

    Syntax p -> p.getAge() >= 18 (a,b) -> a.getAge() <

    b.getAge() () -> Timber.d(“Ping”) (p) -> {
 Timber.d(“Participant age : %d”, p.getAge());
 return p.getAge() < 18;
 }
  14. 29.

    Example 
 Collections.sort(participants, new Comparator<Participant>() {
 @Override
 public int compare(Participant

    p1, Participant p2) {
 return Integer.compare(p1.getAge(), 
 p2.getAge());
 }
 });
  15. 31.

    Example public final class Participant {
 ….
 public static int

    compareByAge(Participant a, 
 Participant b) {
 return Integer.compare(a.getAge(), b.getAge());
 }
 ….
 }
  16. 32.

    Example public final class Participant {
 ….
 public static int

    compareByAge(Participant a, 
 Participant b) {
 return Integer.compare(a.getAge(), b.getAge());
 }
 ….
 }
  17. 33.
  18. 36.

    From 
 Collections.sort(participants, new Comparator<Participant>() {
 @Override
 public int compare(Participant

    p1, Participant p2) {
 return Participant.compareByAge(p1,p2);
 }
 });
  19. 39.
  20. 43.

    Syntax • Reference to an instance method of a particular

    object (o) -> o.toString() o::toString
  21. 44.

    Syntax • Reference to an instance method of an arbitrary

    object of a particular type Arrays.sort((a,b) -> a.compareToIgnoreCase(b))
  22. 45.

    Syntax • Reference to an instance method of an arbitrary

    object of a particular type Arrays.sort((a,b) -> a.compareToIgnoreCase(b)) Arrays.sort(String::compareToIgnoreCase)
  23. 46.

    Syntax • Reference to an instance method of an arbitrary

    object of a particular type Arrays.sort((a,b) -> a.compareToIgnoreCase(b)) Arrays.sort(String::compareToIgnoreCase)
  24. 52.
  25. 55.

    Annotations before Java 8 • Method: @Override void onCreate()… •

    Class: 
 @RunWith(JUnit4Runner.class) 
 public class TestDoggieTreats {… • Parameters, return values
 @NonNull String prepareText(@Nullable input);
  26. 56.

    Type annotations • Anywhere you use a type • Class

    instantiation: new @Interned MyObject(); • Type cast: myString = (@NonNull String) str; • Implements clause: class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... } • Throws: void monitorTemperature() throws @Critical TemperatureException { ... }
  27. 57.

    Type annotations • Anywhere you use a type • Class

    instantiation: new @Interned MyObject(); • Type cast: myString = (@NonNull String) str; • Implements clause: class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... } • Throws: void monitorTemperature() throws @Critical TemperatureException { ... }
  28. 62.

    Streams Data manipulation like you always dreamed of. Can filter,

    map & reduce while being traversed, sequentially or in parallel.
  29. 63.

    Example public interface FilterCondition<T> {
 boolean accept(T candidate);
 }
 List<Participant>

    filter(List<Participant> 
 participants, 
 FilterCondition<Participant> 
 filterCondition)
  30. 64.

    Example List<Participant> output = new ArrayList<>();
 
 for (Participant participant

    : participants) {
 if (filterCondition.accept(participant)) {
 output.add(participant);
 }
 }
 
 return output;

  31. 82.

    Streams are lazy • The intermediate operations are always lazy

    • The “terminal” operations produce values or side- effects
  32. 91.

    Default methods • How to build “streams” without breaking all

    custom collections? • Collection interface adds: • boolean removeIf(Predicate<? super E> filter) • Spliterator<E> spliterator() • Stream<E> stream() • Stream<E> parallelStream()
  33. 92.

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

    default Spliterator<E> spliterator() • default Stream<E> stream() • default Stream<E> parallelStream()
  34. 93.

    Default methods Enables you to add new (default) implementations to

    interfaces so implementing classes don’t need to change
  35. 94.

    Collection @Override
 default Spliterator<E> spliterator() {
 return Spliterators.spliterator(this, 0);
 }


    default Stream<E> stream() {
 return StreamSupport.stream(spliterator(), false);
 }
  36. 95.

    Implementing classes • When you implement an interface that contains

    a default method, you can do the following: • Not mention the default method at all, which lets your implementation use the default method • Override the default method • Reuse the default method implementation using super
  37. 96.

    Implementing classes • Not mention the default method at all,

    which lets your implementation use the default method
  38. 97.

    Implementing classes • Not mention the default method at all,

    which lets your implementation use the default method class FancyList<E> implements Collection<E>
  39. 99.

    Implementing classes • Override the default method class FancyList<E> implements

    Collection<E> @Override
 public Stream<E> stream() {
 return ….. 
 }
  40. 101.

    Implementing classes • Reuse the default method implementation using super

    class FancyList<E> implements Collection<E> @Override
 Stream<E> stream() {
 // ……
 return super.stream();
 }
  41. 102.

    Extending interface • When you extend an interface that contains

    a default method, you can do the following: • Not mention the default method at all, which lets your extended interface inherit the default method • Redeclare the default method, which makes it abstract • Redefine the default method, which overrides it
  42. 103.

    Extending interface • Not mention the default method at all,

    which lets your extended interface inherit the default method
  43. 104.

    Extending interface • Not mention the default method at all,

    which lets your extended interface inherit the default method interface Set<E> extends Collection<E> {
 ….
 }
  44. 106.

    Extending interface • Redeclare the default method, which makes it

    abstract
 
 interface FancySet<E> extends Collection<E> {
 ….
 Stream<E> stream();
 }
  45. 108.

    Extending interface • Redefine the default method, which overrides it

    interface Set<E> extends Collection<E> {
 ….
 @Override default Spliterator<E> spliterator() {
 return Spliterators.spliterator(this, Spliterator.DISTINCT);
 }
 }
  46. 109.

    Multiple inheritance? public interface A {
 default void foo() {


    Timber.d(“Calling A.foo()");
 }
 }
 
 
 
 
 
 
 public class ProblematicClass implements A, B {
 //…..
 } public interface B {
 default void foo() {
 Timber.d(“Calling B.foo()");
 }
 }
  47. 110.

    Multiple inheritance? public interface A {
 default void foo() {


    Timber.d(“Calling A.foo()");
 }
 }
 
 
 
 
 
 
 public class ProblematicClass implements A, B {
 //…..
 } public interface B {
 default void foo() {
 Timber.d(“Calling B.foo()");
 }
 }
  48. 111.

    Multiple inheritance public class ProblematicClass implements A, B { }

    // error: class ProblematicClass inherits unrelated defaults for foo() from types A and B
  49. 112.

    Multiple inheritance public class ProblematicClass implements A, B { }

    // error: class ProblematicClass inherits unrelated defaults for foo() from types A and B
  50. 114.

    Multiple inheritance public class ProblematicClass implements A, B { @Override

    public void foo() { A.super.foo(); B.super.foo(); } }
  51. 115.

    Instances methods vs default methods public class Horse { public

    String identifyMyself() { return "I am a horse."; } } public interface Flyer { default public String identifyMyself() { return "I am able to fly."; } } public interface Mythical { default public String identifyMyself() { return "I am a mythical creature."; } } public class Pegasus extends Horse implements Flyer, Mythical { public static void main(String... args) { Pegasus myApp = new Pegasus(); System.out.println(myApp.identifyMyself()); } }
  52. 116.

    Instances methods vs default methods public class Horse { public

    String identifyMyself() { return "I am a horse."; } } public interface Flyer { default public String identifyMyself() { return "I am able to fly."; } } public interface Mythical { default public String identifyMyself() { return "I am a mythical creature."; } } public class Pegasus extends Horse implements Flyer, Mythical { public static void main(String... args) { Pegasus myApp = new Pegasus(); System.out.println(myApp.identifyMyself()); } }
  53. 117.

    Instances methods vs default methods public class Horse { public

    String identifyMyself() { return "I am a horse."; } } public interface Flyer { default public String identifyMyself() { return "I am able to fly."; } } public interface Mythical { default public String identifyMyself() { return "I am a mythical creature."; } } public class Pegasus extends Horse implements Flyer, Mythical { public static void main(String... args) { Pegasus myApp = new Pegasus(); System.out.println(myApp.identifyMyself()); } }
  54. 118.

    Instances methods vs default methods public class Horse { public

    String identifyMyself() { return "I am a horse."; } } public interface Flyer { default public String identifyMyself() { return "I am able to fly."; } } public interface Mythical { default public String identifyMyself() { return "I am a mythical creature."; } } public class Pegasus extends Horse implements Flyer, Mythical { public static void main(String... args) { Pegasus myApp = new Pegasus(); System.out.println(myApp.identifyMyself()); } }
  55. 119.

    Instances methods vs default methods public class Horse { public

    String identifyMyself() { return "I am a horse."; } } public interface Flyer { default public String identifyMyself() { return "I am able to fly."; } } public interface Mythical { default public String identifyMyself() { return "I am a mythical creature."; } } public class Pegasus extends Horse implements Flyer, Mythical { public static void main(String... args) { Pegasus myApp = new Pegasus(); System.out.println(myApp.identifyMyself()); } }
  56. 120.

    Instances methods vs default methods • Instance methods are preferred

    over interface default methods • The method Pegasus.identifyMyself returns the string I am a horse.
  57. 121.

    Static methods • Comparator gains:
 
 public static <T extends

    Comparable<? super T>> Comparator<T> reverseOrder() {
 return Collections.reverseOrder();
 }
  58. 125.

    How-to • Declare the annotation as repeatable • Declare a

    containing annotation type • See: https://docs.oracle.com/javase/tutorial/java/ annotations/repeating.html
  59. 129.

    Requirements • This applies for all Java 8 features •

    Requirements: • Use Jack & Jill • Set language compatibility • Android Studio 2.1+ • Build tools 21.1.1+
  60. 130.

    A bit about Jack • Jack is a new Android

    toolchain • Compiles Java source into Android dex bytecode • Replaces the previous toolchain • javac, ProGuard, jarjar, dx etc.
  61. 135.

    Annotation processor • If you’re using Dagger, Butterknife etc. apply

    plugin: 'com.neenbedankt.android-apt'
 apt 'com.google.dagger:dagger-compiler:2.2'
  62. 138.

    Known issues • Jack does not generate intermediate class files

    when compiling an app, so it breaks some tools • Instant run doesn’t work with Jack • Lint that operates on class files • JaCoCo instrumentation (now fixed) • Possible Kotlin issues
  63. 139.

    Known issues • Updated list: https://source.android.com/source/ known-issues.html • The one

    under Java 8 features doesn’t seem to be updated • File bugs: http://tools.android.com/filing-bugs
  64. 140.
  65. 141.

    Links — Lambdas • Many lambda examples: docs.oracle.com/javase/ tutorial/java/javaOO/lambdaexpressions.html •

    Lambda tutorial: https://github.com/ AdoptOpenJDK/lambda-tutorial • Official docs on Streams: http://docs.oracle.com/ javase/tutorial/collections/streams/ • Streams tutorial: http://blog.hartveld.com/2013/03/ jdk-8-33-stream-api.html
  66. 142.

    Other talks • Exploring Java’s Hidden Costs (@JakeWharton) • Jack

    and Jill build system (Eric Lafortune) • API Design With Java 8 Lambda and Streams (@stuartmarks & @BrianGoetz)