когда использовать lateinit, init block и companion object. Котлин

Я работаю над проектом андроидного Bluetooth-чата с сайта разработчика, и я пытаюсь использовать Kotlin вместо java. Я новичок в Kotlin, и у меня просто возникает некоторая путаница в отношении «правильного» способа использования моего блока init block и lateinit вместе с моими сопутствующими объектами. в коде, который я публикую, у меня нет сопутствующего объекта, но мне интересно, должен ли я это делать. до сих пор я в основном использую только объект-компаньон как способ подражания статическим членам класса java или иногда содержать константы класса. как для моего блока init, я в основном использую для конструктора. Другими словами, назначение членов передается через фактический конструктор, определенный в объявлении класса. Что касается lateinit, я использую это для объявления членов, которые я не хочу немедленно инициализировать, но также не хочу делать nullable. Пожалуйста, дайте мне знать, если это правильное использование или вещь для меня, если это не так. Вот мой код:

inner class AcceptThread(val secure:Boolean) : Thread(){ lateinit var mmServerSocket:BluetoothServerSocket lateinit var mSocketType:String init { var tmp:BluetoothServerSocket? = null mSocketType = if (secure) "Secure" else "Insecure" try { if (secure){ tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_SECURE) } else{ tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, UUID_INSECURE) } }catch (ioe:IOException){ Log.e(TAG, "Socket Type: $mSocketType listen() failed", ioe) } mmServerSocket = tmp!! mState = STATE_LISTEN } } 

Solutions Collecting From Web of "когда использовать lateinit, init block и companion object. Котлин"

Вам не нужно здесь lateinit учитывая, что вы инициализируете свои переменные в конструкторе. Если бы вы, например, инициализировали переменные в методе жизненного цикла, например onCreate (), вы могли бы использовать lateinit var .

Кроме того, я думаю, вы могли бы реорганизовать ваш блок init, чтобы исключить переменную tmp:

 inner class AcceptThread(val secure:Boolean) : Thread() { val mmServerSocket: BluetoothServerSocket val mSocketType: String = if (secure) "Secure" else "Insecure" init { try { mmServerSocket = if (secure) { mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, UUID_SECURE) } else { mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, UUID_INSECURE) } } catch (ioe: IOException) { Log.e(TAG, "Socket Type: $mSocketType listen() failed", ioe) } mState = STATE_LISTEN } 

Пожалуйста, дайте мне знать, если это правильное использование или вещь для меня, если это не так.

Есть две вещи, которые я укажу на ваш код.

  1. Вам не нужно ключевое слово mmServerSocket и mSocketType потому что вы инициализируете обе переменные в конструкторе. Вы бы нуждались в этом, если бы переменные были инициализированы после создания.
  2. Есть один случай, который может вызвать исключение. Переменная tmp может быть нулевой, если IOException . В этом случае при назначении tmp на KotlinNullPointerException будет KotlinNullPointerException mmServerSocket KotlinNullPointerException . У вас есть несколько возможностей исправить это: вы можете обрабатывать случай по умолчанию в блоке catch , вы можете сделать mmServerSocket и т. Д.