I am practicing to convert java code to Kotlin code:
class TypefaceProvider {
companion object {
private var tmpTypeface = Hashtable<String,Typeface>()
@JvmStatic
fun getTypeface(context : Context, dir : String, name : String) : Typeface {
var createTypeface : Typeface? = tmpTypeface[name]
if(createTypeface == null){
createTypeface = try{
Typeface.createFromAsset(context.assets,"$dir/$name")
} catch (e : Exception){
Log.e(TAG, "fail. msg:${e.message}")
Typeface.DEFAULT
} finally {
tmpTypeface[name] = createTypeface
}
}
return createTypeface <--- wrong, type mismatch
}
}
}
I want to return an non-null typeface object,
I have already checked createTypeface
is not null
.
How to fix the return type mismatch problem?
Should I use return createTypeface!!
or
createTypeface?:Typeface.DEFAULT
(but Typeface.DEFAULT
is duplicate)
or otherwise?
There short answer is -- If you are making sure createTypeface
is truly not null
, returning createTypeface!!
is safe to do. You are asserting something you know to be true. It appears you are doing that, so !!
should work fine in this case.
In general, if you want Kotlin to infer that something is not null
, you need to make sure you never have null as possible value for it. One option for your example is to collapse your null check into a ?:
operator --
class TypefaceProvider {
companion object {
private var tmpTypeface = Hashtable<String, Typeface>()
@JvmStatic
fun getTypeface(context: Context, dir: String, name: String): Typeface {
val createTypeface = tmpTypeface[name] ?: try {
Typeface.createFromAsset(context.assets, "$dir/$name")
} catch (e: Exception) {
Log.e(TAG, "fail. msg:${e.message}")
Typeface.DEFAULT
}
tmpTypeface[name] = createTypeface`
return createTypeface
}
}
}
Note that we had to pull the tmpTypeface[name] = createTypeface
out of the finally
block. It causes your cache to always save a null
value (see @Alexy Romanov's comment below). As an aside, I feel it is better to not have it in the finally block anyway, a side-effect inside a variable assignment seems odd. Also, we don't have to give createTypeface
and explicit type since it can be inferred.
If you want something more readable, you can break the loading/caching logic into a separate method --
class TypefaceProvider {
companion object {
private var tmpTypeface = Hashtable<String, Typeface>()
private fun loadTypeFace(context: Context, dir: String, name: String): Typeface {
val typeface = try {
Typeface.createFromAsset(context.assets, "$dir/$name")
} catch (e: Exception) {
Typeface.DEFAULT
}
tmpTypeface[name] = typeface
return typeface
}
@JvmStatic
fun getTypeface(context: Context, dir: String, name: String) =
tmpTypeface[name] ?: loadTypeFace(context, dir, name)
}
}