[Null-Sicherheit] Kotlin Java-Vergleichsnotiz Richtige Verwendung der Null-Sicherheit

Welcher Artikel?

Wie schreibt man so etwas in Java in Kotlin? Ein Memorandum zum Codevergleich.

[Kotlin] [Java] Kotlin Java-Vergleichsnotiz Dieser Artikel ist auf den Teil der Null-Sicherheitsfunktion von spezialisiert.

Ich möchte die Grundlagen von Kotlin kennenlernen, indem ich es mit Java vergleiche! Bitte lesen Sie den obigen Artikel für diejenigen, die sagen.

Zielgruppe

Was ist Nullsicherheit?

Es bezieht sich auf einen Mechanismus, der im Prinzip Null nicht zulässt.

Zum Beispiel der folgende Code

test.kt


val a: String = null

Dies führt zu einem Kompilierungsfehler. Das liegt daran, dass Kotlin standardmäßig keine Nullen zulässt. Wenn Sie null zulassen möchten, fügen Sie nach dem Typ hinzu?

test.kt


val a: String? = null //Das ist in Ordnung

Beim Zugriff auf eine mit einer Option definierte Variable ist immer eine Nullprüfung erforderlich. Vergleichen wir es mit Java.

test.java


String a = null;
a.contains("hoge"); //Natürlich ist es null, also fällt es mit nullpo

test.kt


var a: String? = null
a.contains("hoge") //Es wird überhaupt nicht kompiliert

Diese Quelle aus Kotlin wird zur Kompilierungszeit abgespielt. Dies liegt daran, dass Nicht-Null nicht garantiert ist. So greifen Sie auf nullfähige Typen zu:

test.kt


val a: String? = null
a?.contains("hoge")

Führen Sie für Funktionsaufrufe vom Typ Nullable einfach Folgendes aus :. Wenn a Null ist, wird enthält nicht ausgeführt und Null wird zurückgegeben.

Wenn ich versuche, dies mit Java zu erreichen,

Zunächst der bekannte Null-Check.

test.java


String a = null;

if (a != null) {
    a.contains("hoge"); //Wenn es null ist, wird es hier nicht übergeben
}

Mit Java 8 können Sie die entsprechende Funktion namens Optional verwenden.

test.java


Optional<String> a = Optional.of(null);
a.ifPresent(notNull -> notNull.contains("hoge")) //enthält wird nur ausgeführt, wenn der Inhalt von a nicht null ist

Sie können sehen, dass es im Vergleich zu Java sehr präzise geschrieben werden kann, Java ist nur eine Laufzeitprüfung. Selbst wenn Sie Java 8 Optional verwenden Erstens ist es keine grundlegende Lösung, wenn Sie vergessen, Optional zu verwenden. Kotlin wird zur Kompilierungszeit überprüft, sodass die Nullprüfung nicht übersehen wird.

Rückgabewert beim Aufrufen einer Java-Methode

Aber auch die Null-Sicherheitsfunktionen von Kotlin sind nicht perfekt. Zum Beispiel beim Aufrufen einer Java-Methode aus Kotlin wie folgt

test.kt


var str = System.getProperty("hoge") //!Schimmel

Da Java keine Nullsicherheitsfunktion hat, wird es auf der Kotlin-Seite zwangsweise als Nicht-Null-Typ zugewiesen. Wenn Sie erzwingen, dass der Java-Wert nicht null ist, folgt auf den Typ ein!

Dies ist etwas knifflig und verhält sich wie Nicht-Null, könnte aber Null sein.

test.kt


var str = System.getProperty("hoge")
var strLength = str.length //Weil es kein Nullable-Typ ist?.Ich brauche nicht

Aber natürlich kann getProperty ("hoge") als null zurückgegeben werden, so dass strLength schleimig fallen kann. Dies bedeutet nicht, dass die absolute Nullsicherheit garantiert wurde.

Wenn Sie es beim Empfang des Rückgabewerts der Java-Methode explizit als Nullable-Typ deklarieren, handelt es sich um einen Nullable-Typ.

test.kt


var str: String? = System.getProperty("hoge")
var strLength = str?.length //Weil es ein Nullable-Typ ist?.Ist notwendig

Es ist sehr schwierig damit umzugehen. .. Wenn Sie Null vollständig löschen möchten, müssen Sie es explizit auf Null setzen.

Nullable auspacken

Schauen wir uns noch einmal das vorherige Beispiel an

test.kt


var str: String? = System.getProperty("hoge")
var strLength = str?.length

In diesem Fall ist der Typ der Variablen str "String?". Die strLength, der der Wert der str-Länge zugewiesen ist, ist also "Int?". Mit anderen Worten, wenn der Typ der Zuweisungsquelle Nullable ist, ist die Variable des Zuweisungsziels ebenfalls Nullable. Damit werden nur Variablen erstellt, die Nullable sein sollen, und die Vorteile der Null-Sicherheitsfunktion können nicht vollständig empfangen werden.

Wenn Sie den Typ, der einmal nullbar war, ungleich null machen möchten, gibt es die folgenden zwei Methoden

Erzwungenes Auspacken

test.kt


var str: String? = System.getProperty("hoge")
var foo = str!!.length // !!Sie können erzwingen, dass str vom Typ String by ist
//foo wird zum Int-Typ

Wenn der Typ, der einmal nullbar wurde, "!!" ist, wird "entfernt".

test.kt


var str: String? = System.getProperty("hoge")
str = str!! //str wird zu einem String-Typ
var foo = str.length // non-Weil es null ist?.Oder!!.Kein Bediener erforderlich

Wenn str Null ist, fällt es natürlich mit einem schleimigen Po. Es macht keinen Sinn, es zu einem Nullable-Typ zu machen.

Mit dem Elvis-Operator auspacken

test.kt


var str = System.getProperty("hoge") ?: "Unknown Property"
var foo = str.length //str wird zu einem String-Typ

Dieses ?: Wird als Elvis-Operator bezeichnet und wertet den rechten Ausdruck aus, wenn das Ergebnis des linken Ausdrucks von?: Null ist.

test.java


String str = System.getProperty("hoge") != null ? System.getProperty("hoge") : "Unknown Property";

Synonym zu.

Selbst wenn Systrem.getProperty ("hoge") Null ist, wird zu diesem Zeitpunkt ein dedizierter Wert zurückgegeben str wird zu "String type" und foo wird zu "Int type". Der Typ Nullable ist weg, und Sie können jetzt sicher mit Variablen umgehen.

Wenn Sie keinen dedizierten Wert zurückgeben möchten, dh wenn er Null ist, möchten Sie die nachfolgende Verarbeitung nicht fortsetzen.

test.kt


var str = System.getProperty("hoge") ?: return //str wird zu einem String-Typ

Wenn dann "System.getProperty (" hoge ")" Null ist, können Sie die Verarbeitung dieses Blocks beenden.

Praktische Geschichte

test.kt


var str = System.getProperty("hoge") ?: return //str wird zu einem String-Typ

Durch das Auspacken fällt es nicht mehr schleimig ab, Es ist jedoch nicht möglich, einen Fehler zu erkennen, indem der Prozess ohne Fehler zurückgegeben und beendet wird. Erstens sollte dieser Code davon ausgehen, dass System.getProperty ("hoge") nicht null erhält.

Wenn Sie unerwartete Rückgaben erkennen möchten, ohne schleimig zu werden

test.kt


var str = System.getProperty("hoge") ?: run {
   println("Property was not found!!!")
   return
}

Es ist notwendig, eine Art Protokoll so auszuspucken. Die Erklärung von "run" wird weggelassen, da sie außerhalb dieses Bereichs liegt.

Praktische Geschichte 2

Wie Android View kann es zum Zeitpunkt der Instanziierung nicht initialisiert werden. Es gibt auch Fälle, in denen es innerhalb einer bestimmten Methode wie "onCreate" initialisiert werden muss.

test.kt


class HogeActivity: AppCompatActivity(){

    private var textView: TextView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.hoge_layout)
        textView = findViewById(R.id.textView) as TextView
    }
}

Da textView nur abgerufen werden kann, wenn es mit onCreate aufgeblasen ist, Der Anfangswert muss null sein. In diesem Fall ist der Typ wie TextView?

Es gibt zwei Ansätze, um diese Textansicht ungleich Null zu machen.

Verwenden Sie den Modifikator lateinit

lateinit ist ein Operator für die verzögerte Auswertung der Initialisierung, und die Kompilierung kann durchgeführt werden, ohne den Anfangswert beim Definieren von Variablen festzulegen.

test.kt


class HogeActivity: AppCompatActivity(){

    private lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.hoge_layout)
        textView = findViewById(R.id.textView) as TextView
    }
}

Es ist nicht mehr erforderlich, den Anfangswert gleichzeitig mit der Variablendeklaration festzulegen, da? Aus dem textView-Typ entfernt wird. Der Wert wird zum ersten Mal mit findViewById in textView eingegeben.

Bei lateinit ist jedoch zu beachten, dass es nur für Variablen (var) verwendet werden kann. Wenn Getter aufgerufen wird, bevor Setter aufgerufen wird, stürzt es ab.

von faul benutzen

Die Erklärung von "by" ist allein dadurch etwas kompliziert, daher werde ich sie nicht im Detail erklären. Ein Modifikator, mit dem Sie Eigenschafteneinstellungen an eine andere Klasse delegieren können. faul ist eine Funktion, die ausgeführt wird, wenn Sie zum ersten Mal auf eine Eigenschaft zugreifen, die faul definiert.

Durch die Kombination der beiden kann die Variableninitialisierung von jeder Funktion in einer anderen Klasse durchgeführt werden.

test.kt


class HogeActivity: AppCompatActivity(){

    private val textView: TextView by lazy { findViewById(R.id.textView) as TextView }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.hoge_layout)
    }
}

Auf diese Weise befindet sich der textView-Getter beim ersten Aufruf vor dem Getter. findViewById(R.id.textView) as TextView Wird ausgeführt und der Anfangswert eingegeben.

Durch faul kann dagegen nur für Konstanten (val) verwendet werden. Stattdessen müssen Sie sich keine Sorgen machen, dass Sie wie lateinit abstürzen.

Wenn Sie faul verwenden können, denke ich, ist es besser, dies zu verwenden. Wird lateinit in Fällen wie DI-Dolch verwendet, der von einer anderen Klasse definiert wird?

schließlich

Null-Sicherheit ist ein mächtiges Merkmal, aber es ist keine Silberkugel, die alles löst. Im Gegenteil, es kann gesagt werden, dass es die Ausbreitung von Defekten auf andere Quellen verhindert, weil es schleimig abfällt.

Wenn ich die Null-Sicherheitsfunktion verwende, möchte ich die Gefahr dahinter verstehen, bevor ich sie verwende.

Recommended Posts

[Null-Sicherheit] Kotlin Java-Vergleichsnotiz Richtige Verwendung der Null-Sicherheit
[Java] Korrekter Vergleich des String-Typs
[Java] benutze Optional anstelle von if (hoge! = Null) {...}
[Java] Geschwindigkeitsvergleich der Zeichenfolgenkombination
Kotlin-Generika für Java-Entwickler
Vergleich von null-toleranten, null-toleranten und null-toleranten sicheren Typen aus der Perspektive der Null-Sicherheit
Anmerkung: [Java] Überprüfen Sie den Inhalt des Verzeichnisses
[Java] [Maven3] Zusammenfassung der Verwendung von Maven3
Memo zur Überwachungsmethode für Verzeichnisänderungen (Java, Kotlin)
Kotlins Null-Sicherheit zum Senden an Java-Entwickler
Memo für die Migration von Java nach Kotlin
[Java] Warum StringUtils.isEmpty () anstelle von String.isEmpty () verwenden?
Java-Memo
Verwenden Sie jenv, um mehrere Java-Versionen zu aktivieren
Die Geschichte des einfachen String-Vergleichs in Java
[Java / Kotlin] Ändern Sie die Größe unter Berücksichtigung der Ausrichtung des Bildes