我最想念Java的Kotlin功能– 科特林 vs Java

让我们写一篇涵盖“ 科特林 vs Java”主题的文章-我想告诉你回到Java时我最想念的Kotlin功能。

我作为Java开发人员的生活

虽然我很大 支持者科特林 编程语言,我仍然每天为老板做很多Java编程。因为我知道Kotlin的强大功能,所以我经常在Java上苦苦挣扎,因为Java有一些“陷阱”,需要额外的样板并且缺少许多功能。
在这篇文章中,我想描述一下用Java编码时最想念的Kotlin功能。

new 和分号

Ever since I'm doing 科特林, there are two things I always forget when coding in Java: the new keyword for constructor invocations 和 the annoying ; to complete statements. 科特林 doesn't have new 和 even semicolons are optional. I really appreciate this decision because it reduces the "句法噪音”。

资料类别

In 科特林, data classes are used for simple data containers, representing JSON objects or returning compound objects from functions amongst other use cases. Of course, Java doesn't support this special type of classes yet. As a result, I often have to implement my own data class, which means a lot of boilerplate in Java.

One special use case is compound objects returned from functions. For example, let's imagine a function that needs to return two objects. In 科特林 we could use a data class, or simpler, a Pair directly. In Java, I tend to create a 价值对象,这是一个具有多个final字段的类,每个字段都通过构造函数实例化。与Kotlin相似,我没有实施 吸气剂二传手, but use the class's fields directly as public properties. Unfortunately, this is not what we learned as best practice 和 most Java code style checkers will complain about it. I do not see any encapsulation issues here 和 it's the least verbose approach in Java. The following shows such a compound object, the inner class Multi. In 科特林 this would be a one-liner.

public class MultiReturn {

    公共静态void main(String [] args){
        new MultiReturn().useMulti();
    }

    public void useMulti() {
        Multi multi = helper();
        System.out.println("Multi with " + multi.count + " 和 " + multi.name);
    }

    private Multi helper() {
        return new Multi(2, "test");
    }
    
    private static class Multi {
        private final int count;
        private final String name;

        public Multi(int count, String name) {
            this.count = count;
            this.name = name;
        }
    }
}

局部功能

In many situations, we tend to create private methods that are only used inside another single method in order to make this one more readable. In 科特林, we 能够 use local functions, i.e. functions inside functions (inside functions...), which enables some kind of scope. For me, this is a much cleaner approach, because the function is only accessible inside the function that actually uses the local one. Let's look at an example.


fun deployVerticles() {

    fun deploy(verticleClassName: String) {
        vertx.deployVerticle(verticleClassName, opt, { deploy ->
            LOG.info("$verticleClassName has been deployed? ${deploy.succeeded()}")
        })
    }

    deploy("ServiceVerticle")
    deploy("WebVerticle")
}

取自一个样本 版本号 应用程序,并定义一个本地函数,此函数以后将重用两次。简化代码的好方法。

单表达函数

We 能够 create single expression functions in 科特林, i.e. functions without an actual body. Whenever a function contains only a single expression, it 能够 be placed after a = sign following the function declaration:


fun trueOrFalse() = Random().nextBoolean()

In Java, on the other hand, we always have to use a function body enclosed in {}, which ranges over at least three lines. This is also "句法噪音" I don't want to see anymore. To be fair, Java 1.8 makes it possible to define lambdas which 能够 also solve this, less readable though (Can also be applied to local functions):


public class SingleExpFun {

    private BooleanSupplier trueOrFalse = new Random()::nextBoolean;

    private boolean getNext(){
        return trueOrFalse.getAsBoolean();
    }
}

默认参数

Java的一个非常烦人的部分是必须重载方法的方式。让我们来看一个例子:

public class Overloade
    公共静态void main(String [] args){
        Overloader o =新的Overloader();
        o.testWithoutPrint(2);
        o.test(2);
    }

    public void test(int a, boolean printToConsole) {
        if (printToConsole) System.out.println("int a: " + a);
    }

    public void testWithoutPrint(int a) {
        test(a, false);
    }

    public void test(int a) {
        test(a, true);
    }

}

We 能够 see a class with a method test(int, boolean) that is overloaded for the default case 和 also a convenience method is available. For more complex examples, it 能够 lead to a lot of redundant code, which is simpler in 科特林 通过 using default parameters.


fun test(a: Int, printToConsole: Boolean = true) {
    if (printToConsole) println("int a: " + a)
}

fun testWithoutPrint(a: Int) = test(a, false)

fun main(args: Array) {
    testWithoutPrint(2)
    test(2)
}

Calling multiple methods on an object instance (with)

Obviously, 科特林 is more functional than Java. It makes use of higher-order functions in incredibly many situations 和 provides many standard library functions that 能够 be used as such. One of my favorites is with, which I miss a lot whenever I 能够't use 科特林. The with function 能够 be used to create scopes that actually increase the readability of code. It's always useful when you sequentially call multiple functions on a single object.


class Turtle {
    fun penDown()
    fun penUp()
    fun turn(degrees: Double)
    fun forward(pixels: Double)
}

with(Turtle()) {
    penDown()
    for(i in 1..4) {
        forward(100.0)
        turn(90.0)
    }
    penUp()
}

很棒的是 带接收器的lambda,您可以在我的另一本中阅读 帖子.

空安全

Whenever I work with nullable types since the time I started with 科特林, I actually miss the type system's tools to prevent null-related errors. 科特林 did a very good job 通过 distinguishing nullable types from not-nullable ones. If you strictly make use 的se tools, there is no chance you'll ever see a NullpointerException at runtime.

Lambda和收集处理

科特林 places a lot of value on its lambdas. As shown in the with example earlier, there's special syntax available for lambdas that makes its usage even more powerful. I want to underline that the way functions 和 especially lambdas are treated in the language makes it dramatically superior to Java. Let's see a simple example of Java's Streams, which were introduced along with lambdas in Java 1.8:

List list = people.stream().map(Person::getName).collect(Collectors.toList());

It's a rather simple example of a Stream that is used to get a list of names from a list of persons. Compared to what we did before 1.8, this is awesome. Still, it's too noisy compared to a 真正的功能 科特林追求的方法:

val list = people.map { it.name }

还是另一个示例,其中员工的薪金总和为:

int total = employees.stream()
                      .collect(Collectors.summingInt(Employee::getSalary)));

在Kotlin中简单得多:

val total = employees.sumBy { it.salary }

科特林示例显示了它的简单性 能够 是。 Java不是一种功能语言,并且很难尝试采用lambda和stream之类的功能特性,正如我们在代码片段中可以轻易看到的那样。如果您曾经体验过Kotlin的美丽,那么回到Java真的很糟糕。您是否曾经在熟悉IntelliJ之后尝试使用Eclipse?你知道我的意思了。

包起来

在这篇简短的文章中,我向您介绍了我在使用Java编码时经常会错过的Kotlin顶级功能。只是一些选择,希望它们很快会进入Java语言。但是老实说,当已经有一种更甜的语言可用时,没有理由总是等待Java ...我想指出的是,从Kotlin开始确实使我成为了一个更好的程序员,因为我开始对某些功能感到好奇通过这两种语言,还尝试通过找到变通办法(例如以不同的方式安排我的代码)来找到在Java中使用Kotlin专用的方法。

我会对您最喜欢的功能感兴趣,请随时发表评论。
另外,如果你愿意,看看我的 推特 帐户,如果您对更多Kotlin产品ðŸ™感兴趣,请关注。非常感谢。

如果您想了解有关Kotlin的美丽功能的更多信息,请推荐这本书 行动中的科特林 和我的 其他文章 给你。

关于15条想法“我最想念Java的Kotlin功能– 科特林 vs Java

  • n

    在(是否有Java)流上进行聚合和映射与在容器上进行聚合和映射实际上并不相同。换句话说,Java8没有’具备flatMap等的功能。与Kotlin或Scala不同的是任意容器。

  • 汤姆

    感谢您的精彩文章。帮助我了解有关Kotlin的更多信息。

    下“Default Parameters” section, I didn’但是在Java类中没有任何重载的方法。我认为将遵循以下类似的代码。如果我请纠正我’m wrong.

    公共类重载器{
    公共静态void main(String [] args){
    Overloader o =新的Overloader();
    o.testWithoutPrint(2);
    o.testWithPrint(2);
    }

    public void test(int a, boolean printToConsole) {
    if (printToConsole) System.out.println("int a: " + a);
    }

    // overloaded method here
    public void test(int a) {
    test(a, true);
    }

    public void testWithoutPrint(int a) {
    test(a, false);
    }

    }

  • 马库斯·克鲁格

    不错的概述!不过,有些挑剔。虽然Java没有’t具有局部函数,但确实具有局部类,这些局部类仅在声明它们的块内部可见。您可以通过将函数作为本地类中的方法来用Java实现您的本地函数示例。如果你’对当地的课程不熟悉’的不错的概述 //docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html.

    Another way to fake local functions in Java would be to use a lambda: declare a local variable Consumer deploy = (verticleClassName) -> { ... }; 和 invoke deploy.apply("ServiceVerticle"). Not as pretty, but still accomplishes the goal of encapsulating the function.

    不确定Java的意思是什么 ’t have single expression functions. You 能够 write BooleanSupplier trueOrFalse = new Random()::nextBoolean; in Java. No curly brackets required. Similarly, you could say IntUnaryOperator addTwo = i -> i + 2; for arbitrary single expressions.

  • 我认为它’值得一提的是Kotlin不仅支持可选的函数参数,而且还支持Python等命名参数。这样就可以编写类似join(parts:List,delimiter:String =“, “, prefix: String = “[“, suffix: String = “]”)并使用join(listOf(“foo”, “bar”), prefix = “(“, suffix = “)”),因此导致“[foo, 酒吧]”.

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *