我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么将Java代码移植到Go中

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么将Java代码移植到Go中

这篇文章主要讲解了“怎么将Java代码移植到Go中”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么将Java代码移植到Go中”吧!

测试,代码覆盖率

自动化测试和代码覆盖率追踪,可以让大型项目获益匪浅。

我使用 TravisCI 和 AppVeyor 进行测试。Codecov.io 用来检测代码覆盖率。还有许多其他的类似服务。

我同时使用 AppVeyor 和 TravisCI,是因为 Travis 在一年前不再支持 Windows,而 AppVeyor 不支持  Linux。

如果现在让我重新选择这些工具,我将只使用 AppVeyor,因为它现在支持 Linux 和 Windows 平台的测试,而 TravisCI  在被私募股权公司收购并炒掉原始开发团队后,前景并不明朗。

Codecov 几乎无法胜任代码覆盖率检测。对于 Go,它将非代码的行(比如注释)当做是未执行的代码。使用这个工具不可能得到 100%  的代码覆盖率。Coveralls 看起来也有同样的问题。

聊胜于无,但这些工具可以让情况变得更好,尤其是对 Go 程序而言。

Go 的竞态检测非常棒

一部分代码使用了并发,而并发很容易出错。

Go 提供了竞态检测器,在编译时使用 -race 字段可以开启它。

它会让程序变慢,但额外的检查可以探测是否在同时修改同一个内存位置。

我一直开启 -race 运行测试,通过它的报警,我可以很快地修复那些竞争问题。

构建用于测试的特定工具

大型项目很难通过肉眼检查验证正确性。代码太多,你的大脑很难一次记住。

当测试失败时,仅从测试失败的信息中找到原因也是一个挑战。

数据库客户端驱动与 RavenDB 数据库服务端使用 HTTP 协议连接,传输的命令和响应的结果使用 JSON 编码。

当把 Java 测试代码移植到 Go 时,如果可以获取 Java 客户端与服务端的 HTTP 流量,并与移植到 Go 的代码生成的 HTTP  流量对比,这个信息将非常有用。

我构建了一些特定的工具,帮我完成这些工作。

为了获取 Java 客户端的 HTTP 流量,我使用 Go 构建了一个 logging HTTP 代理,Java 客户端使用这个代理与服务端交互。

对于 Go 客户端,我构建了一个可以拦截 HTTP 请求的钩子。我使用它把流量记录在文件中。

然后我就可以对比 Java 客户端与 Go 移植的客户端生成的 HTTP 流量的区别了。

移植的过程

你不能随机开始迁移 5 万行代码。我确信,如果每一个小步骤之后不进行测试和验证的话,我都会被整体代码的复杂性给打败。

对于 RavenDB 和 Java 代码库,我是新手。所以我的***步是深入理解这份 Java 代码的工作原理。

客户端的核心是与服务端通过 HTTP 协议交互。我捕获并研究了流量,编写最简单的与服务器交互的 Go 代码。

当这么做有效果之后,我自信可以复制这些功能。

我的***个里程碑是移植足够的代码,可以通过移植最简单的 Java 测试代码的测试。

我使用了自底向上和自上到下结合的方法。

自底向上的部分是指,我定位并移植那些用于向服务器发送命令和解析响应的调用链底层的代码。

自上到下的部分是指,我逐步跟踪要移植的测试代码,来确定需要移植实现的功能代码部分。

在成功完成***步移植后,剩下的工作就是一次移植一个测试,同时移植可通过这个测试的所有需要的代码。

当测试移植并测试通过后,我做了一些让代码更加 Go 风格的改进。

我相信这种一步一步渐进的方法,对于完成移植工作是很重要的。

从心理学角度来看,在面对一个长年累月的项目时,设置简短的中间态里程碑是很重要的。不断的完成这些里程碑让我干劲十足。

一直让代码保持可编译、可运行和可通过测试的状态也很好。当最终要面对那些日积月累的缺陷时,你将很难下手解决。

移植 Java 到 Go 的挑战

移植的目标是要尽可能与 Java 代码库一致,因为移植的代码需要与 Java 未来的变化保持同步。

有时我吃惊于自己以一行一行的方式移植的代码量。而移植过程中,最耗费时间的部分是颠倒变量的声明顺序,Java 的声明顺序是 type name ,而 Go  的声明顺序是 name type 。我真心希望有工具可以帮我完成这部分工作。

String vs. string

在 Java 中, String 是一个本质上是引用(指针)的对象。因此,字符串可以为 null 。

在 Go 中 string 是一个值类型。它不可能是 nil ,仅仅为空。

这并不是什么大问题,大多情况下我可以无脑地将 null 替换为 "" 。

Errors vs. exceptions

Java 使用异常来传递错误。

Go 返回 error 接口的值。

移植不难,但需要修改大量的函数签名,来支持返回错误值并在调用栈上传播。

泛型

Go (目前)并不支持泛型。

移植泛型的接口是***的挑战。

下面是 Java 中一个泛型方法的例子:

public <T> T load(Class<T> clazz, String id) {

调用者:

Foo foo = load(Foo.class, "id")

在 Go 中,我使用两种策略。

其中之一是使用 interface{} ,它由值和类型组成,与 Java 中的 object  类似。不推荐使用这种方法。虽然有效,但对于这个库的用户而言,操作 interface{} 并不恰当。

在一些情况下我可以使用反射,上面的代码可以移植为:

func Load(result interface{}, id string) error

我可以使用反射来获取 result 的类型,再从 JSON 文档中创建这个类型的值。

调用方的代码:

var result *Foo err := Load(&result, "id")

函数重载

Go 不支持(很大可能永远不会支持)函数重载。

我不确定我是否找到了正确的方式来移植这种代码。

在一些情况下,重载用于创建更简短的帮助函数:

void foo(int a, String b) {} void foo(int a) { foo(a, null); }

有时我会直接丢掉更简短的帮助函数。

有时我会写两个函数:

func foo(a int) {} func fooWithB(a int, b string) {}

当潜在的参数数量很大时,有时我会这么做:

type FooArgs struct {     A int     B string } func foo(args *FooArgs) { }

继承

Go 并不是面向对象语言,没有继承。

简单情况下的继承可以使用嵌套的方法移植。

class B : A { }

有时可以移植为:

type A struct { } type B struct {     A }

我们把 A 嵌入到 B 中,因此 B 继承了 A 所有的方法和字段。

这种方法对于虚函数无效。

并没有好方法移植那些使用虚函数的代码。

模拟虚函数的一个方式是将结构体和函数指针嵌套。这本质上来说,是重新实现了 Java 免费提供的,作为 object 实现一部分的虚表。

另一种方式是写一个独立的函数,通过类型判断来调度给定类型的正确函数。

接口

Java 和 Go 都有接口,但它们是不一样的内容,就像苹果和意大利香肠的区别一样。

在很少的情况下,我确实会创建 Go 的接口类型来复制 Java 接口。

大多数情况下,我放弃使用接口,而是在 API 中暴露具体的结构体。

依赖包的循环引入

Java 允许包的循环引入。

Go 不允许。

结果就是,我无法在移植中复制 Java 代码的包结构。

为了简化,我使用一个包。这种方法不太理想,因为这个包***会变得很臃肿。实际上,这个包臃肿到在 Windows 下 Go 1.10  无法处理单个包内的那么多源文件。幸运的是,Go 1.11 修复了这个问题。

私有(private)、公开(public)、保护(protected)

Go 的设计师们被低估了。他们简化概念的能力是***的,权限控制就是其中的一个例子。

其他语言倾向于细粒度的权限控制:(每个类的字段和方法)指定最小可能粒度的公开、私有和保护。

结果就是当外部代码使用这个库时,这个库实现的一些功能和这个库中其他的类有一样的访问权限。

Go 简化了这个概念,只拥有公开和私有,访问的范围限制在包的级别。

这更合理一些。

当我想要写一个库,比如说,解析 markdown,我不想把内部实现暴漏给这个库的使用者。但对于我自己隐藏这些内部实现,效果恰恰相反。

Java  开发者注意到这个问题,有时会使用接口作为修复过度暴漏的类的技巧。通过返回一个接口,而不是具体的类,这个类的使用者就无法看到一些可用的公开接口。

并发

简单来说,Go 的并发是***的,内建的竞态检测器非常有助于解决并发的问题。

我刚才说过,我进行的***个移植是模拟 Java 接口。比如,我实现了 Java CompletableFuture 类的复制。

只有在代码可以运行后,我才会重新组织代码,让代码更加符合 Go 的风格。

流畅的函数链式调用

RavenDB 拥有复杂的查询能力。Java 客户端使用链式方法构建查询:

List<ReduceResult> results = session.query(User.class)                         .groupBy("name")                         .selectKey()                         .selectCount()                         .orderByDescending("count")                         .ofType(ReduceResult.class)                         .toList();

链式调用仅在通过异常进行错误交互的语言中有效。当一个函数额外返回一个错误,就没法向上面那样进行链式调用。

为了在 Go 中复制链式调用,我使用了一个“状态错误(stateful error)”的方法:

type Query struct {     err error }  func (q *Query) WhereEquals(field string, val interface{}) *Query {     if q.err != nil {         return q     }     // logic that might set q.err     return q }  func (q *Query) GroupBy(field string) *Query {     if q.err != nil {         return q     }     // logic that might set q.err     return q }  func (q *Query) Execute(result inteface{}) error {     if q.err != nil {         return q.err     }     // do logic }

链式调用可以这么写:

var result *Foo err := NewQuery().WhereEquals("Name", "Frank").GroupBy("Age").Execute(&result)

JSON 解析

Java 没有内建的 JSON 解析函数,客户端使用 Jackson JSON 库。

Go 在标准库中有 JSON 的支持,但它没有提供足够多的钩子函数来展现 JSON 解析的过程。

我并没有尝试匹配所有的 Java 功能,因为 Go 内置的 JSON 支持看起来已经足够灵活。

Go 代码更短

简短不是 Java 的属性,而是写出符合语言习惯代码的文化的属性。

在 Java 中,setter 和 getter 方法很常见。比如,Java 代码:

class Foo {     private int bar;      public void setBar(int bar) {         this.bar = bar;     }      public int getBar() {         return this.bar;     } }

Go 语言版本如下:

type Foo struct {     Bar int }

3 行 vs 11 行。当你有大量的类,类内有很多成员时,这么做可以不断累加这些类。

大部分其他的代码***长度基本差不多。

使用 Notion 来组织工作

我是 Notion.so 的重度用户。用最简单的话来说,Notion 是一个多级笔记记录应用。可以把它看做是 Evernote 和 wiki  的结合,是由***软件设计师精心设计和实现的。

下面是我使用 Notion 组织 Go 移植工作的方式:

怎么将Java代码移植到Go中

下面是具体的内容:

我有一个没有在上面展示的带日历视图的页面,用来记录在特定时间的工作内容和花费时间的简短笔记。因为这次合约是按小时收费,所以工作时长的统计是很重要的信息。感谢这些笔记,我知道我在  11 个月里在这次开发上花费了 601 个小时。

客户喜欢了解进展。我有一个页面,记录了每月的工作总结,如下所示:

怎么将Java代码移植到Go中

这些页面与客户共享。

  • 当开始每天的工作时,短期的 todo list 很有用。

怎么将Java代码移植到Go中

  • 我甚至用 Notion 页面管理发票,使用“导出为 PDF”功能来生成发票的 PDF 版本。

待招聘的 Go 程序员

你的公司还需要 Go 开发者吗?你可以雇用我

额外的资源

针对问题,我提供了一些额外的说明:

Hacker News discussion  /r/golang discussion

感谢各位的阅读,以上就是“怎么将Java代码移植到Go中”的内容了,经过本文的学习后,相信大家对怎么将Java代码移植到Go中这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么将Java代码移植到Go中

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

使用2to3将代码移植到Python 3

概述#几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下。为了简化这个转换过程,Python 3自带了一个叫做2to3的实用脚本(Utility Script),这个脚本会将你的Python 2程序源文件作
2023-01-31

Qt5代码怎么移植到Qt6

本篇内容主要讲解“Qt5代码怎么移植到Qt6”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Qt5代码怎么移植到Qt6”吧!尝试下Qt5的代码是否可以正常在Qt6上编译通过,使用的我网易云代码,这
2023-07-05

怎么将idea中是代码上传到gitlab

作为一款流行的代码开发工具,IntelliJ IDEA(以下简称 IDEA)在代码管理和版本控制方面表现非常出色。与此同时,GitLab 作为一个强大的代码托管平台,也在开发团队中得到了广泛的使用。那么,本文将向大家介绍如何将 IDEA 中
2023-10-22

怎么在Linux中将MySQL迁移到MariaDB

本篇内容介绍了“怎么在Linux中将MySQL迁移到MariaDB”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!如果你想要将 MySQL 中
2023-06-16

怎么将代码提交到Gitee仓库

这篇“怎么将代码提交到Gitee仓库”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么将代码提交到Gitee仓库”文章吧。注
2023-07-05

怎么将项目完美迁移到Python3中

本篇内容主要讲解“怎么将项目完美迁移到Python3中”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么将项目完美迁移到Python3中”吧!1、使用 2to3从几年前开始,Python 在你或
2023-06-02

怎么将Django项目迁移到linux系统中

这篇文章主要介绍“怎么将Django项目迁移到linux系统中”,在日常操作中,相信很多人在怎么将Django项目迁移到linux系统中问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么将Django项目迁移
2023-07-05

怎么将代码从gitlab上下到电脑上

随着大数据和人工智能的快速发展,越来越多的人开始涉足编程和开发领域。而Git作为全球最流行的代码版本控制工具之一,受到了开发者们的热捧和使用。Gitlab则是Git的在线托管平台之一,方便开发者们进行代码管理和协作,同时也是很多团队选择的代
2023-10-22

怎么将GitLab上的代码拉取到本地

本篇内容介绍了“怎么将GitLab上的代码拉取到本地”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!第一步:创建一个GitLab账户首先,你需
2023-07-05

Go代码中怎么绑定Host

这篇文章主要为大家展示了“Go代码中怎么绑定Host”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Go代码中怎么绑定Host”这篇文章吧。本文示例:IP:192.168.1.102,也就是说需要
2023-06-27

怎么将自己的代码上传到gitlab上面

随着程序员们不断地编写代码,代码的管理越来越成为了一件非常重要的事情。GitLab是一种很好的代码托管平台,它可以帮助我们在一个中心化的地方管理我们的代码库,并且方便地进行版本控制。本文将介绍如何将自己的代码上传到GitLab上。创建一个G
2023-10-22

Ubuntu面向对象的框架Qt移植到开发板后怎么显示中文

这篇文章主要介绍“Ubuntu面向对象的框架Qt移植到开发板后怎么显示中文”,在日常操作中,相信很多人在Ubuntu面向对象的框架Qt移植到开发板后怎么显示中文问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”U
2023-06-13

怎么将java代码生成可执行程序

要将Java代码生成可执行程序,可以按照以下步骤进行操作:编写Java代码文件:使用文本编辑器(如Notepad++、Sublime Text等)编写Java源代码文件,以.java作为文件扩展名。编译Java代码:打开命令行终端,导航到存
2023-10-24

怎么使用Git将本地的代码上传到Gitee上

这篇文章主要介绍“怎么使用Git将本地的代码上传到Gitee上”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用Git将本地的代码上传到Gitee上”文章能帮助大家解决问题。1. 申请 Gite
2023-07-05

网站开发中网站被植入恶意代码该怎么解决

本篇文章为大家展示了网站开发中网站被植入恶意代码该怎么解决,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。如何快速恢复网站被黑后的正常访问首先通过登录ftp,如果没有ftp信息的话可以向当初做网站的建
2023-06-04

编程热搜

目录