Is there a class in java similar to StringBuilder with the only difference that it has a fixed length?

196 Views Asked by At

Something like this:

MyFixedLengthStringBuilder sb = new MyFixedLengthStringBuilder(2);
sb.append("123"); // <=== throws ArrayIndexOfOutBoundsException!

The rest would be exactly the same. Basically I need a StringBuilder that can never grow.

I see that StringBuilder is final so it can not be extended. Delegation sounds like my only path here. Do you see any other hack/idea/solution for my need?

3

There are 3 best solutions below

0
Lovesh Dongre On BEST ANSWER

If I could create my own class, it would go something like this and based on requirements more things could be added

public class MyFixedLengthStringBuilder {

    StringBuilder sb;
    int size;
    
    public MyFixedLengthStringBuilder(int size) {
        if(size < 0)
            throw new IllegalArgumentException();
        this.size = size;
        sb = new StringBuilder(size);
    }
    
    public void append(String str) {
        sb.append(str);
        if(sb.length() > size) {
            sb.setLength(size);
            throw new ArrayIndexOutOfBoundsException();
        }
    }
    
}
2
WJS On

You could so something like this. You would still have to have some overloaded methods to handle different argument counts and types but it wouldn't have to be a full delegation. This is just a simple example. It could be worked into a class. EDIT: Modified to handle most methods.

interface TriConsumer<T,R,S> {
      public void accept(T t, R r, S s);
}
public class StringBuilderSol {
    static int size = 20;
    static StringBuilder sb = new StringBuilder(size);
    
    
    public static void main(String[] args) {

        execute(sb::append, "This is fun!");
        System.out.println(sb);
        execute(sb::append, "Java!");
        System.out.println(sb);
        execute(sb::delete, 0,3);
        execute(sb::replace,0,1,"I");
        execute(sb::insert, 1, " like ");
        execute(sb::delete, 7,15);
        System.out.println(sb);
        execute(sb::append, "time to crash");
        
    }
    
    public static <T> void execute(Consumer<T> con,
            T v) {
        con.accept(v);
        checkLength();
    }
    
    public static <T,R> void execute(
            BiConsumer<T, R> biCon,
            T index, R val) {
        biCon.accept(index, val);
        checkLength();
    }

    public static <T,R,S> void execute(
            TriConsumer<T, R, S> triCon,
            T index, R arg1, S arg2) {
        triCon.accept(index, arg1, arg2);
        checkLength();
    }
    
    public static void checkLength() {
        if (sb.length() > size) {
            throw new IndexOutOfBoundsException();
        }
    }

}

Prints

This is fun!
This is fun!Java!
I like Java!
Exception in thread "main" java.lang.IndexOutOfBoundsException
    at stackOverflow.StringBuilderSol.checkLength(StringBuilderSol.java:50)
    at stackOverflow.StringBuilderSol.execute(StringBuilderSol.java:32)
    at stackOverflow.StringBuilderSol.main(StringBuilderSol.java:25)


Another option (but one that has its own problems) is to set up a timer to periodically check the size of the StringBuilder.

0
Izruo On

First of all, the customer requirement is insufficiently specified: Are they requesting a class that is assignment-compatible with StringBuilder or are they simply requesting a class with a specific functionality?

The former is technically impossible, since StringBuilder is declared as final, thus any variable of type StringBuilder will always have the same behavior.

The latter allows you to specify your own new class with your own methods. As for the requirement, the customer likely specified "I just need everything from StringBuilder.", because they didn't bother to actually check what they need precisely. I think it is quite likely that you will be able to craft a class with just a few methods fit for the customer's needs, if you both invest some work into narrowing down the requirement.

And yes, as you already mentioned, in this case it is a good idea to use a composition with the original StringBuilder class.


As you were asking for a hack, you could theoretically write your own implementation of java.lang.StringBuilder and provide a custom ClassLoader that loads your implementation instead of the standard java one. I hope it is obvious that this is not a good practice, though.