Java/Go双修 - Go基础语法与Java对比

463 阅读6分钟

1.变量声明

  • Java
int num = 0;
Integer num = 0;
Integer num = new Integer(0);
String str = "";
String str = new String("");
  • Go
var num int
var num int = 0
num := 0
var str string = ""
str := ""

2.常量定义

  • Java

    Java直接.这个枚举输出的是这个枚举的名字

image.png

  • Go

    常量的定义其实和Java没有什么不同,都是一个.go文件(类文件)通过 . 的方式进行访问

    Go的常量定义要是想让外部包访问,就必须让首字母大写,比如大写的A、B能访问,但是小写的c不能在常量包外访问

image.png

3.集合与切片

  • Java 集合 -> 动态数组
int[] nums = new int[10]; // 数组
List<Integer> list = new ArrayList<>(); // 集合
  • Go 切片 -> 动态数组
var nums = [2]int{} // 数组
var nums = make([]int,0) // 切片 nums := make([]int,0)
nums := make([]int,0)
nums := []int{}

4.Map哈希表

  • Java
Map<String,String> map = new HashMap<>();
map.put("tmp","tmp");
// 如何遍历 1.遍历Entry 2.遍历key,通过key去map拿
for (Map.Entry<String, String> entry : map.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();
    System.out.println("Key: " + key + ", Value: " + value);
}
for (String key : map.keySet()) {
  	System.out.println("Key: " + map.get(key));
}
  • Go
var myMap = map[string]string
myMap := make(map[string]string)
myMap["tmp"] = "tmp"
// 如何遍历 for...range即可
for key, value := range myMap {
  	fmt.Printf("Key: %s, Value: %d\n", key, value)
}
// 也可以采用匿名变量的方法
for key := range myMap {
  	fmt.Printf("Key: %s\n", key)
}
for _, value := range myMap {
  	fmt.Printf("Value: %d\n", value)
}
  • 直接赋值和make函数的区别,其实就是Java中的懒加载机制
    • 使用 make 函数 : make 函数会为切片分配底层数组的内存空间,即使长度为 0,也会分配一定的内存,初始时没有元素。
    • 直接声明 :直接声明的方式只是创建了一个空切片,底层数组的内存分配会在后续添加元素时进行。

5.条件语句

  • Java
String str = "test";
if(str.equals("test")) {
	// todo
}
  • Go
str := "test"
if str == "test" {
	// todo
}
  • Java里面判断字符串是否相等需要通过equals判断,那为什么Go可以用==来判断?
    • Java : String 是引用类型, == 比较的是对象的引用,而 equals 方法比较的是对象的内容
    • Go :字符串是值类型, == 运算符直接比较字符串的内容,因此可以直接使用 == 来判断字符串是否相等。

6.循环语句

  • Java 有for和while关键字,还有foreach增强for循环
for(int i = 0; i < 10; i++) {
}
List<Integer> list = new ArrayList<>();
for(Intger num : list) {
}
while(condition) {
}
  • Go 只有for这一个关键字 以及range函数遍历
for i := 0; i < 10; i++ {
}
nums := make([]int,0)
for i, num := range nums {
	// i是索引位置 num是对应索引位置的元素
}
// 不想要索引位置也可以直接匿名处理
for _, num := range nums {
	// _ 当作匿名处理
}
for condition {
}
  • Java/Go如何遍历字符串
String str = "hello world";
for(int i = 0; i < str.length(); i++) {
		System.out.println(str.charAt(i));
}
str := "hello world"
for index, char := range str {
		fmt.Printf("index: %d, char: %c\n", index, char)
}

7.函数声明

  • Java
public void test1(String s) {
}
public String test2(String s) {
}
  • Go
func test1(s string) {
}
func test2(s string) string {
}

8.函数调用

Java是同个类下的函数式可以直接调用的,Go语言没有类的概念,Go是同个包package下的函数都可以直接调用

  • Java 跨类调用需要有staic修饰,可以直接通过类名.调用
class A {
	public static String test() {
		return "hello world";
	}
}
class B {
	public static void main(String[] args) {
			String res = A.test();
	}
}
  • Go 跨包调用需要将函数首字母大写,下面的utils包中的Add()函数必须是Add不能是add,Go通过第一个字母大小写来确定访问范围
project/
├── main.go
└── utils/
    └── math.go
package utils
// 定义一个导出的函数
func Add(a, b int) int {
    return a + b
}

package main
import (
    "fmt"
    // 导入 utils 包
    "project/utils" 
)
func main() {
    result := utils.Add(1, 2)
}

9.finally / defer

defer是Go语言的特性,简单来说就是一个延迟函数,当函数return的时候会调用

对应的用Java的finally来理解这个defer

  • Java 当写了finally之后,只要能走完try前面的代码,这个finally就一定会执行
try {

} catch(Exception e) {

} finally {
	// todo
}
  • Go
func defer1() {
  fmt.println("defer1")
}
func main() {
  defer defer1()
  fmt.println("main")
  return;
}
/**********************/
输出:
main
defer1

一个函数可以有多个defer,多个defer的执行顺序是先进后出LIFO,就跟栈是一样的

func defer1() {
  fmt.println("defer1")
}
func defer2() {
  fmt.println("defer2")
}
func main() {
  defer defer1()
  defer defer2()
  fmt.println("main")
  return;
}
/**********************/
输出:
main
defer2
defer1

10.异常机制error捕获

  • Java
try {

} catch(Exception e) {
	// todo
}
  • Go

    panic就是我们说的出现错误,recover机制是将异常捕获,打印出异常,方便定位错误,一般是用recover和defer搭配捕获异常

func main() {
		defer func() {
			if error := recover(); error != nil {
					fmt.Println("出现了panic,使用recover获取信息:",error)
			}
		}()
}

panic传递和Java的throw同理,如果当前函数没有捕获该异常,则不断抛给上层函数进行recover()

package main

import "fmt"

func testPanic1() {
    fmt.Println("testPanic1上半部分")
    testPanic2()
    fmt.Println("testPanic1下半部分")
}

func testPanic2() {
    defer func() {
        recover()
    }()
    fmt.Println("testPanic2上半部分")
    testPanic3()
    fmt.Println("testPanic2下半部分")
}

func testPanic3() {
    fmt.Println("testPanic3上半部分")
    panic("在testPanic3出现了panic")
    fmt.Println("testPanic3下半部分")
}

func main() {
    fmt.Println("程序开始")
    testPanic1()
    fmt.Println("程序结束")
}

输出结果

程序开始
testPanic1上半部分
testPanic2上半部分
testPanic3上半部分
testPanic1下半部分
程序结束

11.接口interface

  • Java interface 实现了这个接口就必须实现这个接口的所有方法
public class PhoneExample {
    // 定义Phone接口
    interface Phone {
        void call();
        void sendMessage();
    }
    // 定义Apple类实现Phone接口
    static class Apple implements Phone {
        private String phoneName;
        public Apple(String phoneName) {
            this.phoneName = phoneName;
        }
        @Override
        public void call() {
            System.out.printf("%s有打电话功能\n", phoneName);
        }
        @Override
        public void sendMessage() {
            System.out.printf("%s有发短信功能\n", phoneName);
        }
    }

    // 定义HuaWei类实现Phone接口
    static class HuaWei implements Phone {
        private String phoneName;
        public HuaWei(String phoneName) {
            this.phoneName = phoneName;
        }
        @Override
        public void call() {
            System.out.printf("%s有打电话功能\n", phoneName);
        }
        @Override
        public void sendMessage() {
            System.out.printf("%s有发短信功能\n", phoneName);
        }
    }
  public static void main(String[] args) {
        Phone a = new Apple("apple");
        Phone b = new HuaWei("huawei");
        a.call();
        a.sendMessage();
        b.call();
        b.sendMessage();
        Apple apple = (Apple) a;
        apple.phoneName = "Apple";
        apple.call();
        apple.sendMessage();
    }
}
  • Go interface 实现了我的所有接口,那就是我的实现类
package main

import "fmt"

type Phone interface {
    Call()
    SendMessage()
}

type Apple struct {
    PhoneName string
}

func (a Apple) Call() {
    fmt.Printf("%s有打电话功能\n", a.PhoneName)
}

func (a Apple) SendMessage() {
    fmt.Printf("%s有发短信功能\n", a.PhoneName)
}

type HuaWei struct {
    PhoneName string
}

func (h HuaWei) Call() {
    fmt.Printf("%s有打电话功能\n", h.PhoneName)
}

func (h HuaWei) SendMessage() {
    fmt.Printf("%s有发短信功能\n", h.PhoneName)
}

func main() {
    a := Apple{"apple"}
    b := HuaWei{"huawei"}
    a.Call()
    a.SendMessage()
    b.Call()
    b.SendMessage()

    var phone Phone
    phone = new(Apple) 
    phone.(*Apple).PhoneName = "Apple" 
    phone.Call()
    phone.SendMessage()
}

12.Java类/Go结构体

  • Java
public class Task {

    private int status;

    private String name;

    public static void main(String[] args) {
        Task task1 = new Task(0,"未运行");
        Task task2 = new Task();
        task2.setStatus(0);
        task2.setName("未运行");
    }

    public Task() {

    }
    public Task(int status, String name) {
        this.status = status;
        this.name = name;
    }
    public int getStatus() {
        return status;
    }
    public void setStatus(int status) {
        this.status = status;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
  • Go
type Task struct {
	Status int8
	Name string
}

func NewTaskPtr(status int8, name string) *Task {
	return &Task{
		Status: status,
		Name:   name,
	}
}

func (task *Task) GetStatus() int8 {
	return task.Status
}

func (task *Task) GetName() string{
	return task.Name
}

func main() {
	task := Task{
		Status: 0,
		Name: "未运行",
	}
	fmt.Println("task:{}",task)
}