tl;dr
map.get( i ) is incorrect. Your keys are Character objects, not the int i used in your loop.
Call Map#keySet, and loop those key objects rather than incrementing an int i. Replace your for (int i = 0; i < map.size(); i++){ with for ( Character key : map.keySet() )
Details
By the way, you use the word "compression" but what you are doing is not compression. You are counting total repetition of each character, rather than counting each series of a repeated character separately.
Your code for populating the map is correct. We can see that by doing a println to see the map’s contents. For input "aabccccaaa" we get this map: map.toString(): {a=5, b=1, c=4}.
The problem is where you build up text with StringBuilder. You call map.get( i ). This means you are asking for the value mapped to a key of 0, 1, 2, and such. But you are not using integer numbers as your key. You are using Character as your key type.
Instead, you should be looping on the set of all keys. Then do a get for each of those keys. Your StringBuilder code should look like this:
StringBuilder sb = new StringBuilder();
Set < Character > keys = map.keySet();
for ( Character key : keys )
{
Integer count = map.get( key );
sb.append( key ).append( count );
}
By the way, your insertions into the map could be made into a single line of call by using Map#merge method. So this:
if (map.containsKey(c)){
map.put(c, map.get(c) + 1);
}
else{
map.put(c, 1);
}
…becomes this:
map.merge( c , 1 , Integer :: sum );
The Integer :: sum is a method reference. A method reference is an object that represents that method rather than calls that method. The merge method will call that sum method while performing its work.
By the way, your line s = s.toLowerCase(); replaces the passed argument String object with a new String object. I do not recommend this. You have discarded the original text with nothing gained. You have tossed valuable information needed for debugging and logging. Instead, define a new String variable: String input = s.toLowerCase();. And to prevent such re-assignment of the argument variable, mark the argument declaration as final.
Complete code example:
package work.basil.example;
import java.util.HashMap;
import java.util.Set;
public class RepeatCounter
{
public static void main ( String[] args )
{
System.out.println( countCharacterOccurrence( "aabccccaaa" ) );
System.out.println( countCharacterOccurrence( "abc" ) );
System.out.println( countCharacterOccurrence( "AabBcCdDdDDeE" ) );
}
public static String countCharacterOccurrence ( final String s )
{
String input = s.toLowerCase();
HashMap < Character, Integer > map = new HashMap <>();
for ( int i = 0 ; i < input.length() ; i++ )
{
char c = input.charAt( i );
map.merge( c , 1 , Integer :: sum );
}
// System.out.println( "map = " + map );
StringBuilder sb = new StringBuilder();
Set < Character > keys = map.keySet();
for ( Character key : keys )
{
Integer count = map.get( key );
sb.append( key ).append( count );
}
return sb.toString();
}
}
When run.
a5b1c4
a1b1c1
a2b2c2d5e2
You may want to use another Map implementation rather than HashMap. The HashMap class makes no promise as to the iteration order of its keys.
If you want the keys kept in sorted order, use a SortedMap/NavigableMap implementation such as TreeMap.
If you want the keys kept in their original insertion order, use LinkedHashMap.
Here is a graphic table I made of the Map implementations bundled with Java.

By the way, the char/Character type in Java is obsolete, unable to represent even half of the 143,859 characters defined in Unicode.
While your code can handle an input of "Hello World", it will fail with an input of "Hello 👋 world 🗺️".
Learn to use integer code point numbers instead. So your Map would be a Map < Integer , Integer > where the first Integer represents the code point number of each character, and the second Integer is the count of its occurrences.
For more info, read: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!).