Hi all,
    I am a long‑term Java application developer. I would like to share my 
intuitive thinking about null design from a pure object‑oriented programming 
perspective.
    From my understanding of OOP, once a variable is declared as a certain 
type, it should always represent a valid instance of that type.
    However, in current Java, when I declare an object variable without 
immediately constructing a valid instance, it is assigned null by default. In 
my opinion, null does not belong to this type at all; it is an external state 
outside the entire object system. This is the root cause of 
NullPointerException and numerous redundant null checks, which goes against 
natural OOP intuition.
    Meanwhile, I really dislike nullable type syntax such as Type?. It 
artificially splits a single type into two contradictory states, which only 
confuses code logic and increases developers’ mental burden.
    My simple expectation for Java is as follows:
    Instead of assigning an irrelevant null to an uninitialized object field, 
the language should provide a built‑in none instance that strictly belongs to 
the target type.
    This none instance should satisfy the following conditions:1

  1.
It is exactly an instance of the type itself
  2.
It is a valid object so all methods can be called safely
  3.
It supports natural chaining and automatic short‑circuit when empty

    Such a design not only returns to the essence of OOP, but also fits 
naturally with current streaming and functional programming styles, resulting 
in cleaner and more consistent code.
    Here are practical examples from daily development to illustrate my idea 
clearly:
Current cumbersome Java code (null checks are mandatory to avoid NPE)

// Declared only, default value is null
User user;

// Direct call will throw NPE
String username = user.getName();

// Verbose defensive null check
String username = "";
if (user != null) {
    username = user.getName();
}

// Awkward Optional wrapping
Optional<User> optUser = Optional.ofNullable(user);
String username = optUser.map(User::getName).orElse("");
optUser.ifPresent(System.out::println);

// Return null when no matching data found
public User findUser(Long id) {
    return null;
}


My ideal natural style with built‑in none instance

// Uninitialized, default is the native none instance of User, not null
User user;

// Safe direct call with no exception
String username = user.getName();

// Native fluent chaining with automatic short‑circuit
String username = user.map(User::getName).orElse("");

// Execute logic only when a valid instance exists
user.ifPresent(System.out::println);

// Check for native none instance
if (user.isNone()) {
    // Business logic for uninitialized state
}

// Return type-owned none instance instead of null
public User findUser(Long id) {
    return User.None;
}


Confusing Type? design (type splitting leads to high mental load)

// One single type is split into User and User?
User? user = null;

// Constantly need to handle nullable differences
String username = user?.getName();

// Developers always struggle to judge whether it is a valid object
// Essentially still dealing with non‑object null state, not real OOP


    To sum up:
    In object‑oriented design, the empty state of a type should still be an 
instance of that type, rather than a meaningless null pointer or a confusing 
split‑type syntax.
    This is only my personal experience and intuitive design idea as an 
application developer. I do not discuss any underlying implementation details. 
I look forward to community discussion and feedback.
    Best regards
    A Java Backend Developer

Reply via email to