I have the following data class intended for use in an Android application running Kotlin version 1.2.51:
data class Data(var a: ArrayList<String>, var b: String)
As you can see, a is an ArrayList. I want to append elements from another array into a. I've tried this:
itemsToAppend.forEach {
Data.a.add(it)
}
However, Android Studio determines that a is an unresolved reference. How exactly does one append an item to such an ArrayList?
Thanks.
Data classes are not object classes. You will have to initialise them before you can use it
val d= Data(ArrayList(), "demo")
itemsToAppend.forEach {
d.a.add(it)
}
create an instance of Data:
var a: ArrayList<String> = arrayListOf()
var data = Data(a, "something")
and use data in your loop
If you want to access you list staticly do this:
data class D(var a: ArrayList<String>) { // a can't be used as D.a
companion object {
var ab: ArrayList<String> = ArrayList() // ab can be used as D.ab
}
}
Related
I'm new to java and what I'm currently trying is.
For example I have 2 classes 1 for Employees which can have a name number and email and one for Vehicles which have number type and status.
I retrieve data from an API for both classes and fill and ArrayList<Employee> and ArrayList<Vehicle> with all the data.
Both of these classes need to go through the same function which will create an excel file based on the data.
The problem I'm facing currently is that I want to use both of these arraylist in my function but based on which one I get to do other things inside the function and for this I need to know which arraylist was forwarded to the function. What I'm trying to do is following:
I have a function
Public static void createExcel(Object[] obj){ //do something }
I give the function the type Object so that I can get both of the arraylists. So I parsed the Arraylists as followed:
ArrayLists<Employee> employees = new ArrayList<>();
employees.add(employee);
Object[] objArray = employees.toArray();
ExcelWriter.createExcel(objArray);
The same for Vehicle.
Now my question is how can I in the createExcel funtion retrieve which arraylist was passed and how can I get my original arraylist from this object array? or is this not possible and do I have to do it another way?
EDIT:
To make it a bit more clear I would like my excel function to be something like this:
if(obj == type of ArrayLists<Employee>()){ //retrieve my original employees arraylist here }
And the same for Vehicle
You can check the actual type of an object using instanceof:
public static void createExcel(Object[] obj){
// Assume array is not empty
Object o = obj[0];
if ( o instanceof Employee ) {
// It's an Employee
}
else if ( o instanceof Vehicule ) {
// It's a Vehicule
}
else {
// Should probably throw an Exception here
}
}
But if you wish to do different things dependening on the type of the parameter, why would you write a single function?
Override createExcel method
public static void createExcel(List<Employee> employees){
...
ExcelWriter.createExcel(employees.toArray());
...
}
public static void createExcel(List<Vehicle> vehicles){
...
ExcelWriter.createExcel(vehicles.toArray());
...
}
I can't figure out how should i deal with generics in kotlin.
I'm writing a history class for changes made on generic objects, which should get any type of class as parameter: after that, I would compare the old object values with the new object values, and if I found a difference, I'll write that in my data class.
I've succedeed doing that with java with bean.getClass().getMethods();, but I want to trying move to Kotlin.
class ChangeHistoryUtils<T> (val originalBean : T, username : String , var modifiedBean: T? = null) {
data class ChangeHistory(val username: String, val fieldName : String,
val oldValue : String , val newValue : String , val date : LocalDate = LocalDate.now())
fun compareBeans(){
//how to get all originalBean getters and its values?
}
}
I'm actually stuck here: how should obtain all the getters in my T object?
Let's guess i'll receive a class which with 10 getters, I want to call all these 10 getters in originalBean, and comparing its value with the ones in modifiedBean. If different, I will write it in my ChangeHistory
Thanks
You need to ensure that T itself is not a nullable type, i.e. use something like where T : Any on the class declaration, e.g.:
class ChangeHistoryUtils<T> (originalBean : T, username : String , modifiedBean: T? = null) where T : Any
If you do that you can afterwards just access the methods as you did in Java, e.g. if you just want to reuse the code you already have:
fun compareBeans(){
originalBean::class.java.methods // this is actually your originalBean.getClass().getMethods() !
// just print the methods for now...
.forEach(::println)
}
But as you are using Kotlin you may rather want to use the Kotlin approach then, e.g. just showing the properties, or similar:
originalBean::class.memberProperties
// again just printing them:
.forEach(::println)
You then need to add kotlin-reflect as dependency. You may also want to check the Kotlin reference regarding reflection.
This question already has answers here:
In Kotlin, how to make a property accessible by only specific type
(5 answers)
Closed 4 years ago.
I have some field which is collection, which can be mutated inside service containing it, and some other services should be able to access it without possibility to mutate it by themselves.
In java it would can be implemented like this:
public class Test {
private final List<Integer> list = new ArrayList<>();
public List<Integer> getList() {
return Collections.unmodifiableList(list);
}
}
In kotlin I store this field declared as MutableList:
val someCollection: MutableList<Int> = ArrayList()
get() = unmodifiableList(field)
But then getter obviously would return object with type MutableList.
Ideally I want to achieve something like this:
val someCollection: MutableList<Int> = ArrayList()
get() = unmodifiableList(field) as List // <-- returns List instead of MutableList
In other words is it possible change signature of generated getter to return another interface. Most probably answer is no, and I wonder why? Is it believed to be some bad practice?
I saw that there is possibility to do something like this:
private val _someCollection: MutableList<Int> = ArrayList()
val someCollection: List<Int>
get() = unmodifiableList(field)
But it does seems even worse then manually created getter, as it creates one more field.
No, that's not currently possible in Kotlin. In fact, the current design forces the getters to have the same return type to that of the whole property.
Typically, the workaround is, as you noticed, to use a backing property.
Alternatively, you can define an interface with a List property, implement it with a MutableList in a class, and expose instances of the class using the interface:
interface SomeInterface {
val someList: List<Int>
}
internal class SomeClass : SomeInterface {
override val someList: MutableList<Int> = mutableListOf()
}
fun getSomeInterface(): SomeInterface =
SomeClass().apply { someList += listOf(1, 2, 3) }
See: a related discussion.
Suppose I want to send following parameters :
key1: value1,
key2: value2
But currently I can't decide what will be there at place of key1,key2
That may be any string. key1 may be city,key2 may be code. Or key 1 may be companyName and key 2 is domain. So how can I set any custom unknown parametrs in method of java? Consider that I know total number of parameters and data type of their values, but can't determine their exact keys now. How to implement it in java?
You can send an array of objects in your method:
Object[] myObjects = new Object[2];
myObjects[0] = "This is a string";
myObjects[1] = 5;
myMethod(myObjects);
public void myMethod(Object[] myObjects){
// DoSomethingOverHere
}
If you only have Strings you can do the same but specify an array of Strings instead of objects. If you use objects, make sure to check the instance of the objects before using it.
I assume what you mean to achieve is a method that can accept any type of argument and still do the work.
Below is the approach I would use:
Lets say you want to use myMethod:
class MainClass {
public Object myMethod(Object A,Object B)
{
Object C=(Object) (A.toString()+","+B.toString());
System.out.println(C.toString());
return C;
}
}
And you can call it with any type of parameters:
public class TesterClass {
MainClass mainClass=new MainClass();
mainClass.myMethod(123, "PQR");
mainClass.myMethod(123.00, "PQR");
mainClass.myMethod(123.00, 123);
mainClass.myMethod(new int[]{1,2,3}, "PQR");
}
Your output will be:
123,PQR
123.0,PQR
123.0,123
[I#659e0bfd,PQR
last one is array, you can manipulate its processing)
I need using a tester for Scala Spark filter, with tester implementing java's Predicate interface and receiving specific class name by arguments.
I'm doing something like this
val tester = Class.forName(qualifiedName).newInstance().asInstanceOf[Predicate[T]]
var filtered = rdd.filter(elem => tester.test(elem))
The problem is that at runtime i have a Spark "TaskNotSerializable Exception" because my specific Predicate class is not Serializable.
If I do
val tester = Class.forName(qualifiedName).newInstance()
.asInstanceOf[Predicate[T] with Serializable]
var filtered = rdd.filter(elem => tester.test(elem))
I get the same error.
If I create tester into rdd.filter call it works:
var filtered = rdd.filter { elem =>
val tester = Class.forName(qualifiedName).newInstance()
.asInstanceOf[Predicate[T] with Serializable]
tester.test(elem)
}
But I would create a single object (maybe to broadcast) for testing. How can I resolve?
You simply have to require the class implements Serializable. Note that the asInstanceOf[Predicate[T] with Serializable] cast is a lie: it doesn't actually check value is Serializable, which is why the second case doesn't produce an error immediately during the cast, and the last one "succeeds".
But I would create a single object (maybe to broadcast) for testing.
You can't. Broadcast or not, deserialization will create new objects on worker nodes. But you can create only a single instance on each partition:
var filtered = rdd.mapPartitions { iter =>
val tester = Class.forName(qualifiedName).newInstance()
.asInstanceOf[Predicate[T]]
iter.filter(tester.test)
}
It will actually perform better than serializing the tester, sending it, and deserializing it would, since it's strictly less work.