Cheok Yan Cheng
Cheok Yan Cheng

Reputation: 42730

Technique to runtime create constant which are memory efficient

Currently, I have the following design in my application, which is using enum as a memory efficient constant

public enum Board {
    Toronto    // Toronto stock Exchange
}

public class Stock {
    private final Board board;
    private final Code code;
    ....
}

This is a memory efficient way. As, if there is thousands of Stock in a stock exchange, only 1 instance of Board will be created.

Stock stock0 = new Stock(Code.newInstance("AAA.TO"), Board.Toronto);
Stock stock1 = new Stock(Code.newInstance("AAB.TO"), Board.Toronto);

However, this certainly has some shortcoming. From time-to-time, stock exchange will introduce new board. When such event occurs, I need to


public enum Board {
    Toronto,   // Toronto stock Exchange
    TSXV       // New Toronto venture
}

Stock stock0 = new Stock(Code.newInstance("AAA.TO"), Board.Toronto);
Stock stock1 = new Stock(Code.newInstance("AAB.TO"), Board.Toronto);
Stock stock2 = new Stock(Code.newInstance("TRU.V"), Board.TSXV);

I want to avoid such inconvenient. My initial plan is

public class Board {
    private final String board;
    private Board(String board) {
        this.board = board;
    }
    public Board newInstance(String board) {
        return new Board(board);
    }
}

However, this is not an memory efficient way. As, multiple instances of Board will be created.

// 2 Toronto board instance will be created! Not memory efficient when we have huge stock list.
Stock stock0 = new Stock(Code.newInstance("AAA.TO"), Board.newInstance("Toronto"));
Stock stock1 = new Stock(Code.newInstance("AAB.TO"), Board.newInstance("Toronto"));
Stock stock2 = new Stock(Code.newInstance("TRU.V"), Board.newInstance("TSXV"));

I was wondering, what kind of data structure I can apply, so that I can have a memory efficient way to represent constant (In my context, it means the Board class)

I prefer not to use String, as I prefer to have type safe, to differentiate among Board and real String.

Upvotes: 0

Views: 74

Answers (3)

Cheok Yan Cheng
Cheok Yan Cheng

Reputation: 42730

This a thread safe way for doing so. I'm not really sure whether such implementation can considered as Flyweight pattern. However, I had tried my best effort to ensure it is thread safe. If you found any possible fault, feel free to amend the code.

import java.util.concurrent.ConcurrentHashMap;

/**
 *
 * @author yccheok
 */
public class Board {
    private Board(String board) {
        this.board = board;
    }

    public static Board newInstance(String board) {
        if (board == null) {
            throw new java.lang.IllegalArgumentException("board cannot be null");
        }

        Board result = map.get(board);
        if (result == null) {
            final Board instance = new Board(board);
            result = map.putIfAbsent(board, instance);
            if (result == null) {
                return instance;
            }
        }

        assert(result != null);
        return result;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + board.hashCode();

        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        if (!(o instanceof Board)) {
            return false;
        }

        return this.board.equals(((Board)o).board);
    }

    @Override
    public String toString() {
        return board;
    }

    // Avoid using interface. We want it to be fast!
    private static final ConcurrentHashMap<String, Board> map = new ConcurrentHashMap<>();
    private final String board;
}

Upvotes: 1

Tien Nguyen
Tien Nguyen

Reputation: 4358

In my opinion, the best solution is to add Board to your database and you have to update your database when the business side raises a new board,your Board may changes day by day to adapt business requirements so it's not suitable for Constant or Enum

Upvotes: 0

lorraine batol
lorraine batol

Reputation: 6281

Hmm, how about storing the boards in a set or map? That way you can secure to only have one instance for each.

Pseudocode:

public class Board {
    private static final Set<Board> boards = new HashSet<>();

    public static Board getInstance(String board) {
        //search if board already exists on boards set, if it is, return that instance; else, add to list and return the newly created instance.
    }
    //override equals and hashCode appropriately
}

Upvotes: 2

Related Questions