Share
Embed
Transcript
38 slides
-
ABOUT ME - VINCENT DUBEDOUT ➤ Started on Android 1.5
with an HTC Hero (2009) ➤ Worked with Cross Platform Xamarin C# ➤ Company ➤ Web&App Agency ➤ Project ➤ Kijiji for Street Objects ➤ Messaging 2 -
FIRST - WHAT’S IDENTITY @Test public void testMonkeyBananaIdentity(){ String object1
= new String("banana"); String object2 = new String("banana"); // Comparison on IDENTITY assertThat(object1 == object2).isFalse(); // Comparison on VALUE assertThat(object1.equals(object2)).isTrue(); // Comparison on IDENTITY String object3 = object2; assertThat(object2 == object3).isTrue(); } 3 -
IMMUTABILITY CONCEPT ➤ Once built, doesn’t change ➤ Thread safe,
cannot be corrupted ➤ Simple to construct, test and use ➤ No need of a copy constructor or clone method ➤ Hashcode can use lazy initialization ➤ Good Map/Set keys 4 -
CONCURRENCY CONTEXT task1.setStartDate(new Date("1 Jan 98"); task2.setStartDate(task1.getTaskDate()); // use task
1 data //then somewhere in the task class void delay(int delayDays) { _startDate.setDate(_startDate.getDate() + delayDays); // somewhere else task2.delay(5); // now you find task1's start date has changed 5 -
IMMUTABLE OBJECTS - CONS ➤ New State = New Object
➤ Garbage collection ➤ Not usable in intensive loops (games etc…) ➤ Painful to write 6 -
WHAT’S A JAVA VALUE TYPE OBJECT ➤ Value Based ➤
Immutable and Final ➤ No Accessible constructors ➤ Don’t allow to change internal mutable objects ➤ No use of identity-sensitive operations ➤ Substitutable when equals 7 -
WHAT’S AUTO VALUE ➤ Released as V1 in January 2015
➤ Current version 1.4.1 ➤ Compatible Java 1.6 ➤ Goal: ➤ Immutable Value Types Generation 8 -
JAVA, CREATING AN IMMUTABLE ➤ New class with 3 variables
- 5 lines public final class Area { private final long longitude; private final long latitude; private final float radius; } 9 -
JAVA, CREATING AN IMMUTABLE ➤ Constructor + 5 lines public
final class Area { private final long longitude; private final long latitude; private final float radius; public Area(long longitude, long latitude, float radius) { this.longitude = longitude; this.latitude = latitude; this.radius = radius; } } 10 -
JAVA, CREATING AN IMMUTABLE ➤ Getters + 9 lines public
final class Area { private final long longitude; private final long latitude; private final float radius; public Area(long longitude, long latitude, float radius) { this.longitude = longitude; this.latitude = latitude; this.radius = radius; } public long getLongitude() { return longitude; } public long getLatitude() { return latitude; } public float getRadius() { return radius; } } 11 -
JAVA, CREATING AN IMMUTABLE ➤ Hashcode + 7 lines @Override
public int hashCode() { int result = (int) (longitude ^ (longitude >>> 32)); result = 31 * result + (int) (latitude ^ (latitude >>> 32)); result = 31 * result + (radius != +0.0f ? Float.floatToIntBits(radius) : 0); return result; } 12 -
JAVA, CREATING AN IMMUTABLE ➤ Equals + 11 lines @Override
public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Area area = (Area) o; if (longitude != area.longitude) return false; if (latitude != area.latitude) return false; if (Float.compare(area.radius, radius) != 0) return false; return true; } 13 -
JAVA, CREATING AN IMMUTABLE ➤ toString + 7 lines @Override
public String toString() { return "Area{" + "longitude=" + longitude + ", latitude=" + latitude + ", radius=" + radius + '}'; } 14 -
JAVA, CREATING AN IMMUTABLE ➤ Bonus: Parcelable + 29 lines
@Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(this.longitude); dest.writeLong(this.latitude); dest.writeFloat(this.radius); } protected Area(Parcel in) { this.longitude = in.readLong(); this.latitude = in.readLong(); this.radius = in.readFloat(); } public static final Creator<Area> CREATOR = new Creator<Area>() { @Override public Area createFromParcel(Parcel source) { return new Area(source); } @Override public Area[] newArray(int size) { return new Area[size]; } }; 15 -
JAVA, CREATING AN IMMUTABLE public final class Area implements Parcelable{
private final long longitude; private final long latitude; private final float radius; public Area(long longitude, long latitude, float radius) { this.longitude = longitude; this.latitude = latitude; this.radius = radius; } public long getLongitude() { return longitude; } public long getLatitude() { return latitude; } public float getRadius() { return radius; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Area area = (Area) o; if (longitude != area.longitude) return false; if (latitude != area.latitude) return false; if (Float.compare(area.radius, radius) != 0) return false; return true; } @Override public int hashCode() { int result = (int) (longitude ^ (longitude >>> 32)); result = 31 * result + (int) (latitude ^ (latitude >>> 32)); result = 31 * result + (radius != +0.0f ? Float.floatToIntBits(radius) : 0); return result; } @Override public String toString() { return "Area{" + "longitude=" + longitude + ", latitude=" + latitude + ", radius=" + radius + '}'; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(this.longitude); dest.writeLong(this.latitude); dest.writeFloat(this.radius); } protected Area(Parcel in) { this.longitude = in.readLong(); this.latitude = in.readLong(); this.radius = in.readFloat(); } public static final Creator<Area> CREATOR = new Creator<Area>() { @Override public Area createFromParcel(Parcel source) { return new Area(source); } @Override public Area[] newArray(int size) { return new Area[size]; } }; } 16 -
JAVA, CREATING AN IMMUTABLE ➤ 73 lines to create a
Value Type Object ➤ 63 lines ➤ that can be generated by Android Studio ➤ that you will change each time you modify the class 17 -
AUTOVALUE LIBRARY @AutoValue public abstract class Area implements Parcelable {
public abstract long latitude(); public abstract long longitude(); public abstract float radius(); public static Area create(long latitude, long longitude, float radius) { return new AutoValue_Area(latitude, longitude, radius); } } ➤ AutoValue_Area Generated at Compile Time 18 -
AUTOVALUE LIBRARY @AutoValue public abstract class Area { public abstract
long latitude(); public abstract long longitude(); public abstract float radius(); public static Builder builder() { return new AutoValue_Area.Builder(); } @AutoValue.Builder public abstract static class Builder { public abstract Builder setLatitude(long latitude); public abstract Builder setLongitude(long longitude); public abstract Builder setRadius(float radius); public abstract Area build(); } } 19 -
AUTOVALUE LIBRARY ➤ Generate Immutable Value Type Object ➤ Generates
all toString, equals, etc ➤ Minimal impact on method count ➤ Can use Builders ➤ Generated class means Debugger is usable ➤ Checks for Null Objects (use @Nullable) ➤ Don’t use mutable objects or wrap them ➤ Awesome documentation 20 -
INSTALLATION (main.gradle) buildscript { repositories { jcenter() } dependencies {
classpath 'com.android.tools.build:gradle:2.3.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } (app.gradle) dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) apt 'com.google.auto.value:auto-value:1.4.1' provided 'com.jakewharton.auto.value:auto-value-annotations:1.4' // apt 'com.squareup:javapoet:1.8.0' } 21 -
PARCELABLE (RYAN HARTER) @AutoValue public abstract class Area implements Parcelable
{ public abstract long latitude(); public abstract long longitude(); public abstract float radius(); public static Area create(long latitude, long longitude, float radius) { return new AutoValue_Area(latitude, longitude, radius); } } Installation apt ‘com.ryanharter.auto.value:auto-value-parcel:0.2.5' https://github.com/rharter/auto-value-parcel 23 -
WITHER (GABRIEL ITTNER) @AutoValue public abstract class Area { public
abstract long latitude(); public abstract long longitude(); public abstract float radius(); public abstract Area withLatitude(long latitude); } Installation apt 'com.gabrielittner.auto.value:auto-value-with:1.0.0' https://github.com/gabrielittner/auto-value-with 24 -
AUTOVALUE-REDACTED (SQUARE) @Retention(RetentionPolicy.SOURCE) @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) public @interface Redacted {
} @AutoValue public abstract class Area { public abstract long latitude(); public abstract long longitude(); @Redacted public abstract float radius(); public static Area create(long latitude, long longitude, float radius) { return new AutoValue_Area(latitude, longitude, radius); } } E/AUTOVALUE: Redacted message, Area{latitude=75, longitude=75, radius=██} ➤ Installation apt 'com.squareup.auto.value:auto-value-redacted:1.0.1' ➤ https://github.com/square/auto-value-redacted -
AUTOVALUE-GSON (RYAN HARTER) @AutoValue public abstract class Area { @SerializedName("latitude")
public abstract long latitude(); @SerializedName("longitude") public abstract long longitude(); @SerializedName("radius") public abstract float radius(); public static TypeAdapter<Area> typeAdapter(Gson gson) { return new AutoValue_Area.GsonTypeAdapter(gson); } } Installation apt 'com.ryanharter.auto.value:auto-value-gson:0.4.6' provided 'com.ryanharter.auto.value:auto-value-gson:0.4.6' https://github.com/rharter/auto-value-gson 26 -
AUTOVALUE-GSON (RYAN HARTER) @GsonTypeAdapterFactory public abstract class MyAdapterFactory implements TypeAdapterFactory
{ public static TypeAdapterFactory create() { return new AutoValueGson_MyAdapterFactory(); } } Gson gson = new GsonBuilder() .registerTypeAdapterFactory(MyAdapterFactory.create()) .create(); new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create(gson)) 27 -
AUTOVALUE-GSON - SPEED TEST public static String DUMMY_JSON = "[\n"
+ " {\n" + " \"_id\": \"576869ed835bc5884bf7179e\",\n" + " \"index\": 0,\n" + " \"guid\": \"5f4b447c-4911-4ee2-bdc4-8d71c7f2a6d4\",\n" + " \"picture\": \"http://placehold.it/32x32\",\n" + " \"age\": 31,\n" + " \"eyeColor\": \"green\",\n" + " \"name\": \"Gwendolyn Riggs\",\n" + " \"gender\": \"female\",\n" + " \"company\": \"XOGGLE\",\n" + " \"email\": \"[email protected]\",\n" + " \"phone\": \"+1 (983) 458-3698\",\n" + " \"address\": \"923 Calyer Street, Toftrees, Oklahoma, 2959\",\n" + " \"about\": \"Consectetur dolor sit duis laboris incididunt non ex qui. Dolore cillum Lorem consectetur consequat sint id amet ullamco pariatur irure. Elit amet eu occaecat qui ad. Ex amet mollit commodo reprehenderit eiusmod. Laboris ad irure consectetur eiusmod excepteur tempor consequat incididunt mollit aliquip consectetur nulla.\ \r\\n\"\n" + " } 28 -
AUTOVALUE-GSON - SPEED TEST //// code 1 //// long startTimer
= System.currentTimeMillis(); Gson gson = new GsonBuilder().create(); Type type = new TypeToken<ArrayList<UserDetailWithoutAutoValue>>() {}.getType(); for (int i = 0; i < loopNumber; i++) { List<UserDetailWithoutAutoValue> userDetail = gson.fromJson(DummyJsonProvider.DUMMY_JSON, type); } float totalDuration = System.currentTimeMillis() - startTimer; //// code 2 //// long startTimer = System.currentTimeMillis(); Gson gson = new GsonBuilder() .registerTypeAdapterFactory(MyAdapterFactory.create()) .create(); Type type = new TypeToken<ArrayList<UserDetailAutoValued>>() {}.getType(); for (int i = 0; i < loopNumber; i++) { List<UserDetailAutoValued> userDetail = gson.fromJson(DummyJsonProvider.DUMMY_JSON, type); } float totalDuration = System.currentTimeMillis() - startTimer; 29 -
AUTOVALUE-MOSHI (RYAN HARTER) @AutoValue public abstract class Foo { abstract
String bar(); @Json(name="Baz") abstract String baz(); public static JsonAdapter<Foo> jsonAdapter(Moshi moshi) { return new AutoValue_Foo.MoshiJsonAdapter(moshi); } } Moshi moshi = new Moshi.Builder() .add(MyAdapterFactory.create()) .build(); ➤ Installation apt 'com.ryanharter.auto.value:auto-value-moshi:0.4.3' provided 'com.ryanharter.auto.value:auto-value-moshi-annotations:0.4.3' ➤ https://github.com/rharter/auto-value-moshi -
AUTOVALUE-CURSOR (GABRIEL ITTNER) @AutoValue public abstract class Area { public
abstract long latitude(); public abstract long longitude(); @ColumnName("area_radius") public abstract float radius(); public static Area create(Cursor cursor) { return AutoValue_Area.createFromCursor(cursor); } } ➤ Installation apt 'com.gabrielittner.auto.value:auto-value-cursor:1.0.1' compile 'com.gabrielittner.auto.value:auto-value-cursor-annotations:1.0.1' ➤ https://github.com/gabrielittner/auto-value-cursor -
AUTOVALUE-FIREBASE (MATT LOGAN) @AutoValue @FirebaseValue public abstract class Area {
@FirebaseAdapter(LocationAdapter.class) public abstract Location location(); public abstract float radius(); public static Area create(Location location, float radius) { return new AutoValue_Area(location, radius); } public static Area create(DataSnapshot dataSnapshot){ return dataSnapshot.getValue(AutoValue_Area.FirebaseValue.class).toAutoValue(); } public Object toFirebaseValue(){ return new AutoValue_Area.FirebaseValue(this); } } ➤ Add two methods Create and toFirebaseValue ➤ For non default values, use adapters -
AUTOVALUE-FIREBASE ➤ Dumb Location Adapter class LocationAdapter implements TypeAdapter<Location, String>
{ @Override public Location fromFirebaseValue(String value) { String[] split = value.split(";"); Location location = new Location("firebase"); location.setLatitude(Double.parseDouble(split[0])); location.setLongitude(Double.parseDouble(split[1])); return location; } @Override public String toFirebaseValue(Location value) { return value.getLatitude()+";"+value.getLongitude(); } } -
ONE YEAR USING IT ➤ Really easy to work with
➤ Less code written -> less bugs ➤ Easy refactoring and object manipulation ➤ No “Oups I forgot to modify this toString” ➤ Somewhat faster de/serialization ➤ Somewhat slower compile time ➤ Thread safety