Java Parameters

Su Suriya Ravichandran Updated 14 Nov 2026
7 min read ·Lesson 25 of 133

Parameters are the inputs a method declares. They let one method work with different data each time it is called: a calculateTax method computes tax for whatever amount it receives, rather than for one hard-coded number. Understanding exactly how Java passes values into parameters explains why some changes inside a method are visible to the caller and others are not.

Declaring Parameters

Parameters are listed in the parentheses after the method name, each with a type and a name, separated by commas:

static void printReceipt(String customer, double amount, boolean paid) {
    System.out.println("Customer: " + customer);
    System.out.printf("Amount:   %.2f%n", amount);
    System.out.println("Status:   " + (paid ? "Paid" : "Due"));
}
printReceipt("Ada", 1499.50, true);

Output:

Customer: Ada
Amount:   1499.50
Status:   Paid

Inside the method, each parameter behaves like a local variable that has already been assigned the corresponding argument. It exists only while the method runs.

Parameters Versus Arguments

TermWhere it appearsExample
ParameterThe method declarationString customer
ArgumentThe method call"Ada"

Arguments are matched to parameters by position, not by name. Java has no named arguments.

static double rectangleArea(double width, double height) {
    return width * height;
}

double height = 3, width = 10;
rectangleArea(height, width);   // width parameter receives 3, height receives 10

The variable names at the call site are irrelevant; only the order counts. For multiplication the mix-up is harmless, but with transfer(fromAccount, toAccount, amount) swapping the first two would move money the wrong way. Methods with several parameters of the same type deserve careful naming and, when the list grows long, a parameter object (covered below).

Type Checking and Conversion

Each argument must be assignable to its parameter's type. Widening conversions happen automatically; narrowing ones do not:

static void show(double value) { System.out.println(value); }

show(5);        // int widens to double: prints 5.0
show(5L);       // long widens to double

static void count(int n) { System.out.println(n); }

count(5.0);     // compile error: double cannot be narrowed to int
count((int) 5.9); // explicit cast: prints 5

The compiler also checks the number of arguments. Calling a method with too few or too many is a compile error unless the method uses varargs.

Pass-by-Value

Java passes every argument by value: the parameter receives a copy of the argument's value. What that copy contains depends on whether the type is a primitive or a reference.

Primitives: the method gets a copy of the number

static void addTen(int x) {
    x = x + 10;
    System.out.println("Inside: " + x);
}

int score = 50;
addTen(score);
System.out.println("Outside: " + score);

Output:

Inside: 60
Outside: 50

x is a separate variable holding a copy of 50. Changing x has no effect on score. To get a changed value back, the method must return it: score = addTen(score); with addTen returning x + 10.

References: the method gets a copy of the reference

For objects and arrays, the value copied is the reference, the address of the object. Caller and method now hold two references to the same object.

static void applyBonus(int[] salaries) {
    for (int i = 0; i < salaries.length; i++) {
        salaries[i] += 1000;
    }
}

int[] team = {30000, 42000};
applyBonus(team);
System.out.println(Arrays.toString(team));   // [31000, 43000]

The method modified the array through its copy of the reference, and the caller sees the change because there is only one array.

Reassigning a reference parameter does not affect the caller

static void replace(int[] salaries) {
    salaries = new int[]{0, 0};   // the local copy now points to a new array
    salaries[0] = 99;             // changes the new array only
}

int[] team = {30000, 42000};
replace(team);
System.out.println(Arrays.toString(team));   // [30000, 42000]

Assigning a new object to the parameter only redirects the method's copy. The caller's team variable still points to the original array.

Inside the methodAffects the caller?
Reassign a primitive parameterNo
Reassign a reference parameter (p = new ...)No
Modify the object through a reference (p.setX(), arr[i] = ...)Yes

Immutable objects behave like primitives

String, Integer, LocalDate, and other immutable types have no methods that modify the object. Every "change" creates a new object, which is a reassignment:

static void shout(String s) {
    s = s.toUpperCase();      // new String assigned to local s
}

String msg = "hello";
shout(msg);
System.out.println(msg);      // hello

The method must return the new string for the caller to receive it.

final Parameters

Marking a parameter final prevents the method from reassigning it:

static double net(final double gross, final double taxRate) {
    gross = gross * 0.9;          // compile error: cannot assign a final parameter
    return gross * (1 - taxRate);
}

This guarantees the parameter holds the original argument throughout the method, which helps when reading long methods. It does not make a referenced object immutable; final List<String> items can still have elements added.

Variable Arguments (Varargs)

A method can accept any number of arguments of one type by placing ... after the type of its last parameter:

static int sum(int... numbers) {
    int total = 0;
    for (int n : numbers) {
        total += n;
    }
    return total;
}

System.out.println(sum());              // 0
System.out.println(sum(5));             // 5
System.out.println(sum(1, 2, 3, 4));    // 10
System.out.println(sum(new int[]{7, 8})); // 15

Inside the method, numbers is an ordinary int[]. The compiler packs the arguments into an array automatically. Rules:

  • Only one varargs parameter per method, and it must be the last.
  • Calling with no arguments gives an empty array, not null.
  • An existing array can be passed directly.
static String join(String separator, String... parts) {
    return String.join(separator, parts);
}

join(", ", "red", "green", "blue");   // "red, green, blue"

String.format, System.out.printf, List.of, and Arrays.asList all use varargs.

Many Parameters: Use a Parameter Object

Methods with long parameter lists are hard to call correctly:

createUser("Ada", "Lovelace", "ada@example.com", "+91-9000000000", 36, true, false);

Which boolean means what? Grouping related values into a record makes calls self-explanatory and type-checked:

record UserInfo(String firstName, String lastName, String email,
                String phone, int age) {}

static void createUser(UserInfo info, boolean sendWelcome) { ... }

createUser(new UserInfo("Ada", "Lovelace", "ada@example.com", "+91-9000000000", 36), true);

Adding a field later changes the record, not every method signature and call site.

Validating Parameters

A method should reject arguments it cannot handle, at the start, before doing any work:

static double withdraw(double balance, double amount) {
    if (amount <= 0) {
        throw new IllegalArgumentException("Amount must be positive: " + amount);
    }
    if (amount > balance) {
        throw new IllegalArgumentException("Insufficient balance");
    }
    return balance - amount;
}

For reference parameters that must not be null, Objects.requireNonNull throws a clear exception at the boundary instead of a confusing one deep inside the method:

import java.util.Objects;

static void register(String email) {
    Objects.requireNonNull(email, "email must not be null");
    ...
}

Practical Example: Discount Engine

import java.util.Arrays;

public class Discounts {
    static double finalPrice(double price, double percentOff, double maxDiscount) {
        if (price < 0 || percentOff < 0 || percentOff > 100) {
            throw new IllegalArgumentException("Invalid price or percentage");
        }
        double discount = Math.min(price * percentOff / 100, maxDiscount);
        return price - discount;
    }

    static void applyToAll(double[] prices, double percentOff, double maxDiscount) {
        for (int i = 0; i < prices.length; i++) {
            prices[i] = finalPrice(prices[i], percentOff, maxDiscount);
        }
    }

    public static void main(String[] args) {
        double single = 2000;
        double discounted = finalPrice(single, 20, 300);
        System.out.println(single + " -> " + discounted);   // 2000.0 -> 1700.0

        double[] cart = {500, 1200, 4000};
        applyToAll(cart, 15, 400);
        System.out.println(Arrays.toString(cart));          // [425.0, 1020.0, 3600.0]
    }
}

finalPrice takes primitives, so it cannot alter the caller's single; it returns the new price instead. applyToAll receives a reference to the caller's array and updates it in place, which is why cart changes after the call. Both methods validate or delegate validation before computing. The cap parameter (maxDiscount) shows why parameters make a method reusable: the same logic supports a 20% sale capped at 300 and a 15% sale capped at 400 without any changes to the method.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Java Parameters and get answers drawn from it.

Signed-in readers only.