5

I often want to hold a string that can not be null or blank - whitespace isn't good enough. The compiler handles String? nicely to prevent null, and we can use aNullableString.isNullOrBlank() to check if it is null or blank. However, this requires that the blank check be handled everywhere it is used then handle errors if it is blank, which can cause unexpected errors if you miss a spot.

Is there an easier way to define a type or extension to String that will enforce that the string must not be blank?

1
  • You can make a new "NonEmptyString" type that wraps a string, and ensures it's never blank by checking the "input" string given to its constructor. You can also only expose operations on the wrapped string that won't cause it to become empty. Optionally, you can add such operations, but with checks to ensure they don't actually result in an empty String. Commented Jul 24, 2017 at 16:33

1 Answer 1

4

If you need this behavior in multiple places, you can create a delegate to handle it, where you can do the check either in the setter of the private property, or in the setValue function:

class NonEmptyString(private var str: String) {
    init {
        if (str.isEmpty()) {
            throw IllegalArgumentException("Invalid initial value")
        }
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>) = str

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        if (value.isEmpty()) {
            return // or throw or something
        }
        str = value
    }
}

The usage of this would look like this:

var nonEmpty by NonEmptyString("something")
nonEmpty = ""
println(nonEmpty) // "something"
Sign up to request clarification or add additional context in comments.

2 Comments

Also, there are observable and vetoable in kotlin.properties.Delegates that can slightly simplify this implementation: you won't need to implement the get/setValue(...) operators but instead just pass the code that checks the assigments.
Ah - String is final, so you can't do this by a subclass. Using Delegates looks good. Likely will either throw an exception in the constructor and the setter, or use vetoable to simply reject the input, depending on what works best for my usage. Thx.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.