Assume I have a data class:
data class SensorData(val name: String, val temp : Double)
I create this SensorData object from either an REST service or by internal setter method, whereas name is always populated and temp might be empty.
Further on, I need this SensorData object through several classes, thats I thought of using a singleton.
Obviously I need object keyword as described here, but how can I combine data class object ?
You can use companion object to keep a reference to your data object:
data class SensorData(val name: String, var temp : Double) {
companion object {
#Volatile
#JvmStatic
private var INSTANCE: SensorData? = null
#JvmStatic
#JvmOverloads
fun getInstance(name: String = "default", temp : Double = 0.0): SensorData = INSTANCE ?: synchronized(this) {
INSTANCE ?: SensorData(name, temp).also { INSTANCE = it }
}
}
}
And use it like this:
val name1 = SensorData.getInstance("name", 5.0).name
// Or with default values:
val name2 = SensorData.getInstance().name
I think you got the concept of a Singleton wrong:
"The singleton pattern is a software design pattern that restricts the instantiation of a class to one "single" instance"
It is not only meant to be used to make it public to all classes, but to limit the number of instances.
A data class is a class to store data, why should it be a Singleton?
Rethink your architecture to make it accessible where you need it.
Don't use a data class as a singleton. That's not what they are designed for. A better approach would be to create a wrapper object around your data class, which handles your SensorData-Object(s). This will also allow you to use multiple SensorData objects (maybe needed in future) or replace the current one with a new one if you poll the REST-Service a second time.
object SensorDataService {
var sensorData: SensorData? = null
}
data class SensorData(val name: String, val temp : Double)
In my opinion, you should rethink your architecture as data class is used to store data so why it should be a singleton? It is not only meant to be used to make it public to all classes but to limit the number of instances.
Related
I have a Java class that holds generic information on databse entities (i.e. their id).
#Data
public class DbEntity {
protected final String id;
public DbEntity(String id) {
this.id = id;
}
}
We use Lombok #Data to generate getters, toString, equals...
In Java I would simply extend this class and add #Data once again.
#Data
class JavaSubClass extends DbEntity {
public JavaSubClass(String id) {
super(id);
}
}
In a newer service we use Kotlin but would like to reuse standard classes such as DbEntity.
My first approach was to simply declare a data class such as
data class SubClass1(val id: String, val name: String) : DbEntity(id)
Accidental override: The following declarations have the same JVM signature (getId()Ljava/lang/String;):
fun <get-id>(): String defined in com.demo.SubClass1
fun getId(): String! defined in com.demo.SubClass1
After some reading I found several solutions, all of which I'm not super happy with.
Don't use data classes. This works but leaves me with the task of implementing equals etc.
class SubClass4(id: String, val name: String) : DbEntity(id)
Duplicate the field. This works but we end up with two fields that could go out of sync.
data class SubClass3(val subId: String, val name: String) : DbEntity(subId)
Assign a different name to the getter. This fundamentally also duplicates the field, but hides the getter.
data class SubClass2(#get:JvmName("getId_") val id: String, val name: String) : DbEntity(id)
As I said, I'm not happy with any of the solution presented above. Having an abstract super class or an interface instead would certainly be more appropriate. However the Entity class resides in a library that primarily Java projects depend on. I'm hesitant to change it just because of a new Kotlin dependnecy.
Did anyone encounter similar issues and has advice on how to solve them?
As a workaround, until KT-6653 - Kotlin properties do not override Java-style getters and setters is fixed, I would go for a variant of your point 3, i.e.:
data class SubClass(#get:JvmName("bogusId") private val id: String, val name: String) : DbEntity(id)
The benefit of this variant is, that you always access the "original" getId-function. You will not use the bogusId()-function as it is not visible/accessible (accessing it via reflection makes no sense... you are only interested in the actual id-field). This works and looks similar for both sides: from Java as also from Kotlin. Still, under the hood this variant uses 2 fields, but in the best case you can just replace it in future with something like:
data class SubClass(override val id: String, val name : String) : DbEntity(id)
I am developing a simple Android app, that will display an icon of a vehicle and the user can click on the icon to display the vehicle information. I want to load the data dynamically when I build the app i.e. the data will come from an external source including the picture for the icon.
I am new to Kotlin and not sure what to search for to understand a suitable solution. What is the correct way to define the data, is it best to create an class as below then create an array of the class (not sure if this is possible)
public class VehicleSpec()
{
var OEM: String? = null
var ModelName: String? = null
var EngineSize: String? = null
}
Or would be better to create a multiple dimension array and then link the data to the cells?
var VehicleSpec = arrayOf(20,20)
VehicleSpec[0][0] = Null //OEM
VehicleSpec[0][1] = Null //ModelName
VehicleSpec[0][2] = Null //EngineSize
What is the best way to set up the data storage, is there any good references to understand how this should be setup?
What is the correct way to define the data, is it best to create an class as below then create an array of the class
Using an array for the properties of an object is not making the full use of the type safety you have in Kotlin (and even Java for that matter).
If what you want to express is multiple properties of an object, then you should use a class to define those properties. This is especially true if the properties have different types.
There is no performance difference between an array and a class, because you'll get a reference to the heap in both cases. You could save on performance only if you convert your multi-dimensional array approach to a single-dimension array with smart indexing. Most of the time, you should not consider this option unless you are handling a lot of data and if you know that performance is an issue at this specific level.
(not sure if this is possible)
Defining lists/arrays of classes is definitely possible.
Usually, for classes that are only used as data containers, you should prefer data classes, because they give you useful methods for free, and these methods totally make sense for simple "data bags" like in your case (equals, hashcode, component access, etc.).
data class Vehicle(
val OEM: String,
val ModelName: String,
val EngineSize: String
)
Also, I suggest using val instead of var as much as possible. Immutability is more idiomatic in Kotlin.
Last but not least, prefer non-null values to null values if you know a value must always be present. If there are valid cases where the value is absent, you should use null instead of a placeholder value like empty string or -1.
First at all, using the "class aprocah" makes it easy for you to understand and give you the full benefits of the language itself... so dont dry to save data in an array .. let the compiler handle those stuff.
Secondly i suggest you have maybe two types (and use data classes ;-) )
data class VehicleListEntry(
val id: Long,
val name: String
)
and
data class VehicleSpec(
val id: Long,
val oem: String = "",
val modelName: String = "",
val engineSize: String = ""
)
from my perspective try to avoid null values whenever possible.
So if you have strings - which you are display only - use empty strings instead of null.
and now have a Model to store your data
class VehicleModel() {
private val specs: MutableMap<Long, VehicleSpec> = mutableMapOf()
private var entries: List<VehicleListEntry> = listOf()
fun getSpec(id: Long) = specs[id]
fun addSpec(spec: VehicleSpec) = specs[spec.id] = spec
fun getEntries(): List<VehicleListEntry> = entries
fun setEntries(data: List<VehicleListEntry>) {
entries = data.toMutableList()
}
}
You could also use a data class for your model which looks like
data class VehicleModel(
val specs: MutableMap<Long, VehicleSpec> = mutableMapOf(),
var entries: List<VehicleListEntry> = listOf()
)
And last but not least a controller for getting stuff together
class VehicleController() {
private val model = VehicleModel()
init{
// TODO get the entries list together
}
fun getEntries() = model.entries
fun getSpec(id: Long) : VehicleSpec? {
// TODO load the data from external source (or check the model first)
// TODO store the data into the model
// TODO return result
}
}
I have an immutable object:
class Foo(
val name: String,
val things: List<Thing>
)
A third party lib creates the Foo object with some 'null' Thing objects.
I am creating a new object:
val foo = thirdPartyGetFoo()
val filteredFoo = Foo(foo.name, foo.things.filterNotNull())
That works, however AndroidStudio greys out the filterNotNull function call and presents a warning:
Useless call on collection type: The inspection reports filter-like
calls on already filtered collections.
Is this the right way to filter that list? Should I ignore the warning or is there a better way?
You do not specify what library creates the object with nulls. Some deserialization libraries can use static factory methods which you could configure, and then have the factory method strip the null. For example, if this were Jackson you would simply:
class Foo(val name: String, val things: List<Thing>) {
companion object {
#JsonCreator
#JvmName("createFromNullable")
fun create(name: String, things: List<Thing?>) = Foo(name, things.filterNotNull())
fun create(name: String, things: List<Thing>) = Foo(name, things)
}
}
Then...
val goodFoo = jacksonObjectMapper().readValue<Foo>(someJsonWithNulls)
Maybe your library has options that are similar?
If not, and you don't have 100 of these things with this problem, I would probably create a temporary class to hold the results and convert that to the final class:
open class FooNullable(val name: String, open val things: List<Thing?>) {
open fun withoutNulls(): Foo = Foo(name, things.filterNotNull())
}
class Foo(name: String, override val things: List<Thing>) : FooNullable(name, things) {
override fun withoutNulls(): Foo = this
}
Then you can deserialize into FooNullable and just call withoutNulls() to get the other flavor that is clean. And if you accidentally call it on one without nulls already, it just does nothing.
val goodFoo = Foo("", emptyList<Thing>())
val alsoGoodFoo = goodFoo.withoutNulls() // NOOP does nothing
val badFoo = thirdPartyGetFoo()
val betterFoo = badFoo.withoutNulls() // clean up the instance
val safeFoo = thirdPartyGetFoo().withoutNulls() // all at once!
Not the cleanest, but does work. The downsides is this second step, although it looks like you were already planning on doing that anyway. But this model is safer than what you proposed since you KNOW which type of object you have and therefore you continue to be typesafe and have the compiler helping you avoid a mistake.
You don't have to use inheritance as in the above example, I was just trying to unify the API in case there was a reason to have either version in hand and know which is which, and also act upon them in a similar way.
What is the intended meaning of "companion object"? So far I have been using it just to replace Java's static when I need it.
I am confused with:
Why is it called "companion"?
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
To instantly create a singleton instance that is scoped to a class, I often write
:
companion object {
val singleton by lazy { ... }
}
which seems like an unidiomatic way of doing it. What's the better way?
What is the intended meaning of "companion object"? Why is it called "companion"?
First, Kotlin doesn't use the Java concept of static members because Kotlin has its own concept of objects for describing properties and functions connected with singleton state, and Java static part of a class can be elegantly expressed in terms of singleton: it's a singleton object that can be called by the class' name. Hence the naming: it's an object that comes with a class.
Its name used to be class object and default object, but then it got renamed to companion object which is more clear and is also consistent with Scala companion objects.
Apart from naming, it is more powerful than Java static members: it can extend classes and interfaces, and you can reference and pass it around just like other objects.
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes, that's the idiomatic way. Or you can even group them in non-companion objects by their meaning:
class MyClass {
object IO {
fun makeSomethingWithIO() { /* ... */ }
}
object Factory {
fun createSomething() { /* ... */ }
}
}
To instantly create a singleton instance that is scoped to a class, I often write /*...*/ which seems like an unidiomatic way of doing it. What's the better way?
It depends on what you need in each particular case. Your code suits well for storing state bound to a class which is initialized upon the first call to it.
If you don't need it to be connected with a class, just use object declaration:
object Foo {
val something by lazy { ... }
}
You can also remove lazy { ... } delegation to make the property initialize on first class' usage, just like Java static initializers
You might also find useful ways of initializing singleton state.
Why is it called "companion"?
This object is a companion of the instances.
IIRC there was lengthy discussion here: upcoming-change-class-objects-rethought
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes. Every "static" property/method needs to be placed inside this companion.
To instantly create a singleton instance that is scoped to a class, I often write
You do not create the singleton instance instantly. It is created when accessing singleton for the first time.
which seems like an unidiomatic way of doing it. What's the better way?
Rather go with object Singleton { } to define a singleton-class. See: Object Declarations
You do not have to create an instance of Singleton, just use it like that Singleton.doWork()
Just keep in mind that Kotlin offers other stuff to organize your code. There are now alternatives to simple static functions e.g. you could use Top-Level-Functions instead.
When the classes/objects with related functionalities belong together, they are like companions of each other. A companion means a partner or an associate, in this case.
Reasons for companionship
Cleaner top-level namespace
When some independent function is intended to be used with some specific class only, instead of defining it as a top-level function, we define it in that particular class. This prevents the pollution of top-level namespace and helps with more relevant auto-completion hints by IDE.
Packaging convenience
It's convenient to keep the classes/objects together when they are closely related to each other in terms of the functionality they offer to each other. We save the effort of keeping them in different files and tracking the association between them.
Code readability
Just by looking at the companionship, you get to know that this object provides helper functionality to the outer class and may not be used in any other contexts. Because if it was to be used with other classes, it would be a separate top level class or object or function.
Primary purpose of companion object
Problem: companion class
Let's have a look at the kinds of problems the companion objects solve. We'll take a simple real world example. Say we have a class User to represent a user in our app:
data class User(val id: String, val name: String)
And an interface for the data access object UserDao to add or remove the User from the database:
interface UserDao {
fun add(user: User)
fun remove(id: String)
}
Now since the functionalities of the User and implementation of the UserDao are logically related to each other, we may decide to group them together:
data class User(val id: String, val name: String) {
class UserAccess : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
val userAccess = User.UserAccess()
userAccess.add(john)
}
While this is a good setup, there are several problems in it:
We have an extra step of creating the UserAccess object before we can add/remove a User.
Multiple instances of the UserAccess can be created which we don't want. We just want one data access object (singleton) for User in the entire application.
There is a possibility of the UserAccess class to be used with or extended with other classes. So, it doesn't make our intent clear of exactly what we want to do.
The naming userAccess.add() or userAccess.addUser() doesn't seem very elegant. We would prefer something like User.add().
Solution: companion object
In the User class, we just replace the two words class UserAccess with the two other words companion object and it's done! All the problems mentioned above have been solved suddenly:
data class User(val id: String, val name: String) {
companion object : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
User.add(john)
}
The ability to extend interfaces and classes is one of the features that sets the companion objects apart from Java's static functionality. Also, companions are objects, we can pass them around to the functions and assign them to variables just like all the other objects in Kotlin. We can pass them to the functions that accept those interfaces and classes and take advantage of the polymorphism.
companion object for compile-time const
When the compile-time constants are closely associated with the class, they can be defined inside the companion object.
data class User(val id: String, val name: String) {
companion object {
const val DEFAULT_NAME = "Guest"
const val MIN_AGE = 16
}
}
This is the kind of grouping you have mentioned in the question. This way we prevent the top-level namespace from polluting with the unrelated constants.
companion object with lazy { }
The lazy { } construct is not necessary to get a singleton. A companion object is by default a singleton, the object is initialized only once and it is thread safe. It is initialized when its corresponding class is loaded. Use lazy { } when you want to defer the initialization of the member of the companion object or when you have multiple members that you want to be initialized only on their first use, one by one:
data class User(val id: Long, val name: String) {
companion object {
val list by lazy {
print("Fetching user list...")
listOf("John", "Jane")
}
val settings by lazy {
print("Fetching settings...")
mapOf("Dark Theme" to "On", "Auto Backup" to "On")
}
}
}
In this code, fetching the list and settings are costly operations. So, we use lazy { } construct to initialize them only when they are actually required and first called, not all at once.
Usage:
fun main() {
println(User.list) // Fetching user list...[John, Jane]
println(User.list) // [John, Jane]
println(User.settings) // Fetching settings...{Dark Theme=On, Auto Backup=On}
println(User.settings) // {Dark Theme=On, Auto Backup=On}
}
The fetching statements will be executed only on the first use.
companion object for factory functions
Companion objects are used for defining factory functions while keeping the constructor private. For example, the newInstance() factory function in the following snippet creates a user by generating the id automatically:
class User private constructor(val id: Long, val name: String) {
companion object {
private var currentId = 0L;
fun newInstance(name: String) = User(currentId++, name)
}
}
Usage:
val john = User.newInstance("John")
Notice how the constructor is kept private but the companion object has access to the constructor. This is useful when you want to provide multiple ways to create an object where the object construction process is complex.
In the code above, consistency of the next id generation is guaranteed because a companion object is a singleton, only one object will keep track of the id, there won't be any duplicate ids.
Also notice that companion objects can have properties (currentId in this case) to represent state.
companion object extension
Companion objects cannot be inherited but we can use extension functions to enhance their functionality:
fun User.Companion.isLoggedIn(id: String): Boolean { }
The default class name of the companion object is Companion, if you don't specify it.
Usage:
if (User.isLoggedIn("34")) { allowContent() }
This is useful for extending the functionality of the companion objects of third party library classes. Another advantage over Java's static members.
When to avoid companion object
Somewhat related members
When the functions/properties are not closely related but only somewhat related to a class, it is recommended that you use top-level functions/properties instead of companion object. And preferably define those functions before the class declaration in the same file as that of class:
fun getAllUsers() { }
fun getProfileFor(userId: String) { }
data class User(val id: String, val name: String)
Maintain single responsibility principle
When the functionality of the object is complicated or when the classes are big, you may want to separate them into individual classes. For example, You may need a separate class to represent a User and another class UserDao for database operations. A separate UserCredentials class for functions related to login. When you have a huge list of constants that are used in different places, you may want to group them in another separate class or file UserConstants. A different class UserSettings to represent settings. Yet another class UserFactory to create different instances of the User and so on.
That's it! Hope that helps make your code more idiomatic to Kotlin.
Why is it called "companion"?
An object declaration inside a class can be marked with the companion keyword:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Members of the companion object can be called by using simply the class name as the qualifier:
val instance = MyClass.create()
If you only use 'object' without 'companion', you have to do like this:
val instance = MyClass.Factory.create()
In my understanding, 'companion' means this object is companion with the outter class.
We can say that companion is same as "Static Block" like Java, But in case of Kotlin there is no Static Block concept, than companion comes into the frame.
How to define a companion block:
class Example {
companion object {
fun display(){
//place your code
}
}
}
Calling method of companion block, direct with class name
Example.Companion.display
It's easy to write extension methods in Kotlin:
class A { }
class B {
fun A.newFunction() { ... }
}
But is there some way to create extension variable? Like:
class B {
var A.someCounter: Int = 0
}
You can create an extension property with overridden getter and setter:
var A.someProperty: Int
get() = /* return something */
set(value) { /* do something */ }
But you cannot create an extension property with a backing field because you cannot add a field to an existing class.
No - the documentation explains this:
Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on instances of this class.
and
Note that, since extensions do not actually insert members into classes, there’s no efficient way for an extension property to have a backing field. This is why initializers are not allowed for extension properties. Their behavior can only be defined by explicitly providing getters/setters.
Thinking about extension functions/properties as just syntactic sugar for calling a static function and passing in a value hopefully makes this clear.
However, if you really, really want to do something like this...
As stated above regarding efficiency, an additional backing field added directly to the class is the best way to store data non-derivable from existing non-private members from the class. However, if you don't control the implementation of the class and are dead-set on creating a new property that can store new data, it can be done in a way that is not abysmally inefficient by using separate external tables. Use a separate map that keys on object instances of this class with values that map directly to the value you want to add then define an extension getter and/or setter for this property which uses your external table to store the data associated with each instance.
val externalMap = mutableMapOf<ExistingClass, Int>()
var ExistingClass.newExtensionProperty : Int
get() = externalMap[this] ?: 0
set(value:Int) { externalMap[this] = value }
The additional map lookups will cost you - and you need to consider memory leaks, or using appropriately GC-aware types, but it does work.
There's no way to add extension properties with backing fields to classes, because extensions do not actually modify a class.
You can only define an extension property with custom getter (and setter for var) or a delegated property.
However, if you need to define an extension property which would behave as if it had a backing field, delegated properties come in handy.
The idea is to create a property delegate that would store the object-to-value mapping:
using the identity, not equals()/hashCode(), to actually store values for each object, like IdentityHashMap does;
not preventing the key objects from being garbage collected (using weak references), like WeakHashMap does.
Unfortunately, there is no WeakIdentityHashMap in JDK, so you have to implement your own (or take a complete implementation).
Then, based on this mapping you can create a delegate class satisfying the property delegates requirements. Here's an example non-thread-safe implementation:
class FieldProperty<R, T : Any>(
val initializer: (R) -> T = { throw IllegalStateException("Not initialized.") }
) {
private val map = WeakIdentityHashMap<R, T>()
operator fun getValue(thisRef: R, property: KProperty<*>): T =
map[thisRef] ?: setValue(thisRef, property, initializer(thisRef))
operator fun setValue(thisRef: R, property: KProperty<*>, value: T): T {
map[thisRef] = value
return value
}
}
Usage example:
var Int.tag: String by FieldProperty { "$it" }
fun main(args: Array<String>) {
val x = 0
println(x.tag) // 0
val z = 1
println(z.tag) // 1
x.tag = "my tag"
z.tag = x.tag
println(z.tag) // my tag
}
When defined inside a class, the mapping can be stored independently for instances of the class or in a shared delegate object:
private val bATag = FieldProperty<Int, String> { "$it" }
class B() {
var A.someCounter: Int by FieldProperty { 0 } // independent for each instance of B
var A.tag: String by bATag // shared between the instances, but usable only inside B
}
Also, please note that identity is not guaranteed for Java's primitive types due to boxing.
And I suspect the performance of this solution to be significantly worse than that of regular fields, most probably close to normal Map, but that needs further testing.
For nullable properties support and thread-safe implementation please refer to here.
You can't add a field, but you can add a property, that delegates to other properties/methods of the object to implement its accessor(s). For example suppose you want to add a secondsSinceEpoch property to the java.util.Date class, you can write
var Date.secondsSinceEpoch: Long
get() = this.time / 1000
set(value) {
this.time = value * 1000
}
If you are extending View you can do it quite easily like this...
This is example how I create some my custom class Event property in EditText class extension:
Define id for key :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="EditTextEventOnClearTagKey" type="id" />
</resources>
Define one reusable extension like this:
fun <T : Any> View.tagProperty(#IdRes key: Int, onCreate: () -> T): T {
#Suppress("UNCHECKED_CAST")
var value = getTag(key) as? T
if (value.isNull) {
value = onCreate()
setTag(key, value)
}
return value!!
}
Use it in wherever View extension you need:
val EditText.eventClear get() = tagProperty(R.id.EditTextEventOnClearTagKey) { event<Unit>() }