Would you please let me know the reason why both of
var name: String
var age: Int
have the following error message:
property must be initialized or abstract.
I would like to declare them without initialization
Main:
data class Person(val _name: String,val _age: Int) {
var name: String
var age: Int
init {
name: String = _name.capitalize()
age: Int = _age * 10;
println("the name is: $name")
println("the age is: $age")
}
/*override fun toString(): String {
return "$name is $age years old."
}*/
}
It also says: Unexpected tokens (use ';' to separate expressions on the same line) and that within the init-function.
So actually the message you showed is only one of many problems. As the init-function is already corrupt, the compiler can not see the assignment and therefore it marks your declaration itself as an error too.
Just omit the "type declaration" (actually it's just code that shouldn't be there ;-)) on the assignment in the init and it will compile:
data class Person(val _name: String,val _age: Int) {
var name: String
var age: Int
init {
name = _name.capitalize()
age = _age * 10;
println("the name is: $name")
println("the age is: $age")
}
/*override fun toString(): String {
return "$name is $age years old."
}*/
}
Related
I want to do my task, the code from my teacher but mine is always error :
<html>None of the following functions can be called with the arguments supplied:<br/>public constructor Grup(id: Int) defined in com.cika.uasmobiledua.model.Grup<br/>public constructor Grup(name: String, label: String) defined in com.cika.uasmobiledua.model.Grup
Here's my code:
package com.cika.uasmobiledua.model
import com.google.gson.Gson
class Grup {
var id = 0
var name = ""
var label = ""
constructor(id : Int){
this.id = id
}
constructor(name : String, label : String){
this.name = name
this.label = label
}
fun toJson(): String{
return Gson().toJson(this, Grup::class.java)
}
fun fromJson(json : String): Grup{
if (json.isEmpty()) return Grup()
return Gson().fromJson(json, Grup::class.java)
}
}
Following example will describe my misunderstanding the best I think:
class myExampleClass (
myString: String,
val myInt: Int,
) {
fun memberFunction() {
val memberFunctionValA = myString // does not work
val memberFunctionValB = myInt // does work
}
}
Is there a specific reason? Do we always have to declare parameters as properties to use them inside the class?
For declaring properties and initializing them from the primary constructor, Kotlin has a concise syntax:
class Person(val firstName: String, val lastName: String, var age: Int) { /*...*/ }
I found this on https://kotlinlang.org/docs/reference/classes.html
As far as I can understand you missed a val keyword in the first parameter.
class myExampleClass (
val myString: String, // this might work
val myInt: Int,
) {
fun memberFunction() {
val memberFunctionValA = myString // does not work
val memberFunctionValB = myInt // does work
}
}
I am learning Kotlin and writing code to check my understanding. I'm trying to use a toString override to print the values of a hashMap that is a property of a class. I can't get it to work. Instead I get output like "kotlin.Unit() -> kotlin.Unit". Also, I don't understand why the values of the hashMap ARE printing out before the toString output. I don't know where that output is coming from. Please help me. Thanks. Below is my code and the output I'm getting.
Code:
package ch07.ExpandoObject
import java.beans.PropertyChangeListener
import java.beans.PropertyChangeSupport
import kotlin.properties.Delegates
import kotlin.reflect.KProperty
class Person(
val name: String = "",
age: Int? = null,
var isMarried: Boolean? = null ,_attributes: kotlin.collections.HashMap<String,String>? = hashMapOf<String, String>()
)
:PropertyChangeAware()
{
var _attributes : kotlin.collections.HashMap<String,String>? = hashMapOf<String, String>()
fun setAttribute(attrName: String, value: String) {
_attributes!!.set(attrName, value)
_attributes!!.set("name", this.name)
}
override fun toString() = "Person(name=\"${name?:""}\", age=${age?:99999}, isMarried=$isMarried) " +
"${_attributes?.get("name")} " + "$name " +
this._attributes!!.forEach { (attrName, value) -> println("$attrName = $value") } +
{
for ((attrName, value) in this._attributes!!) {
println("attribute $attrName = ${this._attributes!![attrName]}")
}
}
val _age = ObservableProperty(propName = "age", propValue = age, changeSupport = changeSupport)
private val observer = {
prop: KProperty<*>, oldValue: Int, newValue: Int ->
changeSupport.firePropertyChange(prop.name, oldValue, newValue)
}
var age: Int by Delegates.observable(initialValue = age?:99999,onChange = observer)
}
class ObservableProperty(val propName: String,
var propValue: Int?, val changeSupport: PropertyChangeSupport
) {
fun getValue(): Int? = propValue
fun setValue( newValue: Int) {
val oldValue = propValue
propValue = newValue
changeSupport.firePropertyChange(propName, oldValue, newValue)
}
}
open class PropertyChangeAware {
val changeSupport = PropertyChangeSupport(this)
fun addPropertyChangeListener(listener: PropertyChangeListener) {
changeSupport.addPropertyChangeListener(listener)
}
fun removePropertyChangeListener(listener: PropertyChangeListener) {
changeSupport.removePropertyChangeListener(listener)
}
}
fun main(args: Array<String>) {
val p = Person("Bob", 89, isMarried = false)
val data = mapOf("lastname" to "Jones", "company" to "JetBrains")
for ((attrName, value) in data)
p.setAttribute(attrName, value)
println(p)
}
Here is the current output:
name = Bob
company = JetBrains
lastname = Jones
Person(name="Bob", age=89, isMarried=false) Bob Bob kotlin.Unit() -> kotlin.Unit
Thanks, again, for any help.
You should not use print() or println() functions inside toString() because they output their arguments to the standard output immediately instead of appending them to the string returned to the caller.
Let's examine the output kotlin.Unit() -> kotlin.Unit you're getting. It consists of two parts:
kotlin.Unit is the string representation of attributes!!.forEach { ... } expression. forEach function returns without value, and in Kotlin it's expressed by returning the Unit object value. Its string representation is appended to the string you're returning.
the second part, () -> kotlin.Unit, is also the string representation of the lambda function expression { for((attrName, value) in ...) }. This function takes no parameters, and returns without value, which means that its type is () -> Unit. Note that in Kotlin the block { ... } declares a local lambda function. If you instead want to run the code inside of that block, use the run function: run { ... }
The goal of toString function is to build the string representation of an object. And for that you can use buildString function:
override fun toString() = buildString {
append("Person(name=\"${name?:""}\", age=${age?:99999}, isMarried=$isMarried) ")
append("${_attributes?.get("name")} ").append("$name ")
this._attributes!!.forEach { (attrName, value) -> append("$attrName = $value") }
for ((attrName, value) in this._attributes!!) {
append("attribute $attrName = ${this._attributes!![attrName]}")
}
}
This function creates a StringBuilder and passes it as a receiver to its functional argument, where you call append or appendln on that receiver. Then buildString converts that string builder to a string and returns it.
My code:
open class Team (val country: String = "England",
val aggressive: Boolean = true,
name: String, squadSize: Int = 24) {
val attendance: Int
init {
if (aggressive){
attendance = 25000
} else {
attendance = 20000
}
}
}
fun chooseTeam(team: String) {
val homeTeam = Team(name = "Blue Team")
println("the home team is ${homeTeam.name} so they are ${if(homeTeam.aggressive) "angry" else "timid" }")
}
I'm getting an Unresolved reference: name on ${homeTeam.name}.
However I've specified the name when I instantiate the class val homeTeam = Team(name = "Blue Team") - any idea why I'm getting unresolved reference?
In Kotlin you need to put val/var before any property inside the primary constructor, otherwise the property wont be declared as a member variable.
Please correct it:
open class Team(
val country: String = "England",
val aggressive: Boolean = true,
val name: String,
val squadSize: Int = 24
) {
...
}
Just learning Kotlin In the first code down below there is the val keyword right in the other code there is not,
what is the different here if the val and var is omitted?
class Person(val firstName: String, val lastName: String) {
}
class Person(firstName: String, lastName: String) {
}
If val or var is omitted then they won't be properties, but parameters passed to constructor. You won't be able to work with them outside of constructor.
If you omit val or var in in a constructor, then the only places that can access these parameters are initialization statements that are evaluated at construction time. See https://kotlinlang.org/docs/reference/classes.html
This is useful when you want to do something with a value before storing it. In Java you would put that code a constructor body
class Person(firstName: String, lastName: String) {
// directly in val / var declarations
val firstName = firstName.capitalize()
val lastName = lastName
// in init blocks
val fullName: String
init {
fullName = "$firstName $lastName"
}
// secondary constructors can only see their own parameters
// and nothing else can access those
constructor(fullName: String) : this("", fullName)
}
But it also works for delegation using by
interface Named {
fun getName(): String
}
class Human(private val fname: String, private val lname: String) : Named {
override fun getName() = "$fname + $lname" // functions need val since
// value is resolved after construction
}
class Person2(firstName: String, lastName: String) : Named by Human(firstName, lastName)
class Person3(human: Human) : Named by human {
constructor(firstName: String, lastName: String): this(Human(firstName, lastName))
}
Or in property delegation
class Person4(firstName: String, lastName: String) {
val fullName: String by lazy { "$firstName $lastName" }
}
Note: the closure is captured at initialization time, the values are therefore still available when lazy evaluates eventually.