JPlus:现代Java超集语言——空安全与代码生成新特性

JPlus是一种运行在JVM上的Java超集语言,在保持完全Java兼容性的同时引入了空安全、空安全操作符、样板代码生成语法等现代特性,显著提升开发效率。

JPlus:现代Java超集语言

JPlus是一种运行在JVM上的Java超集语言,在提升开发效率的同时保持与Java生态系统的完全兼容。

为什么支持JPlus?

JPlus填补了Java生态系统中的独特空白:

  • 保持100% Java语法兼容性
  • 引入空安全(?)、空安全操作符(?.)、样板代码生成语法(apply)和Elvis操作符(?:)等特性
  • 允许与现有Java代码逐步采用
  • 直接编译为纯Java代码

目前,没有其他语言能以这种方式扩展Java,同时保持对Java开发者熟悉的语法。

关键特性

  • 严格空检查 - 在编译时防止空引用错误
  • 空安全操作符 - 使用?.操作符安全访问可空变量,避免NullPointerException风险
  • 样板代码生成语法 - 无需Lombok即可替换常见的样板代码,如getter、setter、构造函数和builder
  • Elvis操作符 - 使用?:简化空检查,在变量为空时提供默认值

示例1:结合?.和?:操作符

JPlus支持结合空安全访问操作符(?.)和Elvis操作符(?:),将复杂的空处理逻辑简化为清晰简洁的表达式。

示例:NullsafeWithElvisOperator.jplus

1
2
3
4
5
6
7
8
9
package jplus.example;

public class Main {
    public static void main(String[] args) {
        String? s1 = null;
        String s2 = s1 ?: "jplus";
        System.out.printf("the length of s1 : %d\n", s1?.length() ?: 0);
        System.out.printf("the length of s2 : %d\n", s2.length());
    }
  • s1是一个可空变量
  • s1 ?: “jplus” → 如果s1为null,则赋值"jplus"
  • s1?.length() ?: 0 → 安全地在s1上调用length(),如果s1为null则返回0
  • 通过结合两个操作符,空处理变得安全且简洁

JPlus生成的Java代码输出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package jplus.example;

public class Main {
    public static void main(String[] args) {
        String s1 = null;
        String s2 = (((s1) != null) ? (s1) : "jplus");
        System.out.printf(
                "the length of s1 : %d\n",
                (((((s1 != null) ? s1.length() : null)) != null)
                        ? (((s1 != null) ? s1.length() : null))
                        : 0));
        System.out.printf("the length of s2 : %d\n", s2.length());
    }

表达式s1?.length() ?: 0被转换为Java中的嵌套条件检查:((s1 != null) ? s1.length() : null) != null ? … : 0,确保安全执行。

示例2:使用Apply消除数据类和嵌套类的样板代码

JPlus引入apply关键字来替换常见的Java样板代码,如getter、setter、构造函数、builder等。它作为Lombok注解的语言级别替代方案,提供清晰声明式的语法。

示例:ApplyStatement.jplus

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.example;

apply data, constructor(required, all, no), builder;
apply {
    User.Profile: getter, setter, equality, constructor(all);
}

public class User {
    private String name;
    private int age;

    public class Profile {
        String nickname;
    }
}
  • data:自动生成getter、setter、equals()、hashCode()和toString()
  • builder:生成User.Builder类用于流畅的对象创建
  • constructors(required, all, no):生成包含所有/必需字段的构造函数和无参数构造函数
  • equality:生成equals()和hashCode()方法
  • apply { User.Profile: … }:专门为Profile内部类应用样板代码生成

JPlus生成的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
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
package com.example;

//apply data, constructor(required, all, no), builder;
//apply {
//    User.Profile: getter, setter, equality, constructor(all);
//}

public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User() {}

    public class Profile {
        String nickname;

        public Profile(String nickname) {
            this.nickname = nickname;
        }

        public String getNickname() {
            return nickname;
        }

        public void setNickname(String nickname) {
            this.nickname = nickname;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Profile profile = (Profile) o;
            return java.util.Objects.equals(nickname, profile.nickname);
        }

        @Override
        public int hashCode() {
            return java.util.Objects.hash(nickname);
        }
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" + "name=" + name+ ", " + "age=" + age + "}";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age
                && java.util.Objects.equals(name, user.name);
    }

    @Override
    public int hashCode() {
        return java.util.Objects.hash(name, age);
    }

    public static class Builder {
        private String name;
        private int age;

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public User build() {
            return new User(name, age);
        }
    }

    public static Builder builder() {
        return new Builder();
    }
}

这使得开发人员即使使用深层嵌套结构也能保持代码的DRY和表达性。

当前状态

  • MVP(最小可行产品)阶段
  • IntelliJ Plugin 0.1 MVP Alpha发布,包含:
    • 语法高亮、代码补全和错误检查
    • 可空性检查
    • 与现有Java项目的无缝集成

资源

  • Github仓库
  • intellij-plugin-0.1-mvp-alpha.zip
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计