dierre
04/13/2018, 2:18 PMclass Car (
val model: String?,
val year: Int,
val required: String
) {
private constructor(builder: Builder) : this(builder.model, builder.year, builder.required)
companion object {
inline fun build(required: String, block: Builder.() -> Unit) = Builder(required).apply(block).build()
}
class Builder(
val required: String
) {
var model: String? = null
var year: Int = 0
fun build() = Car(this)
}
}
so that in kotlin I can do val car = Car.build(required = "") {
model = "X"
year = 120
}
The problem is that in Java then I need to write: Car.Builder builder = new Car.Builder("required");
builder.setModel("X");
builder.build();
to do the same stuff. This is not really readable. So I did something this: class CarJavaFriendly(private val model: String?, private val year: Int) {
private lateinit var required: String
fun withRequired(b: String) = this.apply { required = b }
fun execute() {
tryExecute { someFunction() } }
}
private fun <B> tryExecute(f: () -> B): B = try {
f()
} catch (e: UninitializedPropertyAccessException) {
val msg = e.message?.replace("lateinit property ", "") ?: "a property has not been initialized"
throw ValueRequiredException(msg)
}
}
so that in java you can write CarJavaFriendly carJavaFriendly =
new CarJavaFriendly("X", 1)
.withRequired("x")
.execute(somefunction());
so that I can exploit lateInit to check if a parameter which is required, it’s actually initialized. Do you think is there a better approach when it comes to writing API which are readable for Java as well?kingsley
04/15/2018, 3:09 PMCar car = Car.build("required", (b) -> {
b.model = "X";
b.year = 120;
});