Determine if a String can be parsed to LocalDateTime or Int I have the following kotlin function that takes in a string "value", then attempts to parse "value" as both a LocalDateTime and an Int. It returns a Pair of the parsed value of "value" and an enum that specifies which of the three types it was determined to be.

enum class RangeValueType{
    Int,
    Date,
    String
}

fun parseValue(value: String): Pair&lt;RangeValueType, Any&gt; {
    val rangeDate: LocalDateTime
    val rangeInt: Int
    //try date first
    try {
        //ISO_LOCAL_DATE_TIME e.g. 2011-12-03T10:15:30 for Dec. 3rd, 2011 &amp; 10:15 30 sec.
        //can't use basic date b/c e.g. 20111203 is indistinguishable from an int.
        rangeDate = LocalDateTime.parse(value)
        //it parsed to a date, so return the date
        return Pair(RangeValueType.Date, rangeDate)
    }catch (dtpe: DateTimeParseException) {
        //not a date
    }
    //try number next
    try{
        rangeInt = value.toInt()
        //it parsed to an int, so return the int
        return Pair(RangeValueType.Int, rangeInt)
    }catch (nfe: NumberFormatException)
    {
        //not an int
    }
    //not date or int, must be a string
    return Pair(RangeValueType.String, value)
}


My principal concern is that I am using caught exceptions as a means of flow control, which I understand to generally be a Bad Idea. I know C# has a "TryParse" method for exactly this kind of case, but I wasn't able to find anything for Kotlin / Java. 

Is there a better way to parse the values into their proper types?
(Disclamer: I only know Kotlin theoretically)

You can avoid the second try/catch by using String.toIntOrNull instead of String.toInt.

And by extracting the LocalDateTime conversion into a separate function, that also returns null when it fails (which also would help fulfill the single responsibility principle), you could then use a functional approach with the safe call operator (?.), the Elvis operator (?:) and the run extension method:

enum class RangeValueType {
    INT,
    DATE,
    STRING
}

fun parseLocalDateTime(value: String): LocalDateTime? {
    try {
        return LocalDateTime.parse(value)
    } catch (dtpe: DateTimeParseException) {
        return null;
    }
}

fun parseValue(value: String): Pair&lt;RangeValueType, Any&gt; {
    return parseLocalDateTime(value)?.run { Pair(RangeValueType.DATE, this) } ?:
             value.toIntOrNull()?.run { Pair(RangeValueType.INT, this) } ?: 
             value.run { Pair(RangeValueType.STRING, this) } 
}


Runable version 

(NB: enum constants should be written all capitalized so they are not confused with types.)