Kotlin 与 Java 语法差异

Kotlin 与 Java 语法差异

目标:用可运行/可理解的代码对比展示 Kotlin 与 Java 在现代 Android 开发中的语法差异。

说明:Java 示例以 JDK 17+ 常见写法为主;涉及 Compose 的部分会给出 Java 侧"等效思路"(通常是传统 View 或接口回调),因为 Compose 本身是 Kotlin-first。


文档目录(按模块)

  • A. 基础语法与类型系统(1~8)
  • B. 并发与状态建模(9~11)
  • C. Compose 基础范式(12~14)
  • D. Kotlin 表达式与异常风格(15~19)
  • E. 面向对象与语言组织方式(20~30)
  • F. Kotlin 进阶特性(31~36)
  • G. 协程与 Compose 进阶(37~45)

A. 基础语法与类型系统

1. 变量声明:val/var vs final/普通变量

Kotlin

kotlin 复制代码
val name = "Tom"      // 只读引用(不可二次赋值)
var age = 18           // 可变

// name = "Jerry"     // 编译错误
age = 19

Java

java 复制代码
final String name = "Tom"; // 只读引用
int age = 18;               // 可变

// name = "Jerry";         // 编译错误
age = 19;

2. 类型推断:Kotlin 更彻底,Java var 仅限局部变量

Kotlin

kotlin 复制代码
val title = "Park"        // String
val score = 99             // Int
val ratio = 0.8f           // Float

Java (JDK 10+)

java 复制代码
var title = "Park";       // String
var score = 99;            // int
var ratio = 0.8f;          // float

class User {
    // var field = "x";   // 编译错误:字段不能用 var
    String field = "x";
}

3. 空安全:String? + ?. + ?:

Kotlin

kotlin 复制代码
fun lenOrZero(name: String?): Int {
    return name?.length ?: 0
}

Java

java 复制代码
int lenOrZero(String name) {
    return name == null ? 0 : name.length();
}

4. 数据类:data class vs 手写/record

Kotlin

kotlin 复制代码
data class User(val id: Long, val name: String)

val u1 = User(1, "Tom")
val u2 = u1.copy(name = "Jerry")

Java (record)

java 复制代码
public record User(long id, String name) {}

User u1 = new User(1, "Tom");
User u2 = new User(u1.id(), "Jerry");

5. 默认参数 + 命名参数 vs 方法重载

Kotlin

kotlin 复制代码
fun showToast(msg: String, duration: Int = 0, withIcon: Boolean = false) {
    // ...
}

showToast(msg = "保存成功")
showToast("失败", duration = 1)

Java

java 复制代码
void showToast(String msg) {
    showToast(msg, 0, false);
}

void showToast(String msg, int duration) {
    showToast(msg, duration, false);
}

void showToast(String msg, int duration, boolean withIcon) {
    // ...
}

6. when vs switch

Kotlin

kotlin 复制代码
fun level(score: Int): String = when (score) {
    in 90..100 -> "A"
    in 80..89 -> "B"
    in 60..79 -> "C"
    else -> "D"
}

Java

java 复制代码
String level(int score) {
    if (score >= 90 && score <= 100) return "A";
    if (score >= 80) return "B";
    if (score >= 60) return "C";
    return "D";
}

7. 扩展函数 vs 工具类静态方法

Kotlin

kotlin 复制代码
fun String.maskPhone(): String {
    if (length < 7) return this
    return replaceRange(3, 7, "****")
}

val s = "13812345678".maskPhone()

Java

java 复制代码
public final class StringExt {
    public static String maskPhone(String s) {
        if (s == null || s.length() < 7) return s;
        return s.substring(0, 3) + "****" + s.substring(7);
    }
}

String result = StringExt.maskPhone("13812345678");

8. 高阶函数与 Lambda(函数类型)

Kotlin

kotlin 复制代码
fun request(onSuccess: (String) -> Unit, onError: (Throwable) -> Unit) {
    try {
        onSuccess("OK")
    } catch (e: Throwable) {
        onError(e)
    }
}

request(
    onSuccess = { println(it) },
    onError = { println(it.message) }
)

Java

java 复制代码
void request(java.util.function.Consumer<String> onSuccess,
             java.util.function.Consumer<Throwable> onError) {
    try {
        onSuccess.accept("OK");
    } catch (Throwable e) {
        onError.accept(e);
    }
}

request(
    s -> System.out.println(s),
    e -> System.out.println(e.getMessage())
);

B. 并发与状态建模

9. 协程 suspend vs CompletableFuture

Kotlin

kotlin 复制代码
suspend fun loadUser(): User = api.getUser()
suspend fun loadPosts(): List<Post> = api.getPosts()

suspend fun loadPage(): Pair<User, List<Post>> = kotlinx.coroutines.coroutineScope {
    val u = async { loadUser() }
    val p = async { loadPosts() }
    u.await() to p.await()
}

Java

java 复制代码
CompletableFuture<User> loadUser() {
    return CompletableFuture.supplyAsync(() -> api.getUser());
}

CompletableFuture<List<Post>> loadPosts() {
    return CompletableFuture.supplyAsync(() -> api.getPosts());
}

CompletableFuture<PageData> loadPage() {
    return loadUser().thenCombine(loadPosts(), PageData::new);
}

10. Kotlin 密封类(状态建模)vs Java sealed

Kotlin

kotlin 复制代码
sealed interface UiState {
    data object Loading : UiState
    data class Success(val data: List<String>) : UiState
    data class Error(val msg: String) : UiState
}

fun render(state: UiState) = when (state) {
    UiState.Loading -> println("loading")
    is UiState.Success -> println(state.data)
    is UiState.Error -> println(state.msg)
}

Java

java 复制代码
sealed interface UiState permits Loading, Success, Error {}
record Loading() implements UiState {}
record Success(java.util.List<String> data) implements UiState {}
record Error(String msg) implements UiState {}

void render(UiState state) {
    if (state instanceof Loading) {
        System.out.println("loading");
    } else if (state instanceof Success s) {
        System.out.println(s.data());
    } else if (state instanceof Error e) {
        System.out.println(e.msg());
    }
}

11. 委托属性:by lazy / by viewModels()

Kotlin

kotlin 复制代码
class HomeActivity : AppCompatActivity() {
    private val vm: HomeViewModel by viewModels()
    private val token: String by lazy { loadTokenFromDisk() }
}

Java(等效思路)

java 复制代码
public class HomeActivity extends AppCompatActivity {
    private HomeViewModel vm;
    private String token;

    HomeViewModel getVm() {
        if (vm == null) {
            vm = new ViewModelProvider(this).get(HomeViewModel.class);
        }
        return vm;
    }

    String getToken() {
        if (token == null) {
            token = loadTokenFromDisk();
        }
        return token;
    }
}

C. Compose 基础范式

12. Compose DSL 与函数插槽(slot API)

这是 Kotlin 与 Java 在 UI 表达方式上的关键差异 之一。Compose 通过函数参数传递 UI 片段(@Composable () -> Unit),Java 传统 View 一般通过接口回调、布局 ID、Adapter 等实现"可插拔区域"。

Kotlin Compose:函数插槽

kotlin 复制代码
@Composable
fun AppScaffold(
    title: String,
    topBar: @Composable () -> Unit = { Text(title) },
    content: @Composable () -> Unit,
    bottomBar: @Composable (() -> Unit)? = null,
) {
    Column {
        topBar()
        Box(modifier = Modifier.weight(1f)) {
            content()
        }
        bottomBar?.invoke()
    }
}

@Composable
fun DemoScreen() {
    AppScaffold(
        title = "首页",
        topBar = { Text("自定义头部") },
        content = { Text("页面内容") },
        bottomBar = { Button(onClick = {}) { Text("提交") } }
    )
}

Java 传统 View:接口/容器注入的等效思路

java 复制代码
public class LegacyScaffold extends LinearLayout {

    public interface Slot {
        void render(ViewGroup container);
    }

    public void setup(String title, Slot topBar, Slot content, @Nullable Slot bottomBar) {
        ViewGroup top = findViewById(R.id.top_container);
        ViewGroup body = findViewById(R.id.content_container);
        ViewGroup bottom = findViewById(R.id.bottom_container);

        top.removeAllViews();
        body.removeAllViews();
        bottom.removeAllViews();

        if (topBar != null) topBar.render(top);
        content.render(body);
        if (bottomBar != null) bottomBar.render(bottom);
    }
}

13. Compose 状态提升(State Hoisting)vs Java 回调更新

Kotlin Compose

kotlin 复制代码
@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }
    Counter(count = count, onInc = { count++ })
}

@Composable
fun Counter(count: Int, onInc: () -> Unit) {
    Row {
        Text("count = $count")
        Button(onClick = onInc) { Text("+") }
    }
}

Java(View + Listener)

java 复制代码
public class CounterView extends LinearLayout {
    private int count = 0;
    private TextView tv;

    public CounterView(Context c) {
        super(c);
        // inflate...
        tv = findViewById(R.id.tv);
        Button btn = findViewById(R.id.btn);
        btn.setOnClickListener(v -> {
            count++;
            tv.setText("count = " + count);
        });
    }
}

14. Compose 列表声明式渲染 vs RecyclerView Adapter

Kotlin Compose

kotlin 复制代码
@Composable
fun MessageList(items: List<String>) {
    LazyColumn {
        items(items) { msg ->
            Text(text = msg)
        }
    }
}

Java RecyclerView

java 复制代码
public class MessageAdapter extends RecyclerView.Adapter<MessageVH> {
    private final List<String> items;

    public MessageAdapter(List<String> items) {
        this.items = items;
    }

    @Override
    public void onBindViewHolder(@NonNull MessageVH holder, int position) {
        holder.textView.setText(items.get(position));
    }

    @Override
    public int getItemCount() {
        return items.size();
    }
}

D. Kotlin 表达式与异常风格

15. 表达式函数:最后一行即返回值(可省略 return

Kotlin

kotlin 复制代码
fun max(a: Int, b: Int): Int = if (a > b) a else b

fun levelText(score: Int): String {
    if (score >= 60) {
        return "及格"
    }
    return "不及格"
}

// 也可写成表达式体
fun levelText2(score: Int): String = if (score >= 60) "及格" else "不及格"

Java

java 复制代码
int max(int a, int b) {
    return a > b ? a : b;
}

String levelText(int score) {
    if (score >= 60) {
        return "及格";
    }
    return "不及格";
}

16. 作用域函数:let / also / apply / run / with

Kotlin 通过作用域函数减少样板代码。Java 通常通过临时变量、链式 setter、工具方法实现。

Kotlin

kotlin 复制代码
data class User(var name: String = "", var age: Int = 0)

val u1 = User().apply {
    name = "Tom"
    age = 18
} // 返回对象本身(this)

val len = "  park  ".let {
    it.trim().length
} // 返回 lambda 最后一行

val u2 = User("Jerry", 20).also {
    println("before save: $it")
} // 返回对象本身(it)

val text = User("Alice", 22).run {
    "$name-$age"
} // 返回 lambda 结果(this)

val text2 = with(User("Bob", 30)) {
    "$name-$age"
} // 返回 lambda 结果(this)

Java(等效思路)

java 复制代码
User u1 = new User();
u1.setName("Tom");
u1.setAge(18);

int len = "  park  ".trim().length();

User u2 = new User("Jerry", 20);
System.out.println("before save: " + u2);

User tmp = new User("Alice", 22);
String text = tmp.getName() + "-" + tmp.getAge();

User tmp2 = new User("Bob", 30);
String text2 = tmp2.getName() + "-" + tmp2.getAge();

17. 异常处理:try 作为表达式 + runCatching

Kotlin

kotlin 复制代码
fun parseOrZero(s: String): Int {
    val result = try {
        s.toInt()          // try 可直接返回值
    } catch (e: NumberFormatException) {
        0
    }
    return result
}

fun parseOrNull(s: String): Int? {
    return runCatching { s.toInt() }
        .onFailure { println("parse error: ${it.message}") }
        .getOrNull()
}

Java

java 复制代码
int parseOrZero(String s) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        return 0;
    }
}

Integer parseOrNull(String s) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        System.out.println("parse error: " + e.getMessage());
        return null;
    }
}

18. 受检异常(Checked Exception)差异

Kotlin 没有 Java 风格的受检异常语法约束;Java 需要 throwstry/catch

Kotlin

kotlin 复制代码
fun readText(path: java.nio.file.Path): String {
    // Kotlin 调 Java API 时,不强制你写 throws/try-catch
    return java.nio.file.Files.readString(path)
}

Java

java 复制代码
String readText(java.nio.file.Path path) throws java.io.IOException {
    return java.nio.file.Files.readString(path);
}

19. 空安全 + 异常风格结合:?.let {}

Kotlin

kotlin 复制代码
fun printUserName(user: User?) {
    user?.let {
        println(it.name)
    } ?: println("user is null")
}

Java

java 复制代码
void printUserName(User user) {
    if (user != null) {
        System.out.println(user.getName());
    } else {
        System.out.println("user is null");
    }
}

E. 面向对象与语言组织方式

20. 类型声明位置差异(你提到的 Int 左右问题)

Kotlin(类型在变量/参数名后)

kotlin 复制代码
val age: Int = 18
fun sum(a: Int, b: Int): Int = a + b
val list: List<String> = listOf("A", "B")

Java(类型在变量/参数名前)

java 复制代码
int age = 18;
int sum(int a, int b) { return a + b; }
List<String> list = List.of("A", "B");

21. 类构造器写法:主构造器/次构造器 vs 多构造器

Kotlin

kotlin 复制代码
class User(val id: Long, var name: String) {
    constructor(id: Long) : this(id, "")
}

Java

java 复制代码
class User {
    private final long id;
    private String name;

    User(long id, String name) {
        this.id = id;
        this.name = name;
    }

    User(long id) {
        this(id, "");
    }
}

22. 属性(property)vs 字段 + getter/setter

Kotlin

kotlin 复制代码
class Account {
    var balance: Int = 0
        set(value) {
            field = value.coerceAtLeast(0)
        }
}

Java

java 复制代码
class Account {
    private int balance = 0;

    public int getBalance() {
        return balance;
    }

    public void setBalance(int value) {
        this.balance = Math.max(0, value);
    }
}

23. 字符串模板 vs 字符串拼接

Kotlin

kotlin 复制代码
val name = "Tom"
val age = 18
val s = "name=$name, next=${age + 1}"

Java

java 复制代码
String name = "Tom";
int age = 18;
String s = "name=" + name + ", next=" + (age + 1);

24. 静态成员:companion object vs static

Kotlin

kotlin 复制代码
class IdGenerator {
    companion object {
        private var seed = 0
        fun nextId(): Int = ++seed
    }
}

val id = IdGenerator.nextId()

Java

java 复制代码
class IdGenerator {
    private static int seed = 0;

    static int nextId() {
        return ++seed;
    }
}

int id = IdGenerator.nextId();

25. 顶层函数/常量 vs 工具类

Kotlin

kotlin 复制代码
const val API_HOST = "https://api.demo.com"

fun joinPath(a: String, b: String): String = "$a/$b"

Java

java 复制代码
public final class ApiUtils {
    public static final String API_HOST = "https://api.demo.com";

    public static String joinPath(String a, String b) {
        return a + "/" + b;
    }
}

26. 集合操作:链式函数式 API 差异

Kotlin

kotlin 复制代码
val names = listOf("tom", "jerry", "alice")
val result = names
    .filter { it.length > 3 }
    .map { it.replaceFirstChar { c -> c.uppercase() } }

Java

java 复制代码
List<String> names = List.of("tom", "jerry", "alice");
List<String> result = names.stream()
    .filter(s -> s.length() > 3)
    .map(s -> s.substring(0, 1).toUpperCase() + s.substring(1))
    .toList();

27. 区间与遍历:.. / until / downTo / step

Kotlin

kotlin 复制代码
for (i in 0..3) println(i)          // 0,1,2,3
for (i in 0 until 3) println(i)     // 0,1,2
for (i in 10 downTo 0 step 2) println(i)

Java

java 复制代码
for (int i = 0; i <= 3; i++) System.out.println(i);
for (int i = 0; i < 3; i++) System.out.println(i);
for (int i = 10; i >= 0; i -= 2) System.out.println(i);

28. 智能类型转换(smart cast)vs 显式强转

Kotlin

kotlin 复制代码
fun printLen(x: Any) {
    if (x is String) {
        println(x.length) // 自动当作 String
    }
}

Java

java 复制代码
void printLen(Object x) {
    if (x instanceof String) {
        String s = (String) x;
        System.out.println(s.length());
    }
}

29. 运算符重载(operator)vs 显式方法调用

Kotlin

kotlin 复制代码
data class Vec(val x: Int, val y: Int) {
    operator fun plus(other: Vec): Vec = Vec(x + other.x, y + other.y)
}

val v = Vec(1, 2) + Vec(3, 4)

Java

java 复制代码
class Vec {
    final int x;
    final int y;

    Vec(int x, int y) {
        this.x = x;
        this.y = y;
    }

    Vec add(Vec other) {
        return new Vec(this.x + other.x, this.y + other.y);
    }
}

Vec v = new Vec(1, 2).add(new Vec(3, 4));

30. 资源释放:use {} vs try-with-resources

Kotlin

kotlin 复制代码
val text = java.io.BufferedReader(java.io.StringReader("hello")).use { br ->
    br.readLine()
}

Java

java 复制代码
String text;
try (BufferedReader br = new BufferedReader(new StringReader("hello"))) {
    text = br.readLine();
}

F. Kotlin 进阶特性

31. 泛型变型:out/in vs ? extends / ? super

Kotlin

kotlin 复制代码
open class Animal
class Dog : Animal()

fun readAnimals(list: List<out Animal>) {
    // 只读场景
    println(list.size)
}

fun addDogs(list: MutableList<in Dog>) {
    list.add(Dog())
}

Java

java 复制代码
class Animal {}
class Dog extends Animal {}

void readAnimals(List<? extends Animal> list) {
    System.out.println(list.size());
}

void addDogs(List<? super Dog> list) {
    list.add(new Dog());
}

32. 内联 + 具体化泛型:inline reified vs Class<T> 传参

Kotlin

kotlin 复制代码
inline fun <reified T> Gson.fromJsonTyped(json: String): T {
    return fromJson(json, T::class.java)
}

val user: User = gson.fromJsonTyped("{\"id\":1,\"name\":\"Tom\"}")

Java

java 复制代码
<T> T fromJsonTyped(Gson gson, String json, Class<T> clazz) {
    return gson.fromJson(json, clazz);
}

User user = fromJsonTyped(gson, "{\"id\":1,\"name\":\"Tom\"}", User.class);

33. 委托接口实现:by vs 手写包装类

Kotlin

kotlin 复制代码
interface Logger {
    fun log(msg: String)
}

class ConsoleLogger : Logger {
    override fun log(msg: String) = println(msg)
}

class PrefixLogger(private val prefix: String, private val delegate: Logger) : Logger by delegate {
    override fun log(msg: String) {
        delegate.log("[$prefix] $msg")
    }
}

Java

java 复制代码
interface Logger {
    void log(String msg);
}

class ConsoleLogger implements Logger {
    @Override
    public void log(String msg) {
        System.out.println(msg);
    }
}

class PrefixLogger implements Logger {
    private final String prefix;
    private final Logger delegate;

    PrefixLogger(String prefix, Logger delegate) {
        this.prefix = prefix;
        this.delegate = delegate;
    }

    @Override
    public void log(String msg) {
        delegate.log("[" + prefix + "] " + msg);
    }
}

34. 解构声明(destructuring)vs 手动取值

Kotlin

kotlin 复制代码
data class Point(val x: Int, val y: Int)

val (x, y) = Point(10, 20)
println("x=$x, y=$y")

val pair = "Tom" to 18
val (name, age) = pair

Java

java 复制代码
record Point(int x, int y) {}

Point p = new Point(10, 20);
int x = p.x();
int y = p.y();
System.out.println("x=" + x + ", y=" + y);

Map.Entry<String, Integer> entry = Map.entry("Tom", 18);
String name = entry.getKey();
int age = entry.getValue();

35. 注解使用位点:@field: / @get:(Kotlin 特有)

Kotlin(Android 常见:校验/序列化注解)

kotlin 复制代码
data class Form(
    @field:NotBlank
    val name: String,

    @get:JsonProperty("user_id")
    val userId: String
)

Java

java 复制代码
class Form {
    @NotBlank
    private final String name;

    @JsonProperty("user_id")
    public String getUserId() {
        return userId;
    }

    private final String userId;

    Form(String name, String userId) {
        this.name = name;
        this.userId = userId;
    }
}

36. 可见性差异:internal vs Java 包可见

Kotlin

kotlin 复制代码
internal class InternalRepo

class UserService {
    internal fun load() {}
    private fun onlyMe() {}
}

Java

java 复制代码
class PackageRepo {} // 包可见(无修饰符)

public class UserService {
    void load() {}       // 包可见
    private void onlyMe() {}
}

G. 协程与 Compose 进阶

37. 协程异常传播:launch vs async

Kotlin

kotlin 复制代码
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)

fun demo() {
    scope.launch {
        throw IllegalStateException("launch error")
    }

    scope.launch {
        val deferred = async {
            throw IllegalArgumentException("async error")
        }
        try {
            deferred.await() // async 的异常通常在 await 时抛出
        } catch (e: Exception) {
            println("catch async: ${e.message}")
        }
    }
}

Java(CompletableFuture 等效思路)

java 复制代码
ExecutorService pool = Executors.newCachedThreadPool();

void demo() {
    CompletableFuture.runAsync(() -> {
        throw new IllegalStateException("runAsync error");
    }, pool).exceptionally(e -> {
        System.out.println("catch runAsync: " + e.getMessage());
        return null;
    });

    CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> {
        throw new IllegalArgumentException("supplyAsync error");
    }, pool);

    f.handle((v, e) -> {
        if (e != null) {
            System.out.println("catch supplyAsync: " + e.getMessage());
        }
        return null;
    });
}

38. 协程监督:coroutineScope vs supervisorScope

Kotlin

kotlin 复制代码
suspend fun normalScope() = coroutineScope {
    launch {
        delay(50)
        println("child-1 done")
    }
    launch {
        throw RuntimeException("child-2 fail")
    }
    // child-2 失败会取消同级 child-1
}

suspend fun supervisor() = supervisorScope {
    launch {
        delay(50)
        println("child-1 still run")
    }
    launch {
        throw RuntimeException("child-2 fail")
    }
    // child-2 失败不影响 child-1
}

Java(等效思路)

java 复制代码
ExecutorService pool = Executors.newFixedThreadPool(2);

void supervisorLike() {
    Future<?> f1 = pool.submit(() -> {
        Thread.sleep(50);
        System.out.println("child-1 still run");
        return null;
    });
    Future<?> f2 = pool.submit(() -> {
        throw new RuntimeException("child-2 fail");
    });

    // Java 里需要你手动决定是否 cancel 其它任务,默认不是结构化并发
}

39. Flow vs Java Stream(异步流 vs 同步流)

Kotlin Flow

kotlin 复制代码
fun numberFlow(): kotlinx.coroutines.flow.Flow<Int> = flow {
    emit(1)
    delay(100)
    emit(2)
    emit(3)
}

suspend fun collectDemo() {
    numberFlow()
        .map { it * 10 }
        .filter { it >= 20 }
        .collect { println(it) }
}

Java Stream

java 复制代码
Stream<Integer> stream = Stream.of(1, 2, 3)
    .map(i -> i * 10)
    .filter(i -> i >= 20);

stream.forEach(System.out::println);

40. StateFlow 驱动 UI 状态 vs Java Observable/Listener

Kotlin(ViewModel)

kotlin 复制代码
class MessageVm : ViewModel() {
    private val _uiState = MutableStateFlow("Idle")
    val uiState: StateFlow<String> = _uiState

    fun load() = viewModelScope.launch {
        _uiState.value = "Loading"
        delay(200)
        _uiState.value = "Success"
    }
}

Java(等效思路:LiveData/Listener)

java 复制代码
public class MessageVm extends ViewModel {
    private final MutableLiveData<String> uiState = new MutableLiveData<>("Idle");

    LiveData<String> getUiState() {
        return uiState;
    }

    void load() {
        uiState.setValue("Loading");
        // 异步后
        uiState.postValue("Success");
    }
}

41. Compose 副作用:LaunchedEffect

Kotlin Compose

kotlin 复制代码
@Composable
fun UserScreen(userId: String, vm: UserVm = viewModel()) {
    LaunchedEffect(userId) {
        vm.load(userId) // userId 变化时重新执行
    }

    val ui by vm.uiState.collectAsState()
    Text("state=$ui")
}

Java View(等效思路)

java 复制代码
public class UserActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String userId = getIntent().getStringExtra("userId");
        vm.load(userId); // 手动在生命周期节点触发
    }
}

42. Compose 生命周期清理:DisposableEffect

Kotlin Compose

kotlin 复制代码
@Composable
fun SensorObserver(sensorManager: SensorManager) {
    DisposableEffect(Unit) {
        val listener = SensorEventListener { /*...*/ }
        sensorManager.registerListener(listener, /*sensor*/ null, SensorManager.SENSOR_DELAY_NORMAL)

        onDispose {
            sensorManager.unregisterListener(listener)
        }
    }
}

Java View(等效思路)

java 复制代码
public class SensorActivity extends AppCompatActivity {
    private SensorEventListener listener;

    @Override
    protected void onStart() {
        super.onStart();
        listener = new MySensorListener();
        sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onStop() {
        super.onStop();
        sensorManager.unregisterListener(listener);
    }
}

43. Compose 状态保存:rememberSaveable vs onSaveInstanceState

Kotlin Compose

kotlin 复制代码
@Composable
fun FormScreen() {
    var text by rememberSaveable { mutableStateOf("") }
    TextField(value = text, onValueChange = { text = it })
}

Java View

java 复制代码
public class FormActivity extends AppCompatActivity {
    private EditText et;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            String text = savedInstanceState.getString("text", "");
            et.setText(text);
        }
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("text", et.getText().toString());
    }
}

44. Compose 性能状态:derivedStateOf

Kotlin Compose

kotlin 复制代码
@Composable
fun ScrollToTopButton(listState: LazyListState) {
    val showButton by remember {
        derivedStateOf { listState.firstVisibleItemIndex > 0 }
    }

    if (showButton) {
        FloatingActionButton(onClick = { /*scrollToTop*/ }) {
            Text("Top")
        }
    }
}

Java(等效思路)

java 复制代码
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(@NonNull RecyclerView rv, int dx, int dy) {
        boolean show = layoutManager.findFirstVisibleItemPosition() > 0;
        fab.setVisibility(show ? View.VISIBLE : View.GONE);
    }
});

45. 总结与学习路径

模块回顾

  • A. 基础语法与类型系统(1~8)
  • B. 并发与状态建模(9~11)
  • C. Compose 基础范式(12~14)
  • D. Kotlin 表达式与异常风格(15~19)
  • E. 面向对象与语言组织方式(20~30)
  • F. Kotlin 进阶特性(31~36)
  • G. 协程与 Compose 进阶(37~44)

推荐学习顺序

  1. 先掌握 A + D(写 Kotlin 代码的"手感"差异最大)
  2. 再学习 E + F(理解 Kotlin 的抽象能力和工程写法)
  3. Android 方向重点学 B + C + G(ViewModel、Flow、Compose)

迁移建议(Java/View -> Kotlin/Compose)

  1. 数据层:先改为 Kotlin + 空安全 + data class
  2. 状态层:统一到 ViewModel + StateFlow(并处理协程异常边界)
  3. UI 层:从新页面开始用 Compose,逐步替换旧 View 页面

建议:你项目里如果已经大量使用 ViewModel,可先把状态层统一到 StateFlow,再逐步把页面迁移到 Compose,这样风险最低。

相关推荐
左左右右左右摇晃3 小时前
Java并发——并发编程底层原理
java·开发语言
一个有温度的技术博主4 小时前
Redis系列八:Jedis连接池在java中的使用
java·redis·bootstrap
cyforkk4 小时前
Java 并发编程教科书级范例:深入解析 computeIfAbsent 与方法引用
java·开发语言
jerryinwuhan4 小时前
python数据挖掘基础
python·数据挖掘·numpy
后青春期的诗go4 小时前
泛微OA-E9与第三方系统集成开发企业级实战记录(八)
java·接口·金蝶·泛微·oa·集成开发·对接
echome8884 小时前
Python 异步编程实战:asyncio 核心概念与最佳实践
开发语言·网络·python
dreamxian4 小时前
苍穹外卖day09
java·spring boot·tomcat·log4j·maven
剑海风云4 小时前
JDK 26之安全增强
java·开发语言·安全·jdk26
左左右右左右摇晃4 小时前
Java并发——多线程
java·开发语言·jvm