Kotlin VS Java - Яку мову програмування слід вивчати в 2020 році?

Минуло кілька років з тих пір, як Котлін вийшов, і у нього все вийшло. Оскільки він був створений спеціально для заміни Java, Kotlin природно порівнювався з Java у багатьох відношеннях.

Щоб допомогти вам вирішити, яку з двох мов вам вибрати, я порівняю деякі основні особливості кожної мови, щоб ви могли вибрати ту, яку хочете вивчити.

Ось 8 пунктів, які я обговорю в цій статті:

  • Синтаксис
  • Лямбда-вирази
  • Нульова обробка
  • Модельні класи
  • Глобальні змінні
  • Паралельність
  • Функції розширення
  • Громада

Порівняння синтаксису

Для початку давайте порівняємо базовий синтаксис. Багато з вас, хто читає це, можливо, вже мають певні знання про Java та / або Kotlin, але я наведу базовий приклад нижче, щоб ми могли порівняти їх безпосередньо:

Java

public class HelloClass { public void FullName(String firstName, String lastName) { String fullName = firstName + " " + lastName; System.out.println("My name is : " + fullName); } public void Age() { int age = 21; System.out.println("My age is : " + age); } public static void main(String args[]) { HelloClass hello = new HelloClass(); hello.FullName("John","Doe"); hello.Age(); } } 

Котлін

class NameClass { fun FullName(firstName: String, lastName:String) { var fullName = "$firstName $lastName" println("My Name is : $fullName") } } fun Age() { var age : Int age = 21 println("My age is: $age") } fun main(args: Array) { NameClass().FullName("John","Doe") Age() }

Відчуття коду не так відрізняється, окрім деяких невеликих змін синтаксису в методах та класах.

Але справжня різниця тут полягає в тому, що Kotlin підтримує умовивід типу, де тип змінної не потрібно оголошувати. Також нам більше не потрібні крапки з комою ( ;).

Ми також можемо відзначити, що Kotlin не застосовує суворо ООП, як Java, де все повинно міститися всередині класу. Погляньте fun Ageі fun mainв прикладі , де не міститься всередині якого - або класу.

Котлін також зазвичай має менше рядків кодів, тоді як Java дотримується більше традиційного підходу робити все багатослівним.

Однією з переваг Kotlin перед Java є гнучкість Kotlin - він може зробити все за традиційним підходом ООП, або може піти іншим шляхом.

Лямбда-вирази

Якщо ми говоримо про Яву та Котлін, звичайно, ми повинні говорити про відомий вираз лямбда. Kotlin має рідну підтримку лямбда (і завжди є), тоді як лямбда вперше була представлена ​​в Java 8.

Подивимось, як вони обидва виглядають.

Java

//syntaxes parameter -> expression (parameter1, parameter2) -> { code } //sample usage ArrayList numbers = new ArrayList(); numbers.add(5); numbers.add(9); numbers.forEach( (n) -> { System.out.println(n); } );

Котлін

//syntax { parameter1, parameter2 -> code } //sample usage max(strings, { a, b -> a.length < b.length })

У Java дужки є більш м’якими: якщо існує лише один параметр, дужки не потрібні. Але в Котліні завжди потрібні дужки. У цілому, однак, не так багато відмінностей, окрім синтаксису.

На мій погляд, лямбда-функції не будуть використовуватися багато, крім використання їх як методів зворотного виклику. Незважаючи на те, що лямбда-функції мають набагато більше застосувань, проблеми читабельності роблять це менш бажаним. Вони скоротять ваш код, але розібратися з ним згодом буде набагато складніше.

Це лише питання переваг, але я думаю, що корисно, що Котлін застосовує обов’язкові дужки, щоб допомогти з читабельністю.

Нульова обробка

В об'єктно-орієнтованій мові значення нульового типу завжди були проблемою. Ця проблема виникає у формі винятку Null Pointer (NPE), коли ви намагаєтесь використовувати вміст нульового значення.

Оскільки NPE завжди були проблемою, і Java, і Kotlin мають свій власний спосіб обробки нульових об'єктів, як я покажу нижче.

Java

Object object = objServ.getObject(); //traditional approach of null checking if(object!=null){ System.out.println(object.getValue()); } //Optional was introduced in Java 8 to further help with null values //Optional nullable will allow null object Optional objectOptional = Optional.ofNullable(objServ.getObject()); //Optional.of - throws NullPointerException if passed parameter is null Optional objectNotNull = Optional.of(anotherObj); if(objectOptional.isPresent()){ Object object = objectOptional.get(); System.out.println(object.getValue()); } System.out.println(objectNotNull.getValue());

Котлін

//Kotlin uses null safety mechanism var a: String = "abc" // Regular initialization means non-null by default a = null // compilation error //allowing null only if it is set Nullable var b: String? = "abc" // can be set null b = null // ok print(b)

Оскільки я пам’ятаю, Java використовує традиційну перевірку нуля, яка схильна до людських помилок. Потім Java 8 вийшла з додатковими класами, які дозволяють проводити більш надійну перевірку нуля, особливо з боку API / сервера.

Kotlin, з іншого боку, забезпечує нульові змінні безпеки, де змінна повинна бути нульовою, якщо значення може бути нульовим.

Я ще не користувався додатковим класом, але механізм і мета здаються досить схожими на нульову безпеку Котліна. І те, і інше допомагає визначити, яка змінна може бути нульовим значенням, і переконатися, що здійснено правильну перевірку.

Іноді в коді може лежати занадто багато змінних і занадто багато для перевірки. Але додавання перевірки скрізь робить нашу базу коду потворною, і це нікому не подобається, правда?  

На мій погляд, однак, використання додаткової мови Java виглядає трохи брудно через кількість коду, який потрібно додати для перевірки. Тим часом у Котліні ви можете просто додати невелику кількість коду, щоб зробити для вас нульову перевірку.

Клас моделі

Деякі люди можуть також називати це класом Entity. Нижче ви можете побачити, як обидва класи використовуються як модельні класи для кожної мови.

Java

public class Student { private String name; private Integer age; // Default constructor public Student() { } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAge(Integer age) { this.age = age; } public Integer getAge() { return age; } }

Котлін

//Kotlin data class data class Student(var name: String = "", var age: Int = 0) //Usage var student: Student = Student("John Doe", 21)

In Java, properties are declared as private, following the practice of encapsulation. When accessing these properties, Java uses Getters and Setters, along with the isEqual or toString methods when needed.

On the Kotlin side, data classes are introduced for the special purpose of model classes. Data classes allow properties to be directly accessed. They also provide several in-built utility methods such as equals(), toString() and copy().

For me, data classes are one of the best things Kotlin offers. They aim to reduce the amount of the boilerplate code you need for regular model classes, and they do a really good job of that.

(contact me for the full resoluton image)

Global Variables

Sometimes your code might need a variable needs to be accessed everywhere in your code base. This is what global variables are used for. Kotlin and Java each have their own ways of handling this.

Java

public class SomeClass { public static int globalNumber = 10; } //can be called without initializing the class SomeClass.globalNumber;

Kotlin

class SomeClass { companion object { val globalNumber = 10 } } //called exactly the same like usual SomeClass.globalNumber

Some of you might already be familiar with the static keyword here since it's also used in some other language like C++. It's initialized at the start of a program's execution, and is used by Java to provide global variables since it is not contained as an Object. This means it can be accessed anywhere without initializing the class as an object.

Kotlin is using quite a different approach here: it removes the static keyword and replaces it with a companion object which is pretty similar to a singleton. It let's you implement fancy features such as extensions and interfacing.

The lack of the static keyword in Kotlin was actually quite surprising for me. You could argue that using the static keyword might not be a good practice because of its nature and because it's difficult to test. And sure, the Kotlin companion object can easily replace it.

Even then, using static for global variable should be simple enough. If we are careful with it and don't make it a habit of making every single thing global, we should be good.

The companion object might also give us some flexibility with interfacing and such, but how often will we ever be interfacing singleton classes?

I think static keywords help us keep things short and clean for global variables.

Concurrency

Nowadays, concurrency is a hot topic. Sometimes the ability of a programming language to run several jobs concurrently might help you decide if that will be your language of choice.

Let's take a look at how both languages approach this.

Java

 // Java code for thread creation by extending // the Thread class class MultithreadingDemo extends Thread { public void run() { try { // Displaying the thread that is running System.out.println ("Thread " + Thread.currentThread().getId() + " is running"); } catch (Exception e) { // Throwing an exception System.out.println ("Exception is caught"); } } } // Main Class public class Multithread { public static void main(String[] args) { int n = 8; // Number of threads for (int i=0; i

Kotlin

for (i in 1..1000) GlobalScope.launch { println(i) } 

Java mostly uses threads to support concurrency. In Java, making a thread requires you to make a class that extends to the in-built Java thread class. The rest of its usage should be pretty straightforward.

While threads are also available in Kotlin, you should instead use its coroutines. Coroutines are basically light-weight threads that excel in short non-blocking tasks.

Concurrency has always been a hard concept to grasp (and also, to test). Threading has been used for a long time and some people might already been comfortable with that.

Coroutines have become more popular lately with languages like Kotlin and Go (Go similarly has goroutines). The concept differs slightly from traditional threads – coroutines are sequential while threads can work in parallel.

Trying out coroutines, though, should be pretty easy since Kotlin does a very good job explaining them in their docs.  And one bonus for Kotlin over Java is the amount of boilerplate code that can be removed in Kotlin.

Extension Functions

You might be wondering why I'm bringing these up since Java itself doesn't even have this feature.

But I can't help but mention it, because extension functions are a very useful feature that was introduced in Kotlin.

fun Int.plusOne(): Int { return this + 1 } fun main(args: Array) { var number = 1 var result = number.plusOne() println("Result is: $result") }

They allow a class to have new functionality without extending it into the class or using any of the fancy Design Patterns.  It even lets you to add functionality to Kotlin variable classes.

You can practically say goodbye to those lib method that need you to pass everything inside your parameters.

Community

Last but not least, let's talk about something non-technical. First, let's take a look at this survey showing top commonly used programming languages in 2020.

Original text


We can see that Java is one of the most commonly used languages. And while Kotlin is still rising a lot in popularity, the Java community still remains several times larger than Kotlin and it will probably not change anytime soon.

So what does that matter then? Actually it does matter, a lot. With the amount of people in the Java community, it's much easier to find references and get help when you need it, both on the Internet and in the real world.

Many companies are also still using Java as their base and it might not change anytime soon even with Kotlin's interoperability with Java. And usually, doing a migration just doesn't serve any business purpose unless the company has really really important reasons for it.

Wrapping up

For those just scrolling for the summary, here's what we discussed:

  • Syntax: the patterns don't differ that much aside from slight syntax differences, but Kotlin is more flexible in several aspects.
  • Lambda Expressions: the syntax is almost the same, but Kotlin uses curly brackets to help readability.
  • Null Handling: Java uses a class to help with null handling while Kotlin uses in-built null safety variables.
  • Model Classes: Java uses classes with private variables and setter / getter while Kotlin supports it with data classes.
  • Global Variables: Java uses the static keyword while Kotlin uses something akin to sub-classes.
  • Concurrency: Java uses multi-threading whereas Kotlin uses coroutines (which are generally lighter).
  • Extension Functions: a new feature introduced by Kotlin to easily give functionality into classes without extending it.
  • Community: Java still reigns supreme in the community aspect which makes it easier to learn and get help.

There are many more features we could compare between Java and Kotlin. But what I've discussed here are, in my opinion, some of the most important.

I think Kotlin is well worth picking up at the moment. From the development side it helps you remove long boilerplate code and keep everything clean and short. If you are already a Java programmer, learning Kotlin shouldn't be too hard and it's okay to take your time at it.

Thanks for reading! I hope that this article will help you decide which programming language you should pick, Java or Kotlin. And for anything that I'm missing, feel free to leave feedback for me as it will be very much appreciated.