Javalin - 发现 Java 的可爱之处

2022-08-31 17:58:07 +08:00
 SuperMild

多年以前我看到一篇神奇的文章 Java for Everything, 其中提出了一个大胆的想法:就连脚本小工具都用 Java 来写。

我读了这篇文章,但并没有立即使用 Java, 而是写了一段时间 Go, 又写了一段时间 Python, 最近想起这篇文章,就想用 Java 写点东西。

Java 的优点

  1. 易学 (而且程序员几乎都或多或少已经学过), 学习资料丰富
  2. 工具齐全 (比如有 IntelliJ IDEA, 有 maven)
  3. 生态强大,第三方库丰富
  4. 稳重感、安心感。Java 经过了多年工业级考验,能带给我很 "稳" 的心理暗示, 有一种脚踏实地的安全感。

Java 的缺点

本来 Java 是很啰嗦的,这是它最被诟病的地方了。

但现在 Java 有了 record, lambda, Stream API, var(类型推断) 等等, 已经变得不是太啰嗦了,根据我狭隘的个人经验,甚至认为比 Go, Python 更简洁。

Monostich (单行诗)

以前我喜欢用 Go 来做一些自用的小软件,做一个本地网站通过访问网页来使用, 最近想做一个叫 monostich 的小工具,就尝试用 Java 来做。

主要功能

monostich 的功能非常简单。

与 Go 语言代码对比

这次我用 Javalin 来做本地网站,并且采用了以前我写 Go 时的代码组织方式, 因此两种语言可以做个对比。

程序入口: main.go 与 Main.java 对比

可见, Go 与 Java 的代码几乎一模一样:

// github.com/ahui2016/dictplus/blob/main/main.go

func main() {
	e := echo.New()
	e.Static("/public", "public")
	e.File("/", "public/index.html")

	api := e.Group("/api", sleep)
	api.POST("/get-word", getWordHandler)
	api.POST("/add-word", addWordHandler)
	api.POST("/update-word", updateWordHandler)
	api.POST("/delete-word", deleteWordHandler)
	api.POST("/search-words", searchHandler)

	e.Logger.Fatal(e.Start(*addr))
}
// github.com/ahui2016/monostich/.../App.java

public class App {
    public static void main(String[] args) {
        Javalin app = Javalin.create(config ->
            config.addStaticFiles(staticFiles -> {
                staticFiles.hostedPath = "/";
                staticFiles.directory = "/public";
                staticFiles.location = Location.CLASSPATH;
            })).start(port);
    
        app.post("/api/insert-poem", Handle.insertPoem);
        app.post("/api/update-poem", Handle.updatePoem);
        app.post("/api/delete-poem", Handle.deletePoem);
        app.post("/api/get-poem", Handle.getPoem);
        app.post("/api/search-poems", Handle.searchPoems);
    }
}

Handler

可见, Go 比 Java 多了一些 if err != nil, 其余代码几乎一模一样:

// github.com/ahui2016/dictplus/blob/main/handler.go

func addWordHandler(c echo.Context) error {
	w := new(Word)
	if err := c.Bind(w); err != nil {
		return err
	}
	if err := db.InsertNewWord(w); err != nil {
		return err
	}
	return c.JSON(OK, Text{w.ID})
}
// github.com/ahui2016/monostich/.../Handle.java

static Handler insertPoem = ctx -> {
    var form = ctx.bodyAsClass(PoemForm.class);
    var poem = db.insertPoem(form);
    ctx.json(poem);
};

数据库

在上面 Handler 的代码中, db.InsertNewWord() 与 db.insertPoem() 的具体实现如下所示。

可以看到, Go 的代码还是受到了 if err != nil 的困扰,显得很啰嗦, 而 Java 采用 Stream API 的好处是非常明显的,代码简洁了很多。

// github.com/ahui2016/dictplus/.../database.go

func (db *DB) InsertNewWord(w *Word) (err error) {
	tx := db.mustBegin()
	defer tx.Rollback()

	if w.ID, err = getNextID(tx, word_id_key); err != nil {
		return
	}
	w.CTime = util.TimeNow()
	if err = insertWord(tx, w); err != nil {
		return
	}
	err = tx.Commit()
	return
}
// github.com/ahui2016/monostich/.../DB.java

Poem insertPoem(PoemForm form) {
    return jdbi.withHandle(handle -> handle.inTransaction(h -> {
        var poem = new Poem(getNextId(h), form.title(), form.stich(), Util.now());
        h.createUpdate(Stmt.INSERT_POEM)
                .bindMap(poem.toMap())
                .execute();
        return poem;
    }));
}

相关链接

本软件后端采用 Javalin, 前端采用 mj.js, 相关介绍请看以下链接。

4421 次点击
所在节点    Java
31 条回复
qW7bo2FbzbC0
2022-08-31 18:12:31 +08:00
你说的这些优点是确实存在的,你用的这个 lin 框架比 spring 简洁, 同时我觉得 C#比 Java 走更多一步。甚至不需要额外的三方 web 框架

https://docs.microsoft.com/en-us/aspnet/core/tutorials/min-web-api

```
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateTime.Now.AddDays(index),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast");

app.Run();

internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
```
lisongeee
2022-08-31 18:24:16 +08:00
呃呃,既然追求代码简洁,为什么不试试神奇的 kotlin 呢?

![image]( https://user-images.githubusercontent.com/38517192/187657094-4f610b00-e0fb-4e7c-a5e1-914a06ce019e.png)
zbatman
2022-08-31 18:32:00 +08:00
有请双方辩手入场
hccsoul
2022-08-31 18:38:10 +08:00
我先来 ,java 是世界上最优秀的语言,杠我的去和楼主对线 /🐶
imzcg2
2022-08-31 18:39:33 +08:00
不能自动写代码完成任务的都不是最优秀的图灵完备语言
justanetizen
2022-08-31 19:13:42 +08:00
呃,java 8 连 UTF8 处理起来都麻烦,不知道你们为毛还要抱残守缺。
WispZhan
2022-08-31 19:13:46 +08:00
为什么不看看其他 JVM 语言呢?
dqzcwxb
2022-08-31 19:21:40 +08:00
@justanetizen #6 细说
zed1018
2022-08-31 19:28:23 +08:00
如果一定要 everything 我选择 kotlin ,java 有的我都有,我有的 java 真不一定现在就有,而且 non-nullable type 这个对我来讲太刚需
SuperMild
2022-08-31 19:31:27 +08:00
@qW7bo2FbzbC0 一直听说 C# 的优秀,以后找个机会研究研究学习学习。

@lisongeee kotlin 用了更多函数式编程方法,我脑子不太够用,总觉得 kotlin 用起来反而比 java 更累,java 还是比较直白的。
fzdwx
2022-08-31 19:37:41 +08:00
然后这个写 Java for everything 的人的 github 的置顶项目没有一个 Java 写的。太搞了哈哈。
wuxqing
2022-08-31 19:55:32 +08:00
如果不搞 spring 那个体系,https://solon.noear.org/ 这个看着也很简洁。
fzdwx
2022-08-31 20:02:41 +08:00
@wuxqing #12
solon 就代码组织形式跟 spring 就什么区别吗?
cyningxu
2022-08-31 20:10:10 +08:00
kotlin ,你是我的神!
Veneris
2022-08-31 20:16:11 +08:00
go 打成二进制包就可以了,java 需要 jre ,不过反过来说 java 因此也是跨平台的了,这一点是优点还是缺点见仁见智
但是 java 打出来的包体积,启动后的内存占,普遍要大一些,有时候我只是想写个玩具项目而已,总给我一种很笨重的感觉
另外,kotlin 可以 native 了,不过还没有具体尝试过
Leviathann
2022-08-31 20:20:57 +08:00
@Veneris kotlin 的 native ,目前还不如借助 graalvm 的 jvm native
proxychains
2022-08-31 20:21:53 +08:00
我先来
感觉不如 php...java
SuperMild
2022-08-31 20:26:15 +08:00
@Veneris Go 在这方面真是这大优点,如果是做东西放到 VPS 上去用,我现在也是倾向于用 Go
TWorldIsNButThis
2022-08-31 20:30:25 +08:00
@SuperMild 恩 习惯 kotlin 的 lambda 算是一个坎,lambda 也是 kotlin 语法魔术的核心
另外 kotlin 也比较推崇灵活变换隐含的 receiver 来实现更接近自然语言的表达
Huelse
2022-08-31 20:41:40 +08:00
来体验下 scala fp 吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/876788

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX