Analyzing: array, slice, map, zero value - in Go vs Java | Types - Language

Series: Go for Java Developers

This article opens a series of materials about the Go language for developers who are already well acquainted with Java. We will compare the approaches of the two languages to quickly understand how the Go data model is structured and why it looks the way it does.

Why break down basic structures at all

In Java, almost all collections are classes from the standard library. You create an ArrayList, HashMap, HashSet object and work with them.

In Go, everything is organized a bit differently. Many data structures are built directly into the language.

  • array — fixed array
  • slice — dynamic structure on top of an array
  • map — hash table
  • zero value — built-in default value

That is why it is important to understand how they are related to memory. Go simplifies many things, but sometimes it is less obvious for a Java developer.


Array in Go

Array in Go is a fixed-size array. The size is part of the type.

This means that [3]int and [5]int are different types.

Example

// declaring an array of 3 elements
var nums [3]int

// writing values
nums[0] = 10
nums[1] = 20
nums[2] = 30

// output
fmt.Println(nums)

Java equivalent:

// fixed-size array
int[] nums = new int[3];

nums[0] = 10;
nums[1] = 20;
nums[2] = 30;

System.out.println(Arrays.toString(nums));

At first glance — everything is the same. But in Go, arrays are used significantly less often.

In real Go code, slice is almost always used instead of array. Array is more often used as an internal mechanism for data storage.

Slice — the main container of Go

Slice is a dynamic structure, which works on top of an array.

In fact, a slice is a small descriptor, which contains three things:

  • pointer to an array
  • length
  • capacity

Example of slice

// creating a slice
var nums []int

// adding an element
nums = append(nums, 1)

// adding more
nums = append(nums, 2, 3)

fmt.Println(nums)

Java equivalent:

// dynamic list
List<Integer> nums = new ArrayList<>();

// adding elements
nums.add(1);
nums.add(2);
nums.add(3);

System.out.println(nums);

The behavior is similar to ArrayList, but implemented differently.


Slice Backing Array

The most important concept is the backing array.

A slice holds a reference to the array, where the actual data resides.

Schematically, it looks like this:

Slice
 ├─ pointer ────────────┐
 ├─ length              │
 └─ capacity            │
                        ▼
Backing Array
[10][20][30][40][50]

If a new slice is created, it may point to the same array.

Example

// original array
arr := [5]int{1,2,3,4,5}

// creating slice
s1 := arr[1:4]

fmt.Println(s1)

Java equivalent (conditional)


// there is no direct equivalent in Java

int[] arr = {1,2,3,4,5};

// usually part of the array is copied
int[] slice = Arrays.copyOfRange(arr, 1, 4);

System.out.println(Arrays.toString(slice));

In Java, copying occurs more frequently, while in Go, memory sharing is common.

Multiple slices can reference the same backing array. Changing data through one slice will change data in all.

What happens during append

If capacity allows, new elements are added to the same array.

If there is not enough space — Go creates a new array and copies the data.

append()

Slice
  ↓
is capacity sufficient?
   │
   ├─ yes → write to the same array
   │
   └─ no → new array + copying
This is similar to the internal workings of ArrayList, which also increases the internal array.

Map in Go

Map is a built-in hash table.

It is similar to HashMap from Java, but is part of the language.

Example

// creating map
ages := make(map[string]int)

// adding values
ages["Alice"] = 30
ages["Bob"] = 25

fmt.Println(ages["Alice"])

Java equivalent:


// HashMap
Map<String, Integer> ages = new HashMap<>();

ages.put("Alice", 30);
ages.put("Bob", 25);

System.out.println(ages.get("Alice"));

Zero Value — an important feature of Go

In Go, each variable automatically receives a default value.

This is called zero value.

Type Zero value Comment
int 0 numeric zero
string "" empty string
bool false boolean value
slice nil but append still works
map nil needs to be created with make

Example of slice without initialization


// nil slice
var nums []int

// append works
nums = append(nums, 1)

fmt.Println(nums)

Java analogy


// in Java the variable will be null
List<Integer> nums = null;

// nums.add(1) will trigger NullPointerException
Zero value allows for writing less defensive code. Many structures can be used immediately after declaration.

Comparison of Go and Java

Concept Go Java Comment
Array array array similar
Dynamic List slice ArrayList slice is built into the language
Hash Table map HashMap map is part of the language
Default Value zero value null / 0 fewer null errors in Go
Memory Management slice + backing array internal array similar to ArrayList

Constants / Constants

In Go, constants are declared using const and hold immutable values. You can create single or group constants. The difference from Java is that types can be implicit and iota is supported for automatic sequence generation.

Example of a single constant

// Go
const Pi = 3.14159

func main() {
    fmt.Println(Pi)
}

Java equivalent:

// Java
class Main {
    static final double PI = 3.14159;

    public static void main(String[] args) {
        System.out.println(PI);
    }
}

Example of group constants with iota

// Go
const (
    Sunday = iota
    Monday
    Tuesday
)

func main() {
    fmt.Println(Sunday, Monday, Tuesday) // 0 1 2
}

Java equivalent through enum:

// Java
enum Day { SUNDAY, MONDAY, TUESDAY }

public class Main {
    public static void main(String[] args) {
        System.out.println(Day.SUNDAY.ordinal()); // 0
        System.out.println(Day.MONDAY.ordinal()); // 1
        System.out.println(Day.TUESDAY.ordinal()); // 2
    }
}
Tip: use iota for consecutive numeric constants. Enum in Java provides similar functionality but is more strictly typed.

Practical conclusion

For a Java developer, the most important thing is to understand one thing:

in Go, containers are not so much classes as language constructs.

The main differences:

  • slice replaces most use cases of ArrayList
  • map — built-in hash table
  • zero value reduces the number of errors
  • multiple slices can share the same memory
The most common mistake of novice Go developers is forgetting that a slice can share a backing array. This can lead to unexpected data changes.

Practical rule:

  • use slice instead of array
  • remember about append and capacity
  • use map for associative structures
  • remember that zero value is often already ready for use

When these principles become habitual, Go code starts to feel significantly easier than Java code with a lot of wrapper objects.


🌐 На русском
Total Likes:0

Оставить комментарий

My social media channel
By sending an email, you agree to the terms of the privacy policy

Useful Articles:

Modern architectural approaches: from monolith to event-driven systems
Introduction Architecture is more than just a way to arrange classes and modules. It is the language a system uses to communicate time. Today, Java developers live in a world where the boundaries bet...
Java v25: Choosing the Right Multithreading for Any Task
Introduction The Java world is rapidly evolving, and with each version, new tools are emerging for effectively working with multithreading, collections, and asynchrony. Java 25 brings powerful feature...
Data types in Java
Data Types in Java Hello! This is Vitaly Lesnykh. In this lesson of the "Java Basics for Beginners" course, we will discuss what data types are. Data types are the foundation of any programming langu...

New Articles:

Zero Allocation in Java: what it is and why it matters
Zero Allocation — is an approach to writing code in which no unnecessary objects are created in heap memory during runtime. The main idea: fewer objects → less GC → higher stability and performance. ...
Stream vs For in Java: how to write the fastest code possible
In Java, performance is often determined not by the "beauty of the code," but by how it interacts with memory, the JIT compiler, and CPU cache. Let s analyze why the usual for is often faster than Str...
Compiler, Build, and Tooling in Go and Java: how assembly, initialization, analysis, and diagnostics are organized in two ecosystems
This article is dedicated to a general overview of how the compiler, build, and tooling practices are arranged in Go, and how to better understand them through comparison with Java. We will not delve ...
Fullscreen image