学习前提

理解Java基本类型、条件和循环;本课引入方法参数和数组契约。

本课完成后你能做什么

拆分可复用计算,理解参数和返回值。

先理解机制

方法签名声明参数类型和返回类型。将求和从main中提取后,可以用不同输入单独验证,而不用复制循环。方法应明确是否允许空数组、null和负值。

Java总是按值传递参数。数组参数传递的是引用的副本;通过它修改元素会影响调用者看到的同一个数组,但把参数重新赋值不等于替换调用者的变量。

本例sum只读取输入并返回long,避免修改数组。空数组的和定义为0;null被明确拒绝。这些边界属于接口约定,不应让调用者猜测。

可运行示例

使用JDK 21。将代码保存为Main.java,在独立练习目录执行 javac -encoding UTF-8 Main.java,再执行 java Main。每章独立运行,不把多个public Main类放进同一文件。


public class Main {
    static long sum(int[] values) {
        if (values == null) throw new IllegalArgumentException("values required");
        long total = 0;
        for (int value : values) total += value;
        return total;
    }
    public static void main(String[] args) {
        int[] minutes = {25, 30, 15};
        System.out.println(sum(minutes));
        System.out.println(sum(new int[0]));
        System.out.println(minutes[0]);
    }
}

推演与验证

输出70、0、25。第三行验证函数未改写第一个元素。

常见错误与边界

返回long不代表任意数量都不会溢出;它只是扩大范围。不要在求和函数中混入打印、读取输入等职责。

动手练习

编写countAtLeast(int[] values,int minimum),统计大于等于阈值的元素。

参考解法与理由

沿用null检查,计数从0开始,循环中if(value>=minimum)增加计数并返回。对{25,30,15}和阈值25结果为2;空数组为0。

深入实验:Java传值为什么仍能修改数组

“Java传引用”容易误导:参数得到的是引用值的副本。副本仍能指向调用者的数组,所以元素修改可见;把参数重新指向另一个数组却不会重绑调用者变量。保存为Main.java,使用JDK 21独立编译运行。

import java.util.Arrays;
public class Main {
    static void change(int[] values) {
        values[0] = 9;
        values = new int[]{100, 200};
        values[1] = 300;
    }
    public static void main(String[] args) {
        int[] original = {1, 2};
        change(original);
        System.out.println(Arrays.toString(original));
        int[] copy = Arrays.copyOf(original, original.length);
        copy[0] = 0;
        System.out.println(Arrays.toString(original));
        System.out.println(Arrays.toString(copy));
    }
}

预期观察

三行分别为[9, 2]、[9, 2]、[0, 2]。调用者没有得到[100, 300]。

原因、取舍与适用边界

第一次赋值通过共享引用改了同一个数组。第二次赋值只替换方法里的局部参数,调用者仍指向旧数组。对int[]复制后元素独立,但对对象数组仅复制引用;对象内部仍可能共享可变状态。编写API时应明确“会修改传入数据”还是“返回新值”;不要让调用者通过试错猜测副作用。

进阶练习

设计一个不修改原数组的doubleValues方法,处理空数组并说明null的约定。

解法与推理

先Objects.requireNonNull检查,再创建等长新数组并逐项使用Math.multiplyExact(value, 2)填入;空数组返回空数组。multiplyExact在溢出时报错,避免把大整数静默变成负数。方法文档应说明null和算术溢出都会失败。

进一步阅读