简书链接:kotlinvsjava用法和java替代方案 文章字数:3884,阅读全文大约需要15分钟
1 2 3 4 5 6 7 8 9 10 11 var email=null; email?: println("email is empty"); email?.let{ println("emali not empty"); } var current= email?.let { "nihao" }?:"not i fuck i am null"; println("current var ${current}");
Kotlin 和 Java 是两种不同的编程语言,它们有许多不同的语法和特性。下面我将列出几个 Kotlin 和 Java 的语法比较,并且解释一些 Kotlin 中常用的语法糖在 Java 中的替代方案。
可空类型 Kotlin 中的可空类型是一个非常有用的特性,可以避免空指针异常。Java 中也有类似的概念,但需要手动判断是否为 null,例如:
java
1 2 3 4 String str = null; if(str != null) { System.out.println(str.length()); }
而在 Kotlin 中,可以直接使用安全调用运算符 ?. 来避免 null 异常,例如:
kotlin
1 2 val str: String? = null println(str?.length)
扩展函数 Kotlin 中的扩展函数是一种便利的方式来添加新的行为到现有的类上。Java 中没有扩展函数,但可以通过创建一个工具类并将方法声明为静态方法来实现类似的功能,例如:
kotlin
1 2 3 4 fun String.lastChar(): Char = this[length - 1] val str = "Hello World" val lastChar = str.lastChar()
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static char lastChar(String str) { return str.charAt(str.length() - 1); } String str = "Hello World"; char lastChar = StringUtil.lastChar(str); public class StringUtils { public static boolean isNullOrEmpty(String str) { return str == null || str.isEmpty(); } }
lambda 表达式 Kotlin 中的 lambda 表达式是一种轻量级的语法,可以用于定义匿名函数或简化回调函数的实现。Java 8 中也引入了 lambda 表达式,但语法略有不同,例如:
kotlin
1 2 3 // Kotlin val list = listOf(1, 2, 3) list.forEach { println(it) }
1 2 3 // Java List<Integer> list = Arrays.asList(1, 2, 3); list.forEach((Integer i) -> System.out.println(i));
apply 函数 Kotlin 中的 apply 函数用于初始化对象并返回该对象本身。Java 中没有类似的语法糖,但可以通过创建一个构建器类并在其中定义构造方法和设置属性的方法来实现类似的功能,例如:
1 2 3 4 5 6 //kotlin val person = Person().apply { name = "John" age = 30 }
1 2 3 4 5 6 // Java Person person = new Person.Builder() .setName("John") .setAge(30) .build();
数据类 Kotlin 中的数据类是一种用于表示只包含数据的类的简洁方式。Java 中没有类似的语法糖,但可以通过手动添加 getter 和 setter 方法、equals() 和 hashCode() 方法等来实现类似的功能,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 //kotlin data class Person(val name: String, val age: Int) // Java public class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Person)) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } }
类型推断 Kotlin 中的类型推断可以让编译器根据上下文推断出变量的类型,使代码更加简洁。Java 10 中引入了 var 关键字来实现类似的功能,但仅限于局部变量,例如:
kotlin
1 2 3 4 5 6 7 8 // Kotlin val list = listOf(1, 2, 3) val sum = list.sum() // Java var list = List.of(1, 2, 3); var sum = list.stream().mapToInt(Integer::intValue).sum();
函数式编程 Kotlin 中支持函数式编程,例如高阶函数、lambda 表达式、尾递归等。Java 8 中也引入了一些支持函数式编程的特性,例如 Stream API 和 Optional 类,但相对于 Kotlin 来说还是有些繁琐,例如:
1 2 3 4 5 6 7 8 9 // Kotlin val list = listOf(1, 2, 3) val evenNumbers = list.filter { it % 2 == 0 } // Java List<Integer> list = Arrays.asList(1, 2, 3); List<Integer> evenNumbers = list.stream() .filter(x -> x % 2 == 0) .collect(Collectors.toList());
属性委托 Kotlin 中的属性委托是一种将属性的 get 和 set 方法委托给其他对象来实现的方式。Java 中没有类似的语法糖,但可以通过手动编写 getter 和 setter 方法并在其中调用其他对象的方法来实现类似的功能,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //kotlin var name: String by MyDelegate() // Java public class MyClass { private MyDelegate delegate = new MyDelegate(); public void setName(String name) { delegate.setValue(name); } public String getName() { return delegate.getValue(); } }
协程 Kotlin 中的协程是一种用于异步编程的轻量级线程。Java 中没有类似的语法糖,但可以使用线程池和 CompletableFuture 等类来实现类似的功能,例如:
1 2 3 4 5 //kotlin suspend fun loadUsers(): List<User> = withContext(Dispatchers.IO) { // 耗时操作 }
1 2 3 4 5 6 // Java ExecutorService executor = Executors.newFixedThreadPool(10); CompletableFuture<List<User>> future = CompletableFuture.supplyAsync(() -> { // 耗时操作 }, executor);
操作符重载 Kotlin 中支持对运算符进行重载,使得代码更加简洁易读。Java 中没有类似的语法糖,但可以手动编写方法来实现类似的功能,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //kotlin data class Point(val x: Int, val y: Int) { operator fun plus(other: Point): Point = Point(x + other.x, y + other.y) } // Java public class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } public Point plus(Point other) { return new Point(x + other.x, y + other.y); } }
注解 Kotlin 中的注解是一种用于添加元数据的方式,可以用于标记代码、指定运行时行为等。Java 中也有类似的概念,并且提供了许多内置注解,例如 @Override、@Deprecated 等,同时还支持自定义注解。
1 2 3 4 5 6 7 8 9 10 //kotlin @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class MyAnnotation(val value: String) @MyAnnotation("test") class MyClass { //... }
java
1 2 3 4 5 6 7 8 9 10 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value(); } @MyAnnotation("test") public class MyClass { //... }
扩展属性 Kotlin 中的扩展属性是一种用于为现有的类添加新的属性的方式。Java 中没有类似的语法糖,但可以通过创建一个包含 getter 和 setter 方法的接口并将其实现类与目标类组合来实现类似的功能,例如:
kotlin
1 2 3 4 5 6 var String.lastChar: Char get() = this[length - 1] set(value) { val sb = StringBuilder(this) sb.setCharAt(length - 1, value) }
// Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public interface LastCharAccessor { char getLastChar(); void setLastChar(char c); } public class MyString implements LastCharAccessor { private final String str; public MyString(String str) { this.str = str; } @Override public char getLastChar() { return str.charAt(str.length() - 1); } @Override public void setLastChar(char c) { StringBuilder sb = new StringBuilder(str); sb.setCharAt(str.length() - 1, c); } }
Lambda with receiver 在 Kotlin 中,Lambda 表达式可以带有接收者类型的参数,通常用于构建 DSL。Java 中没有类似的语法糖,但可以通过创建一个接口并将其实现类与目标对象组合来实现类似的功能,例如:
kotlin
1 2 3 4 5 6 7 8 9 10 11 12 13 fun buildString(action: StringBuilder.() -> Unit): String { val sb = StringBuilder() sb.action() return sb.toString() } // 使用 val str = buildString { append("Hello") append(" ") append("World") } println(str) // 输出 "Hello World"
1 2 3 4 5 6 7 8 9 10 11 12 13 // Java public interface StringBuilderAction { void apply(StringBuilder sb); } public class StringBuilderUtils { public static String buildString(StringBuilderAction action) { StringBuilder sb = new StringBuilder(); action.apply(sb); return sb.toString(); } }
// 使用
1 2 3 4 5 6 String str = StringBuilderUtils.buildString(sb -> { sb.append("Hello"); sb.append(" "); sb.append("World"); }); System.out.println(str); // 输出 "Hello World"
协程与异步编程 Kotlin 内置了协程支持,它是一种轻量级的并发编程方式,可以避免传统线程池带来的上下文切换和资源消耗问题。在 Kotlin 中,使用 suspend 关键字来标记挂起函数,这表示该函数可能会暂停执行,并且可以在挂起函数中使用 delay() 等函数来实现非阻塞式的等待操作。
kotlin
1 2 3 4 5 6 7 8 9 10 suspend fun doSomething() { delay(1000) // ... } fun main() { GlobalScope.launch { doSomething() } }
Java 中也有类似的功能,例如 CompletableFuture 和 RxJava 等库,但需要更多的代码和配置来实现相同的结果。
java
1 2 3 4 5 6 7 8 CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { // handle exception } // ... });
数据类 Kotlin 中的数据类是一种用于表示仅包含数据的类的简洁方式,可以自动生成 equals、hashCode、toString 等常用方法。Java 中没有类似的语法糖,但可以手动编写这些方法,或者使用 Lombok 等第三方库来生成这些方法。
kotlin
1 data class Person(val name: String, val age: Int)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 // Java public class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
集合操作 Kotlin 中的集合操作是一种方便的方式,可以使用函数式编程的风格来对集合进行过滤、转换、排序等操作。Java 8 中也引入了类似的功能,例如 Stream API 和 Lambda 表达式,但需要更多的代码和注意事项。
kotlin
1 2 3 val list = listOf("apple", "banana", "orange") val result = list.filter { it.startsWith("a") }.map { it.toUpperCase() }
1 2 3 // Java 8 List<String> list = Arrays.asList("apple", "banana", "orange"); List<String> result = list.stream().filter(s -> s.startsWith("a")).map(String::toUpperCase).collect(Collectors.toList());
委托 Kotlin 中的委托是一种将某个类的功能委托给另一个类或对象的方式,可以减少重复代码的编写。Java 中没有类似的语法糖,但可以使用代理模式来实现类似的效果。
kotlin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface Hello { fun sayHello() } class HelloWorld : Hello { override fun sayHello() { println("Hello World") } } class HelloWorldDelegate(val hello: Hello) : Hello by hello fun main() { val helloWorld = HelloWorld() val helloWorldDelegate = HelloWorldDelegate(helloWorld) helloWorldDelegate.sayHello() // 输出 "Hello World" }
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 interface Hello { void sayHello(); } class HelloWorld implements Hello { @Override public void sayHello() { System.out.println("Hello World"); } } class HelloWorldDelegate implements Hello { private final Hello hello; public HelloWorldDelegate(Hello hello) { this.hello = hello; } @Override public void sayHello() { hello.sayHello(); } } public static void main(String[] args) { Hello helloWorld = new HelloWorld(); Hello helloWorldDelegate = new HelloWorldDelegate(helloWorld); helloWorldDelegate.sayHello }
在 Kotlin 中,当 Lambda 表达式只有一个参数时,可以使用 it 来代替该参数的名称。此外,使用 apply 函数可以方便地对对象进行初始化或配置。
kotlin
1 2 3 4 5 6 7 8 9 val str = "Hello World" val result = str.run { length } val upperCase = str.toUpperCase() val newStr = str.let { "$it!" } val sb = StringBuilder().apply { append("Hello") append(" ") append("World") }
在 Java 中没有类似的语法糖,但可以使用匿名内部类或 Lambda 表达式来实现相同的效果。
java
1 2 3 4 5 6 7 8 String str = "Hello World"; int result = str.length(); String upperCase = str.toUpperCase(); String newStr = new StringBuilder(str).append("!").toString(); StringBuilder sb = new StringBuilder(); sb.append("Hello"); sb.append(" "); sb.append("World");
Elvis 操作符 Kotlin 中的 Elvis 操作符 ?: 是一种简单的方式,可以在条件为 null 时提供默认值。
kotlin
1 2 val str: String? = null val result = str ?: "default value"
Java 中没有类似的语法糖,但可以使用三元运算符来实现相同的效果。
java
1 2 String str = null; String result = (str != null) ? str : "default value";
安全调用操作符 Kotlin 中的安全调用操作符 ?. 是一种简单的方式,可以在对象不为 null 时才调用其方法或属性。
kotlin
1 2 val str: String? = null val result = str?.length
Java 中没有类似的语法糖,但可以使用条件语句来实现相同的效果。
java
1 2 String str = null; Integer result = (str != null) ? str.length() : null;
惰性求值 在 Kotlin 中,可以使用 lazy 委托来实现惰性求值,即在第一次访问时才计算表达式的值。这对于计算成本高、不需要立即执行的操作非常有用。
kotlin
1 2 3 4 5 6 7 val lazyValue: String by lazy { println("computed!") "Hello" } println(lazyValue) println(lazyValue)
在 Java 中没有类似的语法糖,但可以手动实现惰性求值,例如使用单例模式。
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class LazyValue { private static LazyValue INSTANCE; private LazyValue() {} public static synchronized LazyValue getInstance() { if (INSTANCE == null) { INSTANCE = new LazyValue(); } return INSTANCE; } public String compute() { System.out.println("computed!"); return "Hello"; } } public static void main(String[] args) { LazyValue lazyValue = LazyValue.getInstance(); System.out.println(lazyValue.compute()); System.out.println(lazyValue.compute()); }
it、apply、let、run 和 with 在 Kotlin 中,可以使用 it 来引用 lambda 参数的名称,并且可以使用 apply、let、run 和 with 函数来简化代码。
apply:可以在对象上执行一组操作,并返回该对象本身。 let:可以在对象上执行一组操作,并返回操作结果,也可以返回自身修改后的对象。 run:可以在作为接收者的对象上执行一组操作,并返回操作结果,可以忽略返回值。 with:可以将对象作为参数传递给函数,并在函数中执行一组操作。 kotlin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 val str: String? = "Hello World" str?.let { println(it.length) it.toUpperCase() }?.run { println(this) } str?.run { length.also { println(it) } toUpperCase().also { println(it) } } val sb = StringBuilder().apply { append("Hello") append(" ") append("World") }
在 Java 中没有直接对应的语法糖,但可以使用匿名内部类或 Lambda 表达式来实现相同的效果。例如,可以使用 Consumer 和 Function 接口来实现 let 和 run 功能。需要注意的是,Java 8 之前没有支持函数式编程的标准库,因此需要自己定义这些接口。
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 String str = "Hello World"; Optional.ofNullable(str).map(s -> { System.out.println(s.length()); return s.toUpperCase(); }).ifPresent(System.out::println); String result = Optional.ofNullable(str).map(s -> { System.out.println(s.length()); return s.toUpperCase(); }).orElse(null); StringBuilder sb = new StringBuilder(); Consumer<StringBuilder> builderAction = b -> { b.append("Hello"); b.append(" "); b.append("World"); }; builderAction.accept(sb);
it 在 Kotlin 的 Lambda 表达式中,如果只有一个参数,则可以使用 it 来替换该参数名称。例如:
kotlin
1 2 val list = listOf("apple", "banana", "orange") val result = list.filter { it.startsWith("a") }
在上面的代码中,Lambda 表达式 { it.startsWith(“a”) } 中的 it 表示列表中的每个元素。
apply apply 函数接收一个对象和一个 Lambda 表达式,并在对象上执行此表达式。Lambda 表达式可以访问对象的属性和方法,并且返回值被忽略,最终返回对象本身。例如:
kotlin
1 2 3 4 5 val sb = StringBuilder().apply { append("Hello") append(" ") append("World") }
在上面的代码中,apply 函数创建了一个 StringBuilder 对象,并执行了一些操作来初始化它(即添加了 “Hello” 和 “World” 字符串)。Lambda 表达式返回的值被忽略,最终返回的是初始化后的 StringBuilder 对象。
let let 函数接收一个对象和一个 Lambda 表达式,并在对象上执行此表达式。Lambda 表达式可以访问对象的属性和方法,并且可以返回任何类型的值。函数返回值是 Lambda 表达式的返回值,或者如果 Lambda 表达式为 null,则返回 null。例如:
kotlin
1 2 3 4 5 val str: String? = "Hello World" val result = str?.let { println(it.length) it.toUpperCase() }
在上面的代码中,let 函数调用了一个可空的字符串,并将其传递给 Lambda 表达式。Lambda 表达式首先将字符串转换为大写字母,然后返回转换后的字符串作为 result 变量的值。
run run 函数接收一个对象和一个 Lambda 表达式,并在该对象上执行此表达式。Lambda 表达式可以访问对象的属性和方法,并且可以返回任何类型的值。函数返回值是 Lambda 表达式的返回值,或者如果 Lambda 表达式为 null,则返回 null。例如:
kotlin
1 2 3 4 5 val str: String? = "Hello World" val result = str?.run { println(length) toUpperCase() }
在上面的代码中,run 函数调用了一个可空的字符串,并将其传递给 Lambda 表达式。Lambda 表达式首先将字符串转换为大写字母,然后返回转换后的字符串作为 result 变量的值。
with with 函数接收一个对象和一个 Lambda 表达式,并在该对象上执行此表达式。Lambda 表达式可以访问对象的属性和方法,并且不能返回任何值。函数返回值是 Lambda 表达式的最后一个表达式的值,或者如果 Lambda 表达式为空,则为 Unit。例如:
kotlin
1 2 3 4 5 6 val str = "Hello World" val result = with(StringBuilder()) { append("Length: ") append(str.length) toString() }
在上面的代码中,with 函数创建了一个空的 StringBuilder 对象,并将其传递给 Lambda 表达式。Lambda 表达式首先使用 append 方法添加一个字符串,然后使用 toString 方法将 StringBuilder 转换为字符串并返回该字符串。
Kotlin 中,”let” 和 “run” 是两个常用的标准库函数,它们有一些共同点,但也有一些区别。
相同之处:
“let” 和 “run” 都是用于简化代码的帮助函数。 它们都接受一个 Lambda 表达式作为参数,并将其应用于指定的对象。 在 Lambda 表达式中,可以使用 “it” 引用来引用对象。 它们都返回 Lambda 表达式的结果。 不同之处:
“let” 将指定的对象作为 Lambda 表达式的参数传递,并返回 Lambda 表达式的结果。因此,当您需要对某个对象执行多个操作并确保不为空时,”let” 是一个很好的选择。例如:
1 2 3 4 5 val result = myObject?.let { // 使用 it 执行操作 // ... // 返回结果 }
“run” 将指定的对象作为 Lambda 表达式的接收者,并返回 Lambda 表达式的结果。因此,当您需要在对象上执行多个操作并且不关心任何返回值时,”run” 是一个不错的选择。例如:
1 2 3 4 5 myObject?.run { // 使用 this 执行操作 // ... // 不需要返回结果 }
总之,尽管 “let” 和 “run” 在某些情况下可以互换使用,但它们的设计目的和用法略有不同。重要的是要了解它们的区别,并在适当的情况下选择正确的函数。
java版本 it、apply、let、run 和 with 在 Java 中,可以使用 lambda 表达式以及函数接口来实现类似于 Kotlin 的 it、apply、let、run 和 with。
it 在 Java 中,可以使用单个参数的 Lambda 表达式来代替 Kotlin 中的 it。例如:
1 list.stream().filter(x -> x > 10).forEach(System.out::println);
apply 在 Java 中,可以通过一个自定义的函数接口实现 apply 函数。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface Function<T, R> { R apply(T t); } public class Person { private String name; private int age; public Person apply(Function<Person, Person> f) { return f.apply(this); } } Person person = new Person(); person.apply(p -> { p.setName("John"); p.setAge(30); return p; });
let 在 Java 中,可以通过一个自定义的函数接口实现 let 函数。例如:
1 2 3 4 5 6 7 8 9 10 11 public interface Function<T, R> { R apply(T t); } public class SomeClass { public static <T, R> R let(T obj, Function<T, R> func) { return func.apply(obj); } } String result = SomeClass.let("Hello", s -> s.toUpperCase());
run 在 Java 中,可以通过一个自定义的函数接口实现 run 函数。例如:
1 2 3 4 5 6 7 8 9 10 11 public interface Runnable { void run(); } public class SomeClass { public static void run(Runnable action) { action.run(); } } SomeClass.run(() -> System.out.println("Hello World"));
with 在 Java 中,可以通过一个自定义的函数接口结合 Lambda 表达式实现 with 函数。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface With<T, R> { R apply(T t); } public class SomeClass { public static <T, R> R with(T obj, With<T, R> func) { return func.apply(obj); } } Person person = new Person(); String name = SomeClass.with(person, p -> { p.setName("John"); return p.getName(); });
?: 对应的java版本以及 Kotlin 支持区间对应的java版本
kotlin ?: Elvis 操作符 ?: 可以用于简化 null 检查。如果左侧表达式不为 null,则返回左侧表达式,否则返回右侧表达式。例如:
kotlin
1 2 val name: String? = null val length = name?.length ?: -1
java
1 2 String name = null; int length = (name != null) ? name.length() : -1;
看上去,还不如java版本呢,语法糖太多只会让人迷惑 Kotlin 支持区间,在 Java 中没有直接对应的语法糖。但是,Java 8 引入了 Stream API,可以使用 IntStream、LongStream 和 DoubleStream 来表示数字范围,并进行相应的操作。例如: java
1 2 3 4 5 6 // 使用 IntStream 表示整数范围 [1, 10],并输出每个元素 IntStream.rangeClosed(1, 10).forEach(System.out::println); // 使用 LongStream 表示长整数范围 [1, 100],并计算所有元素的总和 long sum = LongStream.rangeClosed(1, 100).sum(); System.out.println(sum);
需要注意的是,Java 的 Stream API 是延迟执行的,需要通过终止操作才能触发中间操作。常见的终止操作有:forEach()、count()、sum()、min()、max()、average()
等。
属性委托(Property Delegation) 属性委托可以让我们将属性的 get 和 set 操作委托给另外一个类进行处理,从而实现更加灵活的属性处理逻辑。例如:
kotlin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Example { var p: String by Delegate() } class Delegate { operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, delegated property ${property.name}" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name}' in $thisRef.") } } val e = Example() println(e.p) // 输出 "Example@xxxxxx, delegated property p" e.p = "NEW" // 输出 "NEW has been assigned to 'p' in Example@xxxxxx."
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import kotlin.jvm.functions.Function1; import kotlin.reflect.KProperty; class PropertyDelegate<T> { private T value; private Function1<KProperty<?>, T> getter; private Function1<KProperty<?>, Void> setter; public PropertyDelegate(T value, Function1<KProperty<?>, T> getter, Function1<KProperty<?>, Void> setter) { this.value = value; this.getter = getter; this.setter = setter; } public T getValue(Object obj, KProperty<?> prop) { return getter.invoke(prop); } public void setValue(Object obj, KProperty<?> prop, T value) { setter.invoke(prop); this.value = value; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Person { private String name; public final PropertyDelegate<String> nameDelegate = new PropertyDelegate<String>( "unknown", prop -> name, prop -> System.out.printf("The value of property '%s' has been changed.%n", prop.getName()) ); public String getName() { return nameDelegate.getValue(this, null); } public void setName(String name) { nameDelegate.setValue(this, null, name); } }
在 Person 类中,我们创建了一个名为 nameDelegate 的属性委托对象,并将其声明为 final。在 getName() 和 setName() 方法中,我们分别通过 getValue() 和 setValue() 方法来获取和设置
内联函数
内联函数(Inline Functions) 内联函数可以将函数体的代码直接插入到调用处,从而减少函数调用的开销。在 Kotlin 中,如果一个函数被标记为 inline,那么它的函数体会被内联到调用该函数的地方。例如:
kotlin
1 2 3 4 5 6 inline fun <reified T> printType() { println(T::class) } printType<String>() // 输出 "class kotlin.String" printType<Int>() // 输出 "class kotlin.Int"
Java 并没有类似 Kotlin 的 inline 关键字来声明内联函数,但是 Java 8 引入了 Lambda 表达式和方法引用等特性,可以在一定程度上替代内联函数的功能。例如,Kotlin 中的 apply() 函数可以使用 Java 8 的方法引用来实现:
可以使用 Java 8 的方法引用来调用该函数:
java
1 2 3 StringBuilder sb = new StringBuilder(); sb.append("Hello, ").append("World!").apply(StringBuilder::reverse); System.out.println(sb.toString()); // 输出 "!dlroW ,olleH"
内联参考https://blog.csdn.net/mirkowug/article/details/118153173
类型别名(Type Aliases) 类型别名可以让我们为现有的数据类型起一个新名字,提高代码的可读性和可维护性。例如:
kotlin
1 2 3 4 5 6 7 8 typealias Name = String typealias PersonData = Map<String, Any> fun getName(): Name = "John" fun getPersonData(): PersonData = mapOf("name" to "John", "age" to 30) val name: Name = getName() val data: PersonData = getPersonData()
额,java搞不了