多年以前我看到一篇神奇的文章 Java for Everything, 其中提出了一个大胆的想法:就连脚本小工具都用 Java 来写。
我读了这篇文章,但并没有立即使用 Java, 而是写了一段时间 Go, 又写了一段时间 Python, 最近想起这篇文章,就想用 Java 写点东西。
本来 Java 是很啰嗦的,这是它最被诟病的地方了。
但现在 Java 有了 record, lambda, Stream API, var(类型推断) 等等, 已经变得不是太啰嗦了,根据我狭隘的个人经验,甚至认为比 Go, Python 更简洁。
if err != nil
, 代码是很简明易懂,
但论代码的简短,也是经常比不上 Java 。以前我喜欢用 Go 来做一些自用的小软件,做一个本地网站通过访问网页来使用, 最近想做一个叫 monostich 的小工具,就尝试用 Java 来做。
monostich 的功能非常简单。
这次我用 Javalin 来做本地网站,并且采用了以前我写 Go 时的代码组织方式, 因此两种语言可以做个对比。
可见, 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);
}
}
可见, 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, 相关介绍请看以下链接。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.