Java 程序员极速上手 go

简介: Java 程序员极速上手 go

随着 Go 语言的流行,很多公司的技术栈在往 Go 上转,但很多招进来的后端开发工程师都是 Java 技术栈,然后在工作中边学边上手。

那么 Java 程序员要想极速上手 Go,应该从哪些方面入手呢?

对于已经有一定基础的 Java 工程师,可以思考自己以前用 Java 编程时,最常使用的语言特性,列一个清单出来。然后按照这个清单,去学习 Go 语言的对应实现方式,这样能够有针对性的的学习,有的放矢。

下面是我使用 Java 进行日常工作中经常使用的5个编程要点,我会介绍这些要点对应的 Go 实现,仅供大家参考。

1. 并发编程(Concurrency)

Go语言通过goroutine和channel提供了轻量级的并发编程模型,与Java的线程模型相比更加简洁和高效。下面是一个简单的并发示例:

package main
import (
    "fmt"
    "time"
)
func main() {
    // 创建一个 go routine
    go sayHello("World")
    
    // 主 goroutine 打印 Hello
    sayHello("Gopher")
}
func sayHello(name string) {
    for i := 0; i < 5; i++ {
        fmt.Println("Hello", name)
        time.Sleep(time.Second)
    }
}

执行上述 go 代码,打印输出:

笔者另外一篇文章,曾经详细介绍过 Go 的并发编程,大家可以移步我这篇腾讯云社区文章:

通过三个例子,学习 Go 语言并发编程的利器 - goroutine

2. 内置并发安全的Map(Built-in concurrency-safe Map)

在Go语言中,内置了并发安全的map类型(sync.Map),可以在多个goroutine中安全地读写数据,而无需额外的锁。以下是一个使用sync.Map的示例:

package main
import (
    "fmt"
    "sync"
)
func main() {
    var m sync.Map
    
    // 写入键值对
    m.Store("key", "value")
    
    // 读取键对应的值
    value, ok := m.Load("key")
    if ok {
        fmt.Println(value)
    }
}

执行上述代码,最后打印 value

这段代码是一个简单的Go语言程序,它演示了如何使用sync.Map进行并发安全的键值对操作。下面是逐行解释这段代码的含义:

  1. package main:声明这个文件属于main包,表明这是一个可执行程序的入口文件。
  2. import (:引入需要使用的外部包,这里使用了"fmt"和"sync"包。
  3. "fmt":引入了用于格式化输出的标准库包。
  4. "sync":引入了用于同步操作的标准库包。
  5. func main() {:定义了程序的主函数。
  6. var m sync.Map:声明了一个变量m,类型为sync.Map。sync.Map是Go语言提供的一种并发安全的map类型,可以在多个goroutine中安全地读写数据,而无需额外的锁。
  7. m.Store("key", "value"):向map m中存储键值对,键为"key",值为"value"。
  8. value, ok := m.Load("key"):从map m中读取键为"key"的值,如果键存在,则将值赋给变量value,并将ok设置为true;如果键不存在,则value为nil,ok为false。这里使用了多重赋值的方式。
  9. if ok {:判断变量ok是否为true,如果为true,说明键存在。
  10. fmt.Println(value):打印键"key"对应的值value。
  11. }:if语句的结束。

整个程序的逻辑很简单,就是先向sync.Map中存储了一个键值对,然后再从中读取出来并打印出对应的值。由于sync.Map是并发安全的,所以可以在多个goroutine中安全地进行这些操作。

3. 错误处理(Error Handling)

Go语言采用显式的错误处理机制,通过返回error类型来传递错误信息,而不是Java中的异常。下面是一个简单的错误处理示例:

package main
import (
    "errors"
    "fmt"
)
func divide(x, y int) (int, error) {
    if y == 0 {
        return 0, errors.New("division by zero")
    }
    return x / y, nil
}
func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("Result:", result)
}

执行之后的输出:

以下是对代码逐行解释的含义:

import (
    "errors"
    "fmt"
)

这里使用了import关键字引入了两个标准库包。errors包用于创建和处理错误信息,fmt包用于格式化输出。

func divide(x, y int) (int, error) {

这行代码定义了一个名为divide的函数。这个函数接受两个int类型的参数xy,并返回两个值,第一个值是int类型的商,第二个值是error类型的错误信息(如果有错误的话)。

if y == 0 {
    return 0, errors.New("division by zero")
}

在函数内部,首先检查y是否为零。如果y为零,就会调用errors.New函数创建一个新的错误,其中包含字符串"division by zero",然后返回0和该错误。

return x / y, nil

如果y不为零,则返回x / y作为商,并且返回nil表示没有错误发生。

func main() {

这行代码定义了程序的主函数。

result, err := divide(10, 0)

在主函数中,调用了divide函数,传入了参数10和0。result接收到divide函数返回的商,err接收到可能返回的错误。

if err != nil {

检查err是否不为nil,如果不为nil,说明函数调用过程中发生了错误。

fmt.Println("Error:", err)

如果有错误发生,使用fmt.Println打印错误信息。

return

然后通过return语句结束函数执行。

fmt.Println("Result:", result)

如果没有发生错误,则打印商的结果。

整体而言,这段代码展示了一个简单的除法函数,并演示了如何处理可能的错误情况。

4. defer和panic/recover(defer and panic/recover)

Go语言提供了defer关键字用于延迟执行函数调用,以及panic和recover机制用于处理异常。以下是一个使用defer和panic/recover的示例:

package main
import "fmt"
func recoverName() {
    if r := recover(); r != nil {
        fmt.Println("recovered from", r)
    }
}
func fullName(firstName *string, lastName *string) {
    defer recoverName()
    if firstName == nil {
        panic("runtime error: first name cannot be nil")
    }
    if lastName == nil {
        panic("runtime error: last name cannot be nil")
    }
    fmt.Printf("%s %s\n", *firstName, *lastName)
    fmt.Println("returned normally from fullName")
}
func main() {
    defer fmt.Println("deferred call in main")
    firstName := "John"
    fullName(&firstName, nil)
    fmt.Println("returned normally from main")
}

执行之后,打印的输出结果:

这段代码演示了在Go语言中如何使用deferpanicrecover来处理运行时错误。具体来说,它包含了以下几个关键点:

  1. recoverName()函数定义了一个延迟函数,它通过调用recover()函数来恢复从panic状态中返回的错误信息。如果recover()函数返回的值不为nil,则说明有panic发生,并且在该函数中进行了错误恢复处理。
  2. fullName()函数展示了如何在运行时可能出现错误的情况下使用panic来中断程序执行,并在发生错误时抛出错误信息。在这个函数中,首先使用defer关键字来延迟执行recoverName()函数,以确保无论是否发生panic,都能在函数退出时执行恢复处理。然后,通过检查传入的指针是否为nil来判断是否存在运行时错误,如果存在错误,就会触发panic,并且程序会跳转到最近的defer语句执行。
  3. main()函数是程序的入口点。在这个函数中,通过使用defer语句来延迟执行fmt.Println("deferred call in main"),确保该语句会在函数退出时被执行。然后定义了一个firstName变量,并调用了fullName()函数,将firstName的地址和一个nil指针作为参数传递给该函数。由于lastName参数为nil,因此会触发panic,并且程序会跳转到fullName()函数中执行错误处理。最后,fmt.Println("returned normally from main")语句会在main()函数正常返回时执行,但由于在调用fullName()函数时已经发生了panic,因此该语句不会被打印出来。

5. 结构体(Structs)和接口(Interfaces)

Go语言中的结构体和接口是非常灵活和强大的,可以有效地组织代码和实现多态性。下面是一个使用结构体和接口的示例:

package main
import (
    "fmt"
)
type Shape interface {
    Area() float64
}
type Rectangle struct {
    Width  float64
    Height float64
}
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}
type Circle struct {
    Radius float64
}
func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}
func printArea(s Shape) {
    fmt.Println("Area:", s.Area())
}
func main() {
    rect := Rectangle{Width: 5, Height: 3}
    circle := Circle{Radius: 4}
    
    printArea(rect)
    printArea(circle)
}

执行之后的代码输出:

这段代码演示了如何在Go语言中使用接口和结构体来实现多态性。具体来说,它包含了以下几个关键点:

  1. Shape接口:定义了一个Shape接口,该接口包含一个Area()方法,用于计算形状的面积。任何实现了Area()方法的类型都可以被视为Shape接口的实现者。
  2. Rectangle结构体:定义了一个Rectangle结构体,包含了WidthHeight两个字段,分别表示矩形的宽度和高度。此外,还实现了Area()方法,用于计算矩形的面积。
  3. Circle结构体:定义了一个Circle结构体,包含了Radius字段,表示圆的半径。同样,它也实现了Area()方法,用于计算圆的面积。
  4. printArea()函数:定义了一个printArea()函数,接受一个Shape类型的参数,并调用其Area()方法来打印形状的面积。
  5. main()函数:程序的入口点。在这个函数中,创建了一个Rectangle类型的变量rect和一个Circle类型的变量circle,并分别传递给printArea()函数进行面积打印。由于RectangleCircle类型都实现了Shape接口的Area()方法,因此它们都可以作为printArea()函数的参数,展示了多态性的特性。

以上只是五个笔者工作中最经常使用到的 Go 特性分享,祝各位 Java 程序员的 Go 转型之路一切顺利。

相关文章
|
5天前
|
Java 程序员 Windows
【Java知识点详解 10】为何要配置环境变量,35岁老年程序员的绝地翻身之路
【Java知识点详解 10】为何要配置环境变量,35岁老年程序员的绝地翻身之路
|
5天前
|
Java 程序员
Java this关键字详解(3种用法),Java程序员面试必备的知识点
Java this关键字详解(3种用法),Java程序员面试必备的知识点
|
7天前
|
Java 程序员 图形学
程序员教你用代码制作飞翔的小鸟--Java小游戏,正好拿去和给女神一起玩
《飞扬的小鸟》Java实现摘要:使用IntelliJ IDEA和JDK 16开发,包含小鸟类`Bird`,处理小鸟的位置、速度和碰撞检测。代码示例展示小鸟图像的加载、绘制与旋转。同时有`Music`类用于循环播放背景音乐。游戏运行时检查小鸟是否撞到地面、柱子或星星,并实现翅膀煽动效果。简单易懂,可直接复制使用。
|
4天前
|
移动开发 搜索推荐 Java
Java如何支持函数式编程?,作为移动开发程序员应该怎样去规划自己的学习路线
Java如何支持函数式编程?,作为移动开发程序员应该怎样去规划自己的学习路线
|
5天前
|
消息中间件 JSON Java
十五,java高级程序员面试宝典
十五,java高级程序员面试宝典
|
5天前
|
NoSQL 算法 Java
【redis源码学习】持久化机制,java程序员面试算法宝典pdf
【redis源码学习】持久化机制,java程序员面试算法宝典pdf
|
7天前
|
缓存 Java 程序员
关于创建、销毁对象⭐Java程序员需要掌握的8个编程好习惯
关于创建、销毁对象⭐Java程序员需要掌握的8个编程好习惯
关于创建、销毁对象⭐Java程序员需要掌握的8个编程好习惯
|
7天前
|
编解码 JavaScript 前端开发
【专栏】介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例
【4月更文挑战第29天】本文介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例。Base64编码将24位二进制数据转换为32位可打印字符,用“=”作填充。文中展示了各语言的编码解码代码,帮助开发者理解并应用于实际项目。
|
7天前
|
Java 大数据 Go
Go vs Java:在大数据处理领域的性能对比
Go与Java在大数据处理中各有特点。Go启动快,内存占用少,静态类型及并发模型(goroutine和channel)使其在并发性能上有优势。Java虽然启动慢,JVM内存占用高,但拥有丰富的生态系统和并发工具。代码示例展示了Go的goroutine和Java的线程池处理大数据的场景。在性能上,Go可能更优,但Java的跨平台性和生态广度使其仍被广泛应用。
|
7天前
|
网络协议 物联网 Java
Go与Java:在物联网领域的适用性分析
本文对比分析了Go和Java在物联网领域的适用性。Go语言因其轻量级、高效和并发特性,适合资源受限的物联网设备,特别是处理并发连接和数据流。Java则凭借跨平台性、丰富的生态系统和企业级应用能力,适用于大型物联网系统和复杂业务场景。两者在物联网领域各有优势,开发者可根据项目需求选择合适的语言。