Andrew
Andrew

Reputation: 4702

Kotlin: Accessing Enum Value generates nullpointerexception

I am trying to pass an enum as a parameter to another class, so I can override its price Value. Here is my approach:

Base class Product:

open class Product(val productName: String, open val price: Double) {
    val profit = price
}

Enum class:

enum class Discount(val factor: Int) {
    BIGSALE(20),
    LITTLESALE(10),
    NOSALE(0)
}

Discount Product:

class DiscountProduct(
    val discount: Discount,
    productName_param: String, price_param: Double
) : Product(productName_param, price_param) {

    // Nullpointer Exception
    override val price: Double
        get() = super.price - ((super.price / 100) * discount.factor)
}

App (main):

val newProduct = DiscountProduct(Discount.BIGSALE, "Prod1", 100)

I appreciate every help. Thank you!

ERROR:

Exception in thread "main" java.lang.NullPointerException
    at DiscountProduct.getPrice(DiscountProduct.kt:6)
    at Product.<init>(Product.kt:2)
    at DiscountProduct.<init>(DiscountProduct.kt:3)
    at AppKt.main(App.kt:2)
    at AppKt.main(App.kt)

Upvotes: 0

Views: 461

Answers (1)

Michael
Michael

Reputation: 58427

The actual constructor for DiscountProduct, when viewed as Java code, will look something like this:

public DiscountProduct(@NotNull Discount discount, @NotNull String productName_param, double price_param) {
    Intrinsics.checkParameterIsNotNull(discount, "discount");
    Intrinsics.checkParameterIsNotNull(productName_param, "productName_param");
    super(productName_param, price_param);
    this.discount = discount;
}

So the super constructor (i.e. Product's constructor) is called first, and then the discount member is initialized.

Product's constructor looks something like this:

public Product(@NotNull String productName, double price) {
    Intrinsics.checkParameterIsNotNull(productName, "productName");
    super();
    this.productName = productName;
    this.price = price;
    this.profit = this.getPrice();
 }

When you get to this.profit = this.getPrice(); (which corresponds to the kotlin line val profit = price) you're calling DiscountProduct's getPrice method, which tries to use the discount member, which hasn't yet been initialized. And that's why you get a NullPointerException.


There are probably a few different ways in which you could fix this. One possible solution would be to make profit a lazy property, so that it doesn't get initialized until the first time you try to use it:

val profit: Double by lazy { price }

Another possible solution would be:

val profit: Double get() = price

The difference between this and a lazy property is that here the price gets calculated every time you use profit, not just the first time.

Upvotes: 2

Related Questions