👉目录
1 语法的“简约”与“简陋”
2 类型系统的“死板”和“灵活”
3 编程语言的‘面向对象’大比拼
4 指针的“直白”表达
5 处理错误的“优雅”与“粗暴”
6 并发的“轻松”与“混乱”
7 反射的“强大”与“局限”
8 社区文化的“开放”与“封闭”
9 结语
12 月 26 日晚 7:30,腾讯云开发者视频号「鹅厂程序员面对面」直播间,我们邀请了作者来为你分析《资金视角看支付系统架构设计》,预约观看有机会抢鹅厂周边好礼!
首先,Java 的语法是相对严谨的,类、接口、继承、抽象……一大堆的关键字让你在写代码时感觉像是在参加一场语法考试。而 Go 的语法则是简约得让人惊讶。你会发现, Go 里没有类的概念,只有结构体(struct)和接口(interface)。这让很多 Java 的 coder在初入 Go 时感到无所适从...
例子:在 Java 中,你可能习惯于写出这样的代码:
public class Dog {
private String name;
public Dog(String name) {
this.name = name;
}
public void bark() {
System.out.println(name + " says Woof!");
}
}
而在 Go 中,你可能会写成:
type Dog struct {
Name string
}
func (d Dog) Bark() {
fmt.Println(d.Name + " says Woof!")
}
乍一看,Go 的代码似乎简单了很多,但对于习惯了 Java 的开发者来说,少了很多“保护”的感觉,心里总是有点不安。你可能会想:“我真的可以不使用构造函数吗?这样会不会出问题?”
Java:
Java 是一种静态类型语言,所有变量的类型在编译时就必须确定。类型检查在编译阶段进行,这有助于捕获类型错误。例如:
int number = 10; // number 的类型在编译时确定为 int
Go:
Go 也是一种静态类型语言,但它支持类型推断。变量的类型可以在声明时省略,编译器会根据赋值自动推断类型。例如:
number := 10 // number 的类型在编译时被推断为 int
Java:
Java 使用显式的类型声明,所有变量和函数参数都需要明确指定类型。例如:
String name = "Alice";
Go:
Go 支持简洁的类型声明,可以使用 := 语法进行简化,同时也可以使用 var 关键字进行显式声明。例如:
var name string = "Alice"
age := 30 // 类型推断为 int
Java:
Java 支持显式和隐式类型转换,但需要注意类型兼容性,特别是在对象之间的转换时。例如:
double d = 10.5;
int i = (int) d; // 显式转换
byte b = 10;
int i = b; // 隐式转换, byte 转换为 int
Go:
Go 也支持显式类型转换,但不支持隐式转换,必须明确指定转换。例如:
var d float64 = 10.5
var i int = int(d) // 显式转换
Person person = new Person("Alice", 30);
// 点了一位名叫 Alice 的顾客
go:
在 Go 的世界里,对象就像是一个随意的 BBQ 聚会。你可以直接用结构体字面量来“烤”出一个对象,简单又直接。
person := Person{Name: "Alice", Age: 30}
// 直接上桌,没那么多讲究
int number = 10; // 这就是我的类型,没得商量
Go:
Go 则是个随性的人,支持类型推断。你可以用 := 直接声明,像是在派对上随便找个饮料喝。
text := "Hello" // 喝什么都行,随便来
Java: 在 Java 的世界里,接口就像是一个严格的俱乐部,只有那些愿意遵守规则的类才能加入。你得用 implements 关键字来申请入会。
Go:
接口是一个方法集,任何实现了这些方法的类型都自动满足该接口。接口不需要显式声明实现。
type Greeter interface {
Greet()
}
type Dog struct{}
func (d Dog) Greet() {
fmt.Println("Woof!")
}
Java:
接口定义了一组方法,类需要使用 implements 关键字来实现接口。Java 接口可以包含默认方法和静态方法。
interface Greeter {
void greet();
}
class Dog implements Greeter {
public void greet() {
System.out.println("Woof!");
}
}
Java:
Java 是个传统的家族,支持单继承。你只能有一个父母(父类),但可以有很多朋友(接口)。
class Dog extends Animal { /* 继承父母的特质 */ }
Go:
Go 则是个现代家庭,支持组合。你可以把多个结构体“嵌入”到一个结构体中,像是把不同的特质混合在一起。
type Dog struct { Animal } // 组合而成,像是拼图
Animal animal = new Dog();
var greeter Greeter = Dog{} // 万花筒
Java: 你得穿好衣服,遵守规则,才能在这个严谨的世界里生存。
Go: 你可以随意穿搭,随性而为,享受生活的乐趣。
特性 | Go | Java |
类和对象 | ||
类的定义 | Go 没有类的概念,使用结构体(struct)来定义数据类型。 | Java 使用类(class)来定义对象的蓝图。 |
对象的创建 | 使用结构体字面量或 new 关键字创建对象。 | 使用 new 关键字创建对象。 |
继承 | Go 不支持传统的继承,但支持组合(embedding)。 | Java 支持单继承和接口的多继承。 |
构造函数 | Go 没有构造函数的概念,通常使用工厂函数来创建对象。 | Java 支持构造函数,可以重载。 |
方法 | 方法可以定义在结构体上,且可以接收指针或值接收者。 | 方法定义在类中,使用 this 关键字访问实例变量。 |
接口 | ||
接口的定义 | 使用 interface 关键字定义接口,方法不需要实现。 | 使用 interface 关键字定义接口,类需要实现接口中的方法。 |
接口实现 | 类型只需实现接口中的方法,自动满足接口,无需显式声明。 | 类使用 implements 关键字显式实现接口。 |
多重接口实现 | 一个类型可以实现多个接口。 | 一个类可以实现多个接口。 |
多态 | ||
多态 | 通过接口实现多态,使用接口类型的变量可以存储任何实现该接口的类型。 | 通过方法重载和方法覆盖实现多态。 |
value := 10
ptr := &value // ptr 是 value 的指针
*ptr = 20 // 修改了 value 的值
try {
// 可能抛出异常的代码
} catch (Exception e) {
e.printStackTrace();
}
result, err := someFunction()
if err != nil {
log.Fatal(err)
}
这种方式虽然让错误处理变得显式,但对于习惯了 Java 的开发者来说,心里总是想着:“难道就不能像 Java 一样优雅地处理错误吗?”随着代码的复杂性增加,错误处理的代码也会随之增多,导致代码的可读性下降。
好的,让我们更详细地探讨一下 Go 的并发模型、Go Modules 和 vendor 目录的使用,并通过具体的例子来说明它们在实际运行中的表现。
假设我们要并发地下载多个网页并打印它们的内容。在 Java 中,你可能会使用线程池来实现,而在 Go 中,你可以使用 goroutine 和 channel 来实现。
Java 示例:
// 导入所需的Java库
import java.io.BufferedReader; // 用于读取输入流
import java.io.InputStreamReader; // 用于将字节流转换为字符流
import java.net.HttpURLConnection; // 用于处理HTTP连接
import java.net.URL; // 用于处理URL地址
import java.util.concurrent.ExecutorService; // 用于管理线程池
import java.util.concurrent.Executors; // 用于创建线程池
// 定义一个名为WebDownloader的公共类
public class WebDownloader {
// 定义主方法,程序的入口点
public static void main(String[] args) {
// 定义一个字符串数组,包含三个URL地址
String[] urls = {" http://example.com" , " http://example.org" , " http://example.net" };
// 创建一个固定大小的线程池,大小为3
ExecutorService executor = Executors.newFixedThreadPool(3);
// 遍历URL数组
for (String url : urls) {
// 提交一个任务到线程池,任务是一个lambda表达式
executor.submit(() -> {
try {
// 打开一个HTTP连接到指定的URL
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
// 创建一个BufferedReader对象,用于读取连接的输入流
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// 定义一个字符串变量,用于存储从输入流中读取的每一行数据
String inputLine;
// 循环读取输入流中的每一行数据,直到没有数据为止
while ((inputLine = in.readLine()) != null) {
// 打印读取到的每一行数据
System.out.println(inputLine);
}
// 关闭BufferedReader对象,释放资源
in.close();
} catch (Exception e) {
// 如果发生异常,打印异常堆栈跟踪信息
e.printStackTrace();
}
});
}
// 关闭线程池,不再接受新的任务,等待所有已提交的任务完成
executor.shutdown();
}
}
// 导入需要的包
package main
import (
"fmt" // 用于格式化输出
"io/ioutil" // 用于读取响应体
"net/http" // 用于发送HTTP请求
"sync" // 用于同步goroutine
)
// 主函数
func main() {
// 定义一个字符串切片,包含需要请求的URL
urls := []string{" http://example.com" , " http://example.org" , " http://example.net" }
// 定义一个WaitGroup,用于等待所有goroutine完成
var wg sync.WaitGroup
// 遍历URL列表
for _, url := range urls {
// 为每个URL增加一个计数器
wg.Add(1)
// 启动一个新的goroutine来处理请求
go func(url string) {
// 在goroutine结束时调用Done(),减少WaitGroup的计数器
defer wg.Done()
// 发送HTTP GET请求
resp, err := http.Get(url)
if err != nil {
// 如果请求出错,打印错误信息并返回
fmt.Println(err)
return
}
// 读取响应体的内容
body, _ := ioutil.ReadAll(resp.Body)
// 打印响应体的内容
fmt.Println(string(body))
// 关闭响应体
resp.Body.Close()
}(url) // 将当前URL传递给goroutine
}
// 等待所有goroutine完成
wg.Wait()
}
sync.WaitGroup
来等待所有的 goroutine 完成。每个 goroutine 都会并发地下载网页内容并打印出来。Go 的并发模型让这个过程变得非常简单和直观。Class > clazz = Dog.class;
Method[] methods = clazz.getDeclaredMethods();
reflect
包,并且需要更多的代码来实现相同的功能:import "reflect"
t := reflect.TypeOf(Dog{})
methods := t.NumMethod()
对于习惯了 Java 的开发者来说,Go 的反射机制可能会让人感到不够直观,尤其是在需要动态处理类型时,反射的局限性可能会让你感到沮丧。
最后,Java 和 Go 的社区文化也有很大不同。Java 社区相对成熟,很多开发者习惯于在 Stack Overflow 和各种论坛上寻求帮助。而 Go 的社区则更加开放,很多开发者习惯于在 GitHub 上直接参与项目的开发和维护。
这让很多 Java 开发者在刚接触 Go 时,可能会感到有些不适应,尤其是在寻求帮助时,可能会觉得“我该去哪里问问题呢?”而且,Go 的文档和社区资源虽然丰富,但有时也会让人感到信息过载,不知道从何入手。
总的来说,从 Java 转到 Go 的过程就像是一场冒险,有惊喜也有收获,欢迎大家分享你们在从 Java 转到 Go 过程中遇到的趣事和挑战,我们一起交流学习!
📢📢欢迎加入腾讯云开发者社群,享前沿资讯、大咖干货,找兴趣搭子,交同城好友,更有鹅厂招聘机会、限量周边好礼等你来~
(长按图片立即扫码)