← Java tutorials

LESSON 24 / 40 · FREE TUTORIAL

Coordinates, Directions and Enums

Write the legal direction and coordinate rules into the type

90–110 minutesThis chapter uses JDK 21 and does not require the preview function.Face Object Progress

WHAT YOU WILL MAKE

Make block navigator BlockNavigator

If you spell the wrong direction once, the navigation may fail. enum circles the answer, record saves the coordinates as a value; movement returns the new position, and the boundaries are explicitly specified by you. Prerequisites: classes, constructors, methods and interfaces. Today I will install armor on the coordinates to prevent them from being changed by mistake, and I will also close the entrance that spells the wrong direction.

Before you start: It is recommended to complete Lessons 19, 21–23 first

Any text can be mixed into the direction variable
  1. stringPossible misspellings and inconsistent capitalization
  2. Enumeration typeDelineate legal constants
  3. nullStill need special treatment

01 / 12

Before starting: predict first, then let the program answer

This chapter uses JDK 21 and does not require the preview function. The story is borrowed from the block world, and the example runs on the ordinary Java console; if the values ​​​​and rules are course models, they will be clearly stated.

Each common example is a complete independent file, saved according to the file name marked on the box. Place each example in a different folder to avoid duplicate names of auxiliary classes. When the complete project is divided into sections, they are connected sequentially in the same file.

Terminal command: replace the Chinese placeholder with the actual file name and class name

javac -encoding UTF-8 ExampleFile.java
java ExampleClass
  • Prediction: Write the expected output first, or draw out the changes in references and data.
  • Verification: Check line by line after running, and then only change one condition.
  • Explanation: Explain whether the results come from Java rules, course contracts, or input data.

02 / 12

New varieties are easy to grow in the direction of the string

When using String to save directions, capitalization, spaces, and spelling may create illegal states. enum fixes the legal answers in a finite set.

Any text can be mixed into the direction variable
  1. stringPossible misspellings and inconsistent capitalization
  2. Enumeration typeDelineate legal constants
  3. nullStill need special treatment

L24Example01.java · Complete independent example

public class L24Example01 {
    public static void main(String[] args) {
        String facing = "dongg";
        System.out.println(facing);
        System.out.println(facing.equals("EAST"));
    }
}

Output

dongg
false

03 / 12

enum circles the legal direction

An enumeration is a type. Direction facing can only hold the value declared in Direction or null.

Enumeration variables can only select declared constants
  1. NORTH / SOUTHNorth-South axis
  2. EAST / WESTEast-West axis
  3. UP / DOWNHeight axis

L24Example02.java · Complete independent example

enum Direction {
    NORTH(0, 0, -1), SOUTH(0, 0, 1),
    EAST(1, 0, 0), WEST(-1, 0, 0),
    UP(0, 1, 0), DOWN(0, -1, 0);
    final int dx, dy, dz;
    Direction(int dx, int dy, int dz) {
        this.dx = dx; this.dy = dy; this.dz = dz;
    }
}
public class L24Example02 {
    public static void main(String[] args) {
        Direction facing = Direction.EAST;
        System.out.println(facing);
        System.out.println(Direction.values().length);
    }
}

Output

EAST
6

BadDirection.java · Intentional error example

enum Direction {
    NORTH(0, 0, -1), SOUTH(0, 0, 1),
    EAST(1, 0, 0), WEST(-1, 0, 0),
    UP(0, 1, 0), DOWN(0, -1, 0);
    final int dx, dy, dz;
    Direction(int dx, int dy, int dz) {
        this.dx = dx; this.dy = dy; this.dz = dz;
    }
}
public class BadDirection {
    public static void main(String[] args) { Direction d = Direction.DONGG; }
}

04 / 12

switch covers the direction branch

switch directly matches enumeration constants, does not require equals, and will not be affected by spelling strings.

Enumeration switch no longer compares strings
  1. switchCovering all six directions
  2. null checkEnter pre-branch processing
  3. Branch resultsReturn the corresponding Chinese name

L24Example03.java · Complete independent example

enum Direction {
    NORTH(0, 0, -1), SOUTH(0, 0, 1),
    EAST(1, 0, 0), WEST(-1, 0, 0),
    UP(0, 1, 0), DOWN(0, -1, 0);
    final int dx, dy, dz;
    Direction(int dx, int dy, int dz) {
        this.dx = dx; this.dy = dy; this.dz = dz;
    }
}
public class L24Example03 {
    static String label(Direction d) {
        if (d == null) return "Not selected";
        return switch (d) {
            case NORTH -> "North"; case SOUTH -> "South";
            case EAST -> "East"; case WEST -> "West";
            case UP -> "on"; case DOWN -> "Next";
        };
    }
    public static void main(String[] args) {
        System.out.println(label(Direction.NORTH));
        System.out.println(label(null));
    }
}

Output

North
Not selected

05 / 12

Enumeration to save displacement data

Enumerations can have fields and constructors. Each direction constant saves its own three-axis increment when created.

Six directions and three-axis displacement
Directiondxdydz
NORTH00-1
SOUTH001
EAST100
WEST-100
UP010
DOWN0-10

L24Example04.java · Complete independent example

enum Direction {
    NORTH(0, 0, -1), SOUTH(0, 0, 1),
    EAST(1, 0, 0), WEST(-1, 0, 0),
    UP(0, 1, 0), DOWN(0, -1, 0);
    final int dx, dy, dz;
    Direction(int dx, int dy, int dz) {
        this.dx = dx; this.dy = dy; this.dz = dz;
    }
}
public class L24Example04 {
    public static void main(String[] args) {
        Direction d = Direction.NORTH;
        System.out.println(d.dx + "," + d.dy + "," + d.dz);
    }
}

Output

0,0,-1

06 / 12

record install three-dimensional coordinates

Coordinates mainly carry three values and are compared by content. record will generate component accessors and equality methods; it is suitable for expressing immutable coordinates when components are immutable values ​​such as int.

One line declaration generates constructor accessor and comparison method
  1. record componentSave x, y, z
  2. x() / y() / z()Automatic accessor
  3. equalsComparison by component content

L24Example05.java · Complete independent example

record BlockPos(int x, int y, int z) { }
public class L24Example05 {
    public static void main(String[] args) {
        BlockPos p = new BlockPos(0, 64, 0);
        System.out.println(p.x());
        System.out.println(p.y());
        System.out.println(p.z());
    }
}

Output

0
64
0

07 / 12

Move and return to new coordinates

The record component cannot be reassigned at will. The move method calculates and returns a new BlockPos based on the old value.

The old position remains unchanged and the new position expresses the result.
  1. startThe old coordinates remain unchanged
  2. moveCalculate increment by direction
  3. nextReceive new coordinate object

L24Example06.java · Complete independent example

enum Direction {
    NORTH(0, 0, -1), SOUTH(0, 0, 1),
    EAST(1, 0, 0), WEST(-1, 0, 0),
    UP(0, 1, 0), DOWN(0, -1, 0);
    final int dx, dy, dz;
    Direction(int dx, int dy, int dz) {
        this.dx = dx; this.dy = dy; this.dz = dz;
    }
}
record BlockPos(int x, int y, int z) {
    BlockPos {
        if (y < -64 || y > 319)
            throw new IllegalArgumentException("The height should be-64 to 319");
    }
    BlockPos move(Direction direction, int steps) {
        if (direction == null || steps < 0) return this;
        long nx = (long) x + (long) direction.dx * steps;
        long ny = (long) y + (long) direction.dy * steps;
        long nz = (long) z + (long) direction.dz * steps;
        int nextY = (int) Math.max(-64L, Math.min(319L, ny));
        return new BlockPos(Math.toIntExact(nx), nextY,
                            Math.toIntExact(nz));
    }
    String shortText() { return "(" + x + "," + y + "," + z + ")"; }
}
public class L24Example06 {
    public static void main(String[] args) {
        BlockPos start = new BlockPos(0, 64, 0);
        BlockPos next = start.move(Direction.EAST, 5);
        System.out.println(start.shortText());
        System.out.println(next.shortText());
    }
}

Output

(0,64,0)
(5,64,0)

08 / 12

Equality and Boundaries of Value Objects

record solves the storage and comparison of values, but does not automatically know the legal height or movement rules in a Minecraft class.

Records with the same content automatically equals
  1. ==Comparison object identity
  2. equalsCompare component contents
  3. Height rangeThe lowest is -64, the highest is 319

L24Example07.java · Complete independent example

enum Direction {
    NORTH(0, 0, -1), SOUTH(0, 0, 1),
    EAST(1, 0, 0), WEST(-1, 0, 0),
    UP(0, 1, 0), DOWN(0, -1, 0);
    final int dx, dy, dz;
    Direction(int dx, int dy, int dz) {
        this.dx = dx; this.dy = dy; this.dz = dz;
    }
}
record BlockPos(int x, int y, int z) {
    BlockPos {
        if (y < -64 || y > 319)
            throw new IllegalArgumentException("The height should be-64 to 319");
    }
    BlockPos move(Direction direction, int steps) {
        if (direction == null || steps < 0) return this;
        long nx = (long) x + (long) direction.dx * steps;
        long ny = (long) y + (long) direction.dy * steps;
        long nz = (long) z + (long) direction.dz * steps;
        int nextY = (int) Math.max(-64L, Math.min(319L, ny));
        return new BlockPos(Math.toIntExact(nx), nextY,
                            Math.toIntExact(nz));
    }
    String shortText() { return "(" + x + "," + y + "," + z + ")"; }
}
public class L24Example07 {
    public static void main(String[] args) {
        BlockPos a = new BlockPos(0, 319, 0);
        BlockPos b = new BlockPos(0, 319, 0);
        System.out.println(a == b);
        System.out.println(a.equals(b));
        System.out.println(a.move(Direction.UP, 1).shortText());
        System.out.println(a.move(Direction.DOWN, 1000).shortText());
    }
}

Output

false
true
(0,319,0)
(0,-64,0)

09 / 12

Challenge Blueprint Block Navigator

The challenge program is called BlockNavigator. Direction saves the three-axis displacement, and BlockPos provides move and shortText.

The direction carries the displacement and the coordinate returns to the new value
  1. Direction and number of stepsSelected Axis of Change
  2. High clampingStop within range beyond boundary
  3. Return new valueThe starting point can still be played back

Acceptance sequence

  • From (0,64,0), go 5 blocks east, 300 blocks up, and 2 blocks north.
  • After height clamping, the end point should be (5,319,-2).
  • 1000 blocks down, the result should be (5,-64,-2).
  • The starting point remains (0,64,0).
  • Negative steps and null direction return to the original position; equals for two objects with the same coordinate is true.

10 / 12

Challenge Implementing Block Navigation

Create a new BlockNavigator.java and compile it using Java 21.

enum and record form an immutable path system
  1. Start0、64、0
  2. End point5、319、-2
  3. Bottom5、-64、-2

BlockNavigator.java · Section 1/2, sequentially connected to the same file

enum Direction {
    NORTH(0, 0, -1), SOUTH(0, 0, 1),
    EAST(1, 0, 0), WEST(-1, 0, 0),
    UP(0, 1, 0), DOWN(0, -1, 0);
    final int dx, dy, dz;
    Direction(int dx, int dy, int dz) {
        this.dx = dx; this.dy = dy; this.dz = dz;
    }
}
record BlockPos(int x, int y, int z) {
    BlockPos {
        if (y < -64 || y > 319)
            throw new IllegalArgumentException("The height should be-64 to 319");
    }
    BlockPos move(Direction direction, int steps) {
        if (direction == null || steps < 0) return this;
        long nx = (long) x + (long) direction.dx * steps;
        long ny = (long) y + (long) direction.dy * steps;
        long nz = (long) z + (long) direction.dz * steps;
        int nextY = (int) Math.max(-64L, Math.min(319L, ny));
        return new BlockPos(Math.toIntExact(nx), nextY,
                            Math.toIntExact(nz));
    }
    String shortText() { return "(" + x + "," + y + "," + z + ")"; }
}
public class BlockNavigator {
    public static void main(String[] args) {
        BlockPos start = new BlockPos(0, 64, 0);

BlockNavigator.java · Paragraph 2/2, sequentially connected to the same file

        BlockPos next = start.move(Direction.EAST, 5)
            .move(Direction.UP, 300).move(Direction.NORTH, 2);
        System.out.println("Start=" + start.shortText());
        System.out.println("End point=" + next.shortText());
        System.out.println("Bottom=" + next.move(Direction.DOWN, 1000).shortText());
        System.out.println("The content is the same=" + start.equals(new BlockPos(0, 64, 0)));
    }
}

Output

Start=(0,64,0)
End point=(5,319,-2)
Bottom=(5,-64,-2)
The content is the same=true

11 / 12

Expansion tasks and clearance review

The job must submit at least four boundary tests at the same time, and indicate whether the old objects have changed.

Third-level task expansion immutable map
  1. Boundary casesTop, bottom and adjacent values
  2. Illegal inputNegative number of steps, empty direction
  3. Object inspectionWhether the old value is maintained

Third gear operation

  • Wooden Pickaxe: Create a Difficulty enum and switch to return EASY NORMAL HARD's monster multiplier.
  • Iron pickaxe: Add dx dy dz to Direction to complete movement in six directions.
  • Diamond Pickaxe: Design TeleportPoint record, save name and coordinates, and return the new teleport point after offset.
Acceptance comparison table
Self-evaluationCanStill need to practice
I will declare enum□□
I would use record□□
I understand immutable data□□

12 / 12

Own acceptance record

Beautiful output is the starting point, and being able to explain boundaries is considered mastery. Select one case each from normal, borderline and error, write down your expectations before running, and leave evidence after running.

Leave a basis for judgment
CategoryThe operation you selectedCheck key points
NormalA common input or a successful actionIs the result consistent line by line?
BorderRange endpoints and adjacent valuesIs there one more step or one less thing?
ErrorIllegal quantity, missing object or bad dataWhether it is explicitly rejected and whether the status is maintained
  • Bug records: triggering conditions, actual phenomena, causes, and minimum repairs.
  • Illustrated record: describe the starting point, end point and meaning of each arrow.
  • Adaptation record: only change one rule, and modify expectations and tests at the same time.

TAKE IT WITH YOU

Take the lesson offline

The complete lesson, code, diagrams and exercises, in your preferred language.