I am new to kotlin and I am facing this issue
I have an ArrayList<String?> and I have to pass it to a function that accepts List<CharSequence>
I tried to find a way to convert them but couldnt, How can I convert ArrayList<String?> to List<CharSequence> in kotlin
Use
val list: List<CharSequence> = arrayList.filterNotNull()
filterNotNull() removes any possible null values so you have a List<String>, which can be automatically up-cast to a List<CharSequence>.
CharSequence is an interface and String class is already implemented that. Hence cast to CharSequence should be enough. map function returns List<T>
val list = arrayList.map { it as CharSequence }
With filtering null values
val list: List<CharSequence> = arrayList.filterNotNull()
Related
I have a model class containing Long and Int properties and I am using Moshi Library to parse a json string into this class.
data class Adjust (
var appId: String?,
var clicks: Long?,
var count: Int?)
If I parse a json like this {"appId":"1", "clicks":""}, I get an error Expected a long but was at path $.clicks
Same thing happens for the Int field.
What can I do short of adding two custom adapters so that the blank strings are parsed as null and do not error out?
The custom adapter I wrote is like this:
object EmptyStringToNullAdapter {
#FromJson
fun fromJson(string: String) = string.toLongOrNull()
#ToJson
fun toJson(value: Long) = value.toString()
}
This works but I have to write another similar one for Int and maybe in future if other numerical fields are added, more such adapters! What is the better approach here?
Incidentally, I have an Enumeration<String> in Kotlin. It contains toList(), but I need to convert it to an Array<String>.
What is the best way to do this in Kotlin?
Lists can be converted to arrays via the .toTypeArray function:
val myEnumeration: Enumeration<String> = ...
val array = myEnumeration.toList().toTypedArray() // array is Array<String>
A simple extension function as a shortcut is also trivial:
inline fun <reified T> java.util.Enumeration<T>.toTypedArray(): Array<T> = toList().toTypedArray()
The reason toTypedArray() doesn't work directly on an Enumeration is that it needs a Collection<T> to be able to efficiently instantiate the new array, but going through toList() first is still efficient enough for most scenarios.
I am trying to create List<Char> from String in Kotlin but it seems there is no inbuilt function is provided by lib. Also casting will generate error. So here is what I am doing. Please let me know if I am missing something in question. (Or we can say converting string to List<Char> in Kotlin).
var stringVal = "ABC"
var genList:List<Char> = arrayListof()
var count = 0
while (stringVal.length == genList.size) {
// way to add stringVal to genList
count++
}
The answer given by #Moira is definitely the way to go here, I would accept it.
However, the question was about adding an element to a List<Char>, which isn't possible in Kotlin because a List is immutable and yours gets initialized as an empty one, so it will stay empty.
Use a MutableList<Char> and simply add single Chars to it if you need it:
fun main(args: Array<String>) {
var genList = mutableListOf<Char>()
genList.add('a')
genList.add('A')
genList.add('B')
genList.add('C')
println(genList)
}
Output:
[a, A, B, C]
val chars = "ABC".toList()
CharSequence has a to(Mutable)List extension function defined in kotlin.text.
fun CharSequence.toList(): List<Char>
Returns a List containing all characters.
kotlin-stdlib / kotlin.text / toList
fun CharSequence.toMutableList(): MutableList<Char>
Returns a MutableList filled with all characters of this char sequence.
kotlin-stdlib / kotlin.text / toMutableList
Kotlin's standard libraries have hundreds of utility functions like this, so chances are that most of the time what you want already exists.
Many standard types that conceptually model some sort of iterable data, but are not Iterable, have extensions defined on them that are equivalent to those in kotlin.collections.
Does the fact that this doesn't compile mean that they're not quite first class types?
fun foo(s: String): Int = s.length
// This won't compile.
val bar = foo
Is there a way to do this without resorting to OO?
Does the fact that this doesn't compile mean that they're not quite first class types?
No, it doesn't.
In Kotlin, to reference a function or a property as a value, you need to use callable references, but it is just a syntax form for obtaining a value of a function type:
fun foo(s: String): Int = s.length
val bar = ::foo // `bar` now contains a value of a function type `(String) -> Int`
Once you get that value, you are not limited in how you work with it, which is what first-class functions are about.
You can use reference to the function :::
fun foo(s: String): Int = s.length
val bar = ::foo
And then invoke it:
bar("some string")
Given this data class:
data class MyPojo(val notInJson: Int, val inJson: Int)
Assume I want to implement a function of the form:
fun deserialize(jsonString: String, valueForFieldNotInJson: Int): MyPojo
Where jsonString does not include a field named notInJson. Assume also, that I have no control over MyPojo class definition.
How could I use Jackson library to deserialize MyPojo from jsonString and augment the missing field (notInJson) from valueForFieldNotInJson parameter?
Notes:
Basically, the question is about deserializing a Immutable class, where some fields come from Json and others are supplied at runtime.
Using custom deserializers or builders will not work because missing values are unknow at compile time.
This can be achieved by combining MinInAnnotations and ValueInjection.
Complete solution as follows:
data class MyPojo(val notInJson: Int, val inJson: Int)
class MyPojoMixIn {
#JacksonInject("notInJson") val notInJson: Int = 0
}
fun deserialize(jsonString: String, valueForFieldNotInJson: Int): MyPojo {
val injectables = InjectableValues.Std().addValue("notInJson", valueForFieldNotInJson)
val reader = jacksonObjectMapper()
.addMixIn(MyPojo::class.java, MyPojoMixIn::class.java)
.readerFor(MyPojo::class.java)
.with(injectables)
return reader.readValue(jsonString)
}