You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中消除fillRect方法重复代码的最优方案咨询

解决Java中边界校验重复代码的几种实用方案

看了你写的两个fillRect方法,确实有大量重复的边界校验逻辑,Java没有指针确实会让这类需要同时修改多个变量的场景有点棘手,但其实有几种既简洁又低开销的方案可以解决这个问题:

方案1:使用Java 16+的Record类(推荐)

Java 16引入的Record是专门用来承载不可变数据的轻量级类型,完全不用担心内存或CPU开销——JVM会对它做充分优化,而且代码可读性极强。

首先定义一个用于存储调整后坐标和尺寸的Record:

private record BoundaryAdjustment(int coord, int size) {}

然后把重复的边界校验逻辑提取到一个私有方法里,返回这个Record:

private BoundaryAdjustment validateBoundary(int initialCoord, int initialSize, int maxDimension) {
    int coord = initialCoord;
    int size = initialSize;

    // 你的边界校验逻辑
    if (coord + size > maxDimension) {
        size -= coord + size - maxDimension;
    }
    if (coord < 0) {
        size += coord;
        coord = 0;
    }

    return new BoundaryAdjustment(coord, size);
}

接下来改造你的fillRect方法,调用这个校验方法即可:

public void fillRect(float x, float y, float width, float height, Color color) {
    BoundaryAdjustment horizontal = validateBoundary(mapX(x), mapWidth(width), pixelWidth);
    BoundaryAdjustment vertical = validateBoundary(mapY(y), mapHeight(height), pixelHeight);

    int xi = horizontal.coord();
    int widthf = horizontal.size();
    int yi = vertical.coord();
    int heightf = vertical.size();

    for (int xx = xi; xx < xi + widthf; xx++){
        for (int yy = yi; yy < yi + heightf; yy++){
            setPixel(xx, yy, color);
        }
    }
}

public void fillRect(float x, float y, float width, float height, float transparency, Color color) {
    BoundaryAdjustment horizontal = validateBoundary(mapX(x), mapWidth(width), pixelWidth);
    BoundaryAdjustment vertical = validateBoundary(mapY(y), mapHeight(height), pixelHeight);

    int xi = horizontal.coord();
    int widthf = horizontal.size();
    int yi = vertical.coord();
    int heightf = vertical.size();

    for (int xx = xi; xx < xi + widthf; xx++){
        for (int yy = yi; yy < yi + heightf; yy++) {
            plot(xx, yy, transparency, color);
        }
    }
}

这种方式既消除了重复代码,又保持了代码的清晰性,而且Record的开销几乎可以忽略——比起你循环中大量的像素操作,这点成本完全不值一提。

方案2:用数组作为“可变容器”(兼容旧Java版本)

如果你的项目还在用Java 16之前的版本,可以用长度为1的int数组来模拟“可变引用”,因为数组是引用类型,方法内部修改数组元素会影响外部。

先写校验方法:

private void validateBoundary(int[] coordRef, int[] sizeRef, int maxDimension) {
    int coord = coordRef[0];
    int size = sizeRef[0];

    // 边界校验逻辑
    if (coord + size > maxDimension) {
        size -= coord + size - maxDimension;
    }
    if (coord < 0) {
        size += coord;
        coord = 0;
    }

    // 把修改后的值写回数组
    coordRef[0] = coord;
    sizeRef[0] = size;
}

调用的时候:

public void fillRect(float x, float y, float width, float height, Color color) {
    int[] xiRef = {mapX(x)};
    int[] widthfRef = {mapWidth(width)};
    int[] yiRef = {mapY(y)};
    int[] heightfRef = {mapHeight(height)};

    validateBoundary(xiRef, widthfRef, pixelWidth);
    validateBoundary(yiRef, heightfRef, pixelHeight);

    int xi = xiRef[0];
    int widthf = widthfRef[0];
    int yi = yiRef[0];
    int heightf = heightfRef[0];

    // 后续循环逻辑不变...
}

这种方式的开销比Record还小,唯一的缺点是可读性稍差,因为数组元素的含义需要靠注释或变量名来明确,但对于简单场景完全够用。

方案3:自定义轻量内部类(兼容旧版本,可读性更好)

如果觉得数组不够直观,可以写一个极简的内部类来承载结果,比如:

private static class BoundaryResult {
    public int coord;
    public int size;

    public BoundaryResult(int coord, int size) {
        this.coord = coord;
        this.size = size;
    }
}

然后校验方法返回这个类的实例,用法和Record几乎一样,只是需要自己写类的代码。这种方式的开销也非常小,JVM会对这类小类做优化,不用担心性能问题。

为什么不用POJO?

其实你担心的POJO开销是多余的——对于这种只承载两个int值的小对象,JVM会用逃逸分析把它分配在栈上(而不是堆),甚至可能直接把对象拆解成单独的变量,完全不会有额外的内存或性能负担。而且Record本质上就是一种特殊的POJO,只是Java帮你自动生成了构造方法、equals、hashCode等方法而已。

总结一下,优先推荐用Record(Java 16+),兼顾可读性和性能;如果是旧版本,用内部类或数组都可以,根据团队的代码风格选择就行。

内容的提问来源于stack exchange,提问作者Meeresgott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:17:53