When your game has a map which is too large to fit into memory, then the default solution to the problem is to use chunks.
Divide your map into rectangular chunks which are about as large as the screen. Only load the chunk the player is in and the adjacent chunks into memory. When the player moves to a different chunk, persist the no longer needed chunks to the hard drive and unload them (which you do in Java by making sure that there are no variables anymore which point to them). When the player returns, load the chunks from the hard drive back into memory.
When your map is randomly-generated, then you can use the fact that the Java
Random class can be initialized with a seed value. When you call
new Random(seed) with the same seed, you get the same sequence of random numbers from it. So when you use a new Random object for each chunk you generate, then all you need to save about a chunk is the seed value and any changes to the chunk which happened over the course of the game.