Exception handling - Building projects

BuildingProj.zip (9.4 KB)
You will need Intellij-IDEA in order to look at this project. Here is a link to get it: https://www.jetbrains.com/idea/download/#section=mac
For some reason the Building class is throwing exception but it’s not being caught. Please help.

I’ve zipped the file with WinZip.

You might get more interest in this question if you could distil the code down to a minimal, reproducible example. (Ideally, it’d then be small enough to post the code here directly.)

It might also help to post the exception message (and its stack trace) here too.

Here is the building class, this is the class which I have a problem with.
package building

import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.random.Random

class BuildingConstructionFailed: Exception("Building Construction Failed")

class Building ( val name: String, var floors: Int = 0, private val scope: CoroutineScope) {
    suspend fun makeFoundation() = scope.launch {
        delay(300)
        speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] The foundation is ready")
    }
    suspend fun buildFloor(floor: Int) = scope.launch{
        if (Random.nextBoolean()) {
            delay(100)
            speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] The $floor'th is raised")
            ++floors
        } else {
            throw BuildingConstructionFailed()
        }
    }
    suspend fun placeWindows(floor: Int) = scope.launch{
        delay(100)
        speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] Windows are placed on the $floor'th")
    }
    suspend fun installDoors(floor: Int) = scope.launch{
        delay(100)
        speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] Doors are installed on the $floor'thfloor")
    }
    suspend fun provideElectricity(floor: Int) = scope.launch{
        delay(100)
        speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] Electricity is provided on the $floor'th floor")
    }
    suspend fun buildRoof() = scope.launch{
        delay(200)
        speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] The roof is ready")
    }
    suspend fun fitOut(floor: Int) = scope.launch{
        delay(200)
        speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] The $floor'th is furnished")

    }
    fun speakThroughBullhorn(message: String) = println(message)
}

This the Building Yard class.

package buildingyardpack

import building.*
import kotlinx.coroutines.*

class BuildingYard {
    suspend  fun startProjects(buildingsToMake: List<Pair<String, Int>>) {
        var tasks = mutableListOf<Deferred<Unit>>()
        runBlocking {
            buildingsToMake.forEach { tasks.add(async(Dispatchers.IO) {startProject(it.first, it.second)})}
        }
        tasks.awaitAll()
    }
    suspend fun startProject(name: String, floors: Int) {
        val building = withContext(Dispatchers.Default) {
            val building = Building(name, scope=this)
            val cores = Runtime.getRuntime().availableProcessors()
            building.speakThroughBullhorn("The building of $name is started with $cores building machines engaged")
            // Any of these phases until foundation isn't ready
            building.makeFoundation().join()

            (1..floors).forEach {
                // A floor should be raised before we can decorate it
                try {
                    building.buildFloor(it).join()
                } catch (exception: BuildingConstructionFailed) {
                    building.buildFloor(it).join()
                }
                // These decorations could be made at the same time
                building.placeWindows(it)
                building.installDoors(it)
                building.provideElectricity(it)
                building.fitOut(it)

            }
            building.buildRoof().join()
            building
        }
        if (building.floors == floors ) {
            building.speakThroughBullhorn("${building.name} is ready!")
        }
    }
}

This is the main function.

import kotlinx.coroutines.*
import kotlin.concurrent.thread
import buildingyardpack.*
import java.util.concurrent.atomic.*

suspend fun main(args: Array<String>) {
    var listOfHouses = mutableListOf<Pair<String, Int>>()
    listOfHouses.add(Pair("Smart house", 20))
    listOfHouses.add(Pair("Mark's house", 30))
    //BuildingYard().startProject("Smart house", 20)
    BuildingYard().startProjects(listOfHouses)
}

This is a screen-shot of the error.


The line I’m having problem with is the one which generates the building exception. Not only does it not properly generate the exception but also it is not caught correctly,

How should it be generated? (Looks like it’s doing just what you told it to. It would be normal for the exception to hold some information about the reason for the failure, or at least a custom message, but it’s not compulsory.)

I assume this is for learning/testing purposes? (It would NOT be normal to throw an exception at random like that!)

How should it be caught? (Looks like you’re doing nothing to catch it, so logging the error and stopping the thread, as it did, is the normal behaviour.)

I was hoping to catch the error and then continue building the floor.

Yes, it is for learning purpose.

If I understand what’s going on the issue is here:

Nothing is catching the exception which could be thrown inside that catch block. If your intetion is to keep try calling building.buildFloor(it).join() until it doesn’t throw, you’ll need a loop around it.

1 Like