Java8

for Android

at Kyobashi.dex #1

About me

Masaki Ogata

@ogaclejapan

Company

CyberAgent, inc.

と一緒に仕事してます :)

Java8

for Android

Java8

for Android

Java8のようなLibraries

for Android

Lambda Expression

Stream API

Date and Time API

Lambda Expressions

(  int  x ,  int  y  )  ->  x  +  y

Retrolambda

Backport of Java 8's lambda expressions to Java 7, 6 and 5

Gradle Retrolambda Plugin

buildscript {
  repositories {
     mavenCentral()
  }

  dependencies {
     classpath 'me.tatarka:gradle-retrolambda:3.2.2'
  }
}

// Required because retrolambda is on maven central
repositories {
  mavenCentral()
}

apply plugin: 'me.tatarka.retrolambda'

:)

Retrolambda Tips for Android

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_lambda_tips);
    
  /* 型は推論可能であれば省略可、引数は1つのみの場合に限り括弧も省略可 */
  findViewById(R.id.button).setOnClickListener(v -> v.setEnabled(false));

  /* return文は1行表示なら省略可 */
  findViewById(R.id.button).setOnTouchListener((v, event) -> true);

  /* 複数行の場合は{}括弧を省略できない */
  new Thread(() -> {
    // something
  }).start();
  
  /* メソッド参照もできる(staticのメソッド参照はClassName::method) */
  new Thread(this::task).start();
}

void task() {
  // something
}

キタ━━━( ´∀`)・ω・) ゚Д゚)・∀・) ̄ー ̄)´_ゝ`)━━━!!!?

Date and Time API

LocalDate.of( 2015 ,  9 ,  7 ).atTime( 20,  0 )

ThreeTenABP

https://github.com/JakeWharton/ThreeTenABP

An adaptation of the JSR-310 backport for Android.

ThreetenABP Tips for Android

public class MyApplication extends Application {
  @Override public void onCreate() {
    super.onCreate();
    AndroidThreeTen.init(this);
  }
}

/* 日付のみを扱う */
LocalDate d = LocalDate.of(2015, 9, 7);
/* 時間のみを扱う */
LocalTime t = LocalTime.of(20, 0);
/* 日付と時間を扱う */
LocalDateTime dt = LocalDateTime.of(d, t);
/* 秒、ナノ秒の期間を扱う */
Duration du = Duration.between(dt, dt.plusHours(2));
/* 年月日の期間を扱う */
Period p = Period.between(d.withYear(2014), d);
/* 経過時間を扱う */
Instant i = dt.toInstant(ZoneOffset.UTC);
/* 日付/時間の出力および解析を扱う */
String s = d.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

Awesome Sample code

∩゚∀゚∩age

Stream API

list.stream( ).map( s  ->  s.length( ) )

Lightweight Stream API

https://github.com/aNNiMON/Lightweight-Stream-API

Stream API from Java 8 rewrited on iterators for Java 7 and below.

Lightweight Stream API

Functional interfaces

Stream (without parallel processing)

Optional class

Objects from Java 7

Σ(`Д´ )

・Interface : 14 files

・Class : 5 files

Lightweight !!

.filter(Predicate<? super T> predicate)
.map(Function<? super T,? extends R> mapper)
.flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
.sorted(Comparator<? super T> comparator)
.limit(long maxSize)
.skip(long n)

Supported Stream APIs

.peek(Consumer<? super T> action)
.forEach(Consumer<? super T> action)
.reduce(BiFunction<T, T, T> accmulator)
.min(Comparator<? super T> comparator)
.max(Comparator<? super T> comparator)
.allMatch(Predicate<? super T> predicate)
etc..

Supported Stream APIs

Stream Tips for Android

/* 初期値をStreamで作る */
final List<User> users = Stream.ofRange(1, 99)
    .map(i -> new User("Name" + i, i))
    .collect(Collectors.toList());

/* ResponseからUserリストをStreamに変形して10代のユーザのみを抽出した名前のリストを返す */
private List<String> getTeenagers(Response response) {
  return Stream.of(response)
      .flatMap(res -> Stream.of(res.users()))
      .filter(user -> 12 < user.age && user.age < 20)
      .sorted((user1, user2) -> Integer.compare(user1.age, user2.age))
      .map(user -> user.name)
      .collect(Collectors.toList());
}

public static class User {
  public final String name;
  public final int age;
  public User(String name, int age) {
    this.name = name;
    this.age = age;
  }
}

One more thing...

Optional<T>

A container object which may or may not contain a non-null value. 

Optional Tips for Android

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_showcase);

  Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
  setSupportActionBar(toolbar);

  /* @NullableなメソッドにはOptionalで対抗する */
  Optional.ofNullable(getActionBar()).ifPresent(ab -> {
    ab.setTitle("Kyobashi.dex #1");
    ab.setDisplayHomeAsUpEnabled(true);
  });
}

private final WeakReference<KyobashiActivity> activityRef;

public void handle() {
  Optional.ofNullable(activityRef.get())
      .filter(act -> !act.isFinishing())
      .ifPresent(KyobashiActivity::something);
}

Let's hava fun

:)