Click here to Skip to main content
13,862,971 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

9.2K views
2 bookmarked
Posted 18 Nov 2013
Licenced CPOL

Simulating C# ref Parameter in Java

, 18 Nov 2013
Rate this:
Please Sign up or sign in to vote.
Simulating C# ref parameter in Java
As I was saying a few posts ago (Beginning Java for .NET Developers), on the 8th slide, there are no ref and no out method parameter modifiers.

These are rarely used in .NET anyway so you can’t really complain of their lack in Java. Furthermore, some of their legitimate uses, such as the static TryParse methods on value types are not applicable in Java. Why? Because in Java, the primitives (int, long, byte, etc. – the equivalent of the basic value types in .NET) are not part of the type hierarchy and they have reference-type wrappers (Integer, etc.) which would solve the issue of returning the result in case of ‘TryParse’ style of parsing. How’s that? It’s like:

public static Integer tryParseInt(String intString) {
    try {
        return Integer.parseInt(intString);
    } catch (NumberFormatException e) {
        return null;
    }
}

No need for an ‘out’ parameter or ‘ref’. But! Let’s try and simulate ‘ref’ using a generic class written this way:

public class Ref<T> {
    private T value;

    public Ref() {
    }

    public Ref(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return value == null ? null : value.toString();
    }
}

Now, suppose we have a class PhoneNumber that expects a number as [firstPart]-[secondPart] (both being integer, positive numbers). This class could look like:

public class PhoneNumber {

    private final int firstPart;
    private final int secondPart;

    private final static int NOT_FOUND = -1;

    public PhoneNumber(int firstPart, int secondPart) {
        this.firstPart = firstPart;
        this.secondPart = secondPart;
    }

    public int getFirstPart() {
        return firstPart;
    }

    public int getSecondPart() {
        return secondPart;
    }

    @Override
    public String toString() {
        return Integer.toString(firstPart) + "-" + Integer.toString(secondPart);
    }
}

We will also suppose that another allowed string representation of a phone number would be “private” (irrespective of the casing). We want to create a static tryParse method on that class. If the given string is not a valid phone number, we could return null. But in case of the “private” value, we would also be forced to return null. There would be an ambiguity. Therefore, we would need some kind of disambiguation. One way would be to use the Ref<t> class defined above like so:

public static boolean tryParse(String phoneNumberString, Ref<PhoneNumber> phoneNumber) {
    if (phoneNumberString == null || phoneNumberString.isEmpty()) return false;
    if (phoneNumber == null) throw new IllegalArgumentException();

    phoneNumber.setValue(null);
    if (phoneNumberString.toLowerCase().equals("private")) {
        return true;
    }
    int dashIndex = phoneNumberString.indexOf('-');
    if (dashIndex == NOT_FOUND || dashIndex == 0 || dashIndex == phoneNumberString.length() - 1) {
        return false;
    }

    String firstPartString = phoneNumberString.substring(0, dashIndex);
    String secondPartString = phoneNumberString.substring(dashIndex + 1, phoneNumberString.length());
    int firstPart;
    int secondPart;

    try {
        firstPart = Integer.parseInt(firstPartString);
        secondPart = Integer.parseInt(secondPartString);
    } catch (NumberFormatException e) {
        return false;
    }

    phoneNumber.setValue(new PhoneNumber(firstPart, secondPart));
    return true;
}

An example of using that code could be:

public static void main(String[] args) {
    String s1 = "555-1234";
    String s2 = "555";
    String s3 = "saldkfjasdf";
    String s4 = "PRIVATE";
    String s5 = "";
    String s6 = null;

    Ref<PhoneNumber> pn1 = new Ref<PhoneNumber>();
    Ref<PhoneNumber> pn2 = new Ref<PhoneNumber>();
    Ref<PhoneNumber> pn3 = new Ref<PhoneNumber>();
    Ref<PhoneNumber> pn4 = new Ref<PhoneNumber>();
    Ref<PhoneNumber> pn5 = new Ref<PhoneNumber>();
    Ref<PhoneNumber> pn6 = new Ref<PhoneNumber>();

    boolean b1 = PhoneNumber.tryParse(s1, pn1);
    boolean b2 = PhoneNumber.tryParse(s2, pn2);
    boolean b3 = PhoneNumber.tryParse(s3, pn3);
    boolean b4 = PhoneNumber.tryParse(s4, pn4);
    boolean b5 = PhoneNumber.tryParse(s5, pn5);
    boolean b6 = PhoneNumber.tryParse(s6, pn6);

    System.out.println("Parsing '" +
    s1 + "' : " + b1 + ", Ph# : " + pn1);
    System.out.println("Parsing '" +
    s2 + "' : " + b2 + ", Ph# : " + pn2);
    System.out.println("Parsing '" +
    s3 + "' : " + b3 + ", Ph# : " + pn3);
    System.out.println("Parsing '" +
    s4 + "' : " + b4 + ", Ph# : " + pn4);
    System.out.println("Parsing '" +
    s5 + "' : " + b5 + ", Ph# : " + pn5);
    System.out.println("Parsing '" +
    s6 + "' : " + b6 + ", Ph# : " + pn6);
}

Upon running this piece of code, we would receive:

Parsing '555-1234' : true, Ph# : 555-1234
Parsing '555' : false, Ph# : null
Parsing 'saldkfjasdf' : false, Ph# : null
Parsing 'PRIVATE' : true, Ph# : null
Parsing '' : false, Ph# : null
Parsing 'null' : false, Ph# : null

This way, we were able to simulate a ref parameter. However, some might argue that this is not the only solution and we could have defined another class called ParseResult<t> encapsulating a boolean representing the success of parsing and a T representing the parsed value (in case the parsing succeeded). Of course, we could do this, it would be a good alternative. However, for the C# / .NET developers, the Ref<t> would be closer to their existing knowledge.

Regarding the out parameter, things are not so bright. That’s because of two things: first, the called method should be enforced to set at least once a value to the out parameter on each execution path and in C#, this is enforced by the compiler while in Java, I see no way to enforce it. Second, the solution (if one would exist) should restrict the called method to only set the value but not read it while the method caller should be able to read and write.

In conclusion, at least we can simulate ref with Ref<t>. This pattern is also used in EventArgs and other derived classes, in .NET.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Andrei Ion Rînea
Software Developer (Senior) IBM, Business Analytics
Romania Romania
No Biography provided

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web06 | 2.8.190214.1 | Last Updated 18 Nov 2013
Article Copyright 2013 by Andrei Ion Rînea
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid