OOP Basics ·
‹ Previous Next ›
⏱ 5 min read Modified: 2026-07-24

Procedural vs Object-Oriented Programming

Java is an object-oriented language — but you can absolutely write procedural code in it, and most beginners do exactly that for their first few weeks. These are the two programming paradigms every Java developer meets first, and the difference between them is not syntax: it is what the program is built around — a sequence of actions, or the objects that perform them.

Is Java Procedural or Object-Oriented?

Java is an object-oriented programming language, not a procedural one. Every method must live inside a class, the whole standard library is built from classes and interfaces, and the language provides dedicated keywords for object-oriented design: class, interface, extends, implements, abstract.

The confusion comes from a real observation: the code inside main looks procedural, because it is. A class that only holds a static void main method is nothing but a container — the statements run top to bottom exactly like a C program. So the honest answer is: Java is an object-oriented language that lets you write procedural code, and it is your design, not the compiler, that decides which paradigm you actually use.

What Is Procedural Programming?

Procedural programming is a paradigm in which a program is described as a sequence of instructions executed from top to bottom, with the order changed by branching (if, switch) and loops (for, while). When the list of instructions grows, repeated fragments are extracted into subprograms — called procedures, functions or, in Java, methods.

Data lives separately from the code that uses it: there are variables on one side and methods that take them as parameters and return results on the other. Combine that with the rule "sequence, selection and iteration only, no goto" and you get what is known as structured programming.

Every program in this course up to this lesson has been written in a procedural style, even though the code physically sits inside a class.

The trouble starts as the program grows. With dozens of methods sharing hundreds of variables, any change to the shape of the data forces you to edit every method that touches it. Splitting the code into methods stops being enough.

Procedural Programming Languages

A procedural language is one whose basic building block is the procedure (function) rather than the object. The classic examples are:

  • C — the best-known procedural language, still used for systems programming and the Linux kernel;
  • Pascal — designed to teach structured programming;
  • Fortran — scientific and engineering computation;
  • COBOL — banking and accounting systems that are still in production today;
  • BASIC, Ada and Go (Go attaches methods to types but has no classes and no inheritance).

Keep in mind that labelling a language "procedural" or "object-oriented" is a simplification. Most modern languages are multi-paradigm: C++, Python, JavaScript and PHP happily support both styles. Java sits closest to the object-oriented end of the scale, yet writing procedural code in it takes no effort at all.

What Is Object-Oriented Programming?

Object-oriented programming (OOP) is a paradigm built around two ideas: the object and the class. Before writing instructions, you look at the problem and identify the entities involved, then describe them with classes. A class defines the characteristics of an object (its fields) and its behaviour (its methods). Data and the code that operates on that data end up in the same place.

An object is a concrete instance created from a class with new: the class Product is the blueprint, while coffee and tea are objects with their own field values.

A useful analogy: procedural programming is like putting up a garden shed — drawing full architectural plans would be a waste of time. OOP is like constructing an apartment block, where the structure is designed in detail before anyone pours concrete. That upfront design is what keeps a large system maintainable and its parts reusable.

Worth knowing

Java is not a “100 % object-oriented” language, whatever some tutorials claim. Primitive types (int, double, boolean) are not objects, and static members are called without creating an instance. That is precisely why code written inside main stays procedural. Languages such as Smalltalk or Ruby, where literally everything is an object, are closer to the “pure OOP” label.

One Task in Two Styles: a Java Example

Let's price a line in a shopping cart. First the procedural version: the data sits in local variables and the method receives it through parameters.

public class Main {

    public static void main(String[] args) {
        String name = "Coffee";
        double price = 12.0;
        int quantity = 3;

        System.out.println(name + ": " + total(price, quantity));
    }

    static double total(double price, int quantity) {
        return price * quantity;
    }
}

Now the same task in an object-oriented style. The data and the behaviour move into a Product class, and the price is hidden behind the private modifier.

public class Product {

    private final String name;
    private final double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public double total(int quantity) {
        return price * quantity;
    }

    public String getName() {
        return name;
    }
}
public class Main {

    public static void main(String[] args) {
        Product coffee = new Product("Coffee", 12.0);
        System.out.println(coffee.getName() + ": " + coffee.total(3));
    }
}

The output is identical, but in the second version the price cannot be corrupted from the outside, and the rule for calculating the total sits next to the data it uses. Adding a discount or a tax means editing one class instead of every place that performs the calculation.

The Four Principles of OOP

OOP in Java is usually explained through four principles: abstraction, encapsulation, inheritance and polymorphism (some sources drop abstraction, since it has no dedicated keyword, and list only three). A full breakdown of each principle with code examples and common interview questions lives in a dedicated lesson: Object-Oriented Programming (OOP) Concepts.

Aggregation and Composition

Inheritance is not the only way to connect classes. Far more often one object simply holds another — the "has-a" relationship, which comes in two flavours: composition (a strong link, where the inner object is created by its owner and cannot exist without it) and aggregation (a loose link, where the object receives a ready-made reference from outside and keeps living independently). A full breakdown with Java code examples lives in a dedicated lesson: Association, Aggregation, and Composition.

Procedural vs OOP: Side-by-Side Comparison

Criterion Procedural programming Object-oriented programming
Basic unit Procedure (method, function) Class and object
Data and behaviour Separate: data is passed into methods Bundled together inside a class
Access to data Usually open, easy to corrupt from outside Hidden by encapsulation (private plus methods)
Reuse Copying code or calling functions Inheritance, composition, interfaces
Changing requirements Edits spread across the whole program Changes stay local to a class
Learning curve Low; you see a result immediately Higher; design comes before code
Typical languages C, Pascal, Fortran, COBOL Java, C#, Kotlin, Smalltalk
Best suited for Scripts, calculations, learning exercises Large applications maintained for years

When Procedural Code Is Enough

OOP has clear advantages, but overusing it hurts. If the whole task fits into a dozen lines — compute a factorial, sort an array, parse a string — procedural code is the right answer. A class with no state and a single method is usually just an extra layer that buys you nothing.

The signals that it is time to introduce objects are easy to spot: several variables are always passed around together; the same set of data is processed in different parts of the program; you start seeing behaviour that varies by the type of entity. That is where class design begins.

Easy to get wrong

Having classes in your code does not make it object-oriented. If a class holds nothing but public fields and all the logic lives in one huge static method, that is a procedural program written with Java syntax. Such a data-only class is known as an anemic model.

Frequently Asked Questions

Is Java procedural or object-oriented?

Java is an object-oriented programming language, not a procedural one: every method must be declared inside a class, and the standard library is built from classes and interfaces. Java still lets you write procedural code — statements placed inside a static main method run top to bottom just like a C program — so the paradigm you actually use is decided by your design, not by the compiler.

Are there three or four OOP principles?

Both answers appear in the wild: the classic four are abstraction, encapsulation, inheritance and polymorphism, though some sources drop abstraction and list only three. See the full breakdown in Object-Oriented Programming (OOP) Concepts.

How is procedural programming different from functional programming?

Procedural code mutates state: variables and fields are overwritten as execution proceeds. Functional programming favours immutable data and side-effect-free functions, and treats functions as values you can pass around. Java supports functional techniques through lambda expressions and the Stream API, but the language itself remains object-oriented.

Should I use inheritance or composition?

Prefer composition by default: it is more flexible and does not couple classes as tightly as inheritance. See the full comparison of association, aggregation, and composition, with code examples, in Association, Aggregation, and Composition.

How do I refactor procedural code into object-oriented code?

Find the variables that are always passed together and group them into a class. Move the methods that took those variables into the same class and delete the parameters that are now redundant. Mark the fields private and expose only the methods the caller genuinely needs. By the end, main should shrink to a few lines that create objects and start the scenario.

Comments

Please log in or register to have a possibility to add comment.