Kotlin只是一个“网红,【面试必备】

fun doSth(text: String) {
val f: String = Utils.format(text) // compiles but assignment can throw NPE at runtime
println ("f.len : " + f.length)
}


那你就需要用 Elvis 来解决这个问题:

fun doSth(text: String) {
val f: String = Utils.format(text) ?: “” // safe with Elvis
println ("f.len : " + f.length)
}


第二种方法:你可以使用 String,能够保证 Null 安全性。

fun doSth(text: String) {
val f: String? = Utils.format(text) // safe
println ("f.len : " + f.length) // compilation error, fine
println ("f.len : " + f?.length) // null-safe with ? operator
}


第三种方法:让 Kotlin 做局部变量类型推断如何?

fun doSth(text: String) {
val f = Utils.format(text) // f type inferred as String!
println ("f.len : " + f.length) // compiles but can throw NPE at runtime
}


馊主意!这个 Kotlin 代码看起来很安全、可编译,但是它容忍了空值,就像在 Java 中一样。除此之外,还有另外一个方法,就是强制将 f 类型推断为 String:

fun doSth(text: String) {
val f = Utils.format(text)!! // throws NPE when format() returns null
println ("f.len : " + f.length)
}


在我看来,Kotlin 的所有这些类似 scala 的类型系统过于复杂。Java 互操作性似乎损害了 Kotlin 类型推断这个重量级功能。**类名称字面常量**使用类似 Log4j 或者 Gson 的 Java 库时,类文字很常见。Java 使用 .class 后缀编写类名:

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDate.class, new LocalDateAdapter()).create();


Groovy 把类进行了进一步的简化。你可以忽略 .class,它是 Groovy 或者 Java 类并不重要。

def gson = new GsonBuilder().registerTypeAdapter(LocalDate, new LocalDateAdapter()).create()


Kotlin 把 Kotlin 类和 Java 类进行了区分,并为其提供了语法规范:

val kotlinClass : KClass = LocalDate::class
val javaClass : Class = LocalDate::class.java


因此在 Kotlin 中,你必须写成如下形式:

val gson = GsonBuilder().registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()).create()


这看起来非常丑陋。**反向类型声明**C 系列的编程语言有标准的声明类型的方法。简而言之,首先指定一个类型,然后是该符合类型的东西,比如变量、字段、方法等等。Java 中的表示方法是:

int inc(int i) {
return i + 1;
}


Kotlin 中则是:

fun inc(i: Int): Int {
return i + 1
}


这种方法有几个原因令人讨厌。首先,你需要在名称和类型之间加入这个多余的冒号。这个额外角色的目的是什么?为什么名称与其类型要分离?我不知道。可悲的是,这让你在 Kotlin 的工作变得更加困难。第二个问题,当你读取一个方法声明时,你首先看到的是名字和返回类型,然后才是参数。在 Kotlin 中,方法的返回类型可能远在行尾,所以需要浏览很多代码才能看到:

private fun getMetricValue(kafkaTemplate : KafkaTemplate<String, ByteArray>, metricName : String) : Double {

}


或者,如果参数是逐行格式的,则需要搜索。那么我们需要多少时间才能找到此方法的返回类型呢?

@Bean
fun kafkaTemplate(
@Value("${interactions.kafka.bootstrap-servers-dc1}") bootstrapServersDc1: String,
@Value("${interactions.kafka.bootstrap-servers-dc2}") bootstrapServersDc2: String,
cloudMetadata: CloudMetadata,
@Value("${interactions.kafka.batch-size}") batchSize: Int,
@Value("${interactions.kafka.linger-ms}") lingerMs: Int,
metricRegistry : MetricRegistry
): KafkaTemplate<String, ByteArray> {
val bootstrapServer = if (cloudMetadata.datacenter == “dc1”) {
bootstrapServersDc1
}

}


第三个问题是 IDE 中的自动化支持不够好。标准做法从类型名称开始,并且很容易找到类型。一旦选择一个类型,IDE 会提供一些关于变量名的建议,这些变量名是从选定的类型派生的,因此你可以快速输入这样的变量:

MongoExperimentsRepository repository


Kotlin 尽管有 IntelliJ 这样强大的 IDE,输入变量仍然是很难的。如果你有多个存储库,在列表中很难实现正确的自动补全,这意味着你不得不手动输入完整的变量名称。

repository : MongoExperimentsRepository


**伴生对象**一位 Java 程序员来到 Kotlin 面前。

> “嗨,Kotlin。我是新来的,我可以使用静态成员吗?"他问。 “不行。我是面向对象的,静态成员不是面向对象的。” Kotlin 回答。 “好吧,但我需要 MyClass 的 logger,我该怎么办?” “这个没问题,使用伴生对象即可。” “那是什么东西?” “这是局限到你的类的单独对象。把你的 logger 放在伴生对象中。”Kotlin解释说。 “我懂了。这样对吗?”

class MyClass {
companion object {
val logger = LoggerFactory.getLogger(MyClass::class.java)
}
}


> “正确!” “很详细的语法,”程序员看起来很疑惑,“但是没关系,现在我可以像 MyClass.logger 这样调用我的 logger,就像 Java 中的一个静态成员?” “嗯......是的,但它不是静态成员!这里只有对象。把它看作是已经实例化为单例的匿名内部类。事实上,这个类并不是匿名的,它的名字是 Companion,但你可以省略这个名字。看到了吗?这很简单。"

我很欣赏对象声明的概念——单例很有用。但从语言中删除静态成员是不切实际的。在 Java 中我们使用静态 Logger 很经典,它只是一个 Logger,所以我们不关心面向对象的纯度。它能够工作,从来没有任何坏处。因为有时候你必须使用静态。旧版本 public static void main() 仍然是启动 Java 应用程序的唯一方式。

class AppRunner {
companion object {
@JvmStatic fun main(args: Array) {
SpringApplication.run(AppRunner::class.java, *args)
}
}
}


**集合字面量**在Java中,初始化列表非常繁琐:

import java.util.Arrays;

List strings = Arrays.asList(“Saab”, “Volvo”);


初始化地图非常冗长,很多人使用 Guava:

import com.google.common.collect.ImmutableMap;

Map<String, String> string = ImmutableMap.of(“firstName”, “John”, “lastName”, “Doe”);


在 Java 中,我们仍然在等待新的语法来表达集合和映射。语法在许多语言中非常自然和方便。
JavaScript:

const list = [‘Saab’, ‘Volvo’]
const map = {‘firstName’: ‘John’, ‘lastName’ : ‘Doe’}


Python:

list = [‘Saab’, ‘Volvo’]
map = {‘firstName’: ‘John’, ‘lastName’: ‘Doe’}


Groovy:

def list = [‘Saab’, ‘Volvo’]
def map = [‘firstName’: ‘John’, ‘lastName’: ‘Doe’]


简单来说,集合字面量的整齐语法就是你对现代编程语言的期望,特别是如果它是从头开始创建的。Kotlin 提供了一系列内置函数,比如 listOf()、mutableListOf()、mapOf()、hashMapOf() 等等。
Kotlin:

val list = listOf(“Saab”, “Volvo”)
val map = mapOf(“firstName” to “John”, “lastName” to “Doe”)


在地图中,键和值与 to 运算符配对,这很好。但为什么一直没有得到广泛使用呢?令人失望。**Maybe**函数式语言(比如 Haskell)没有空值。相反,他们提供 Maybe monad(如果你不熟悉monad,请阅读 Tomasz Nurkiewicz 的这篇文章:[http://www.nurkiewicz.com/2016/06/functor-and-monad-examples-in-plain-java.html](

))。Maybe 很久以前就被 Scala 以 Option 引入到 JVM 世界,然后在 Java 8 中被采用为 Optional。如今,Optional 是在 API 边界处理返回类型中的空值的非常流行的方式。Kotlin 中没有 Optional 的等价物,所以你大概应该使用 Kotlin 的可空类型。让我们来调查一下这个问题。通常情况下,当你有一个 Optional 的时候,你想要应用一系列无效的转换。例如,在 Java 中:

public int parseAndInc(String number) {
return Optional.ofNullable(number)
.map(Integer::parseInt)
.map(it -> it + 1)
.orElse(0);
}


在 Kotlin 中,为了映射你可以使用 let 函数:

fun parseAndInc(number: String?): Int {
return number.let { Integer.parseInt(it) }
.let { it -> it + 1 } ?: 0
}

最后

总而言之,面试官问来问去,问的那些Redis知识点也就这么多吧,复习的不够到位,知识点掌握不够熟练,所以面试才会卡壳。将这些Redis面试知识解析以及我整理的一些学习笔记分享出来给大家参考学习

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

还有更多学习笔记面试资料也分享如下:

都是“Redis惹的祸”,害我差点挂在美团三面,真是“虚惊一场”

  • 1 } ?: 0
    }

最后

总而言之,面试官问来问去,问的那些Redis知识点也就这么多吧,复习的不够到位,知识点掌握不够熟练,所以面试才会卡壳。将这些Redis面试知识解析以及我整理的一些学习笔记分享出来给大家参考学习

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

还有更多学习笔记面试资料也分享如下:

[外链图片转存中…(img-LVzpbnMY-1631174952474)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值