There is a Java Regex question: Given a string, if the \"*\" is at the start or the end of the string, keep it, otherwise, remove it. For example:
*
Others have given very good answers so I won't repeat them. A suggestion when you are working to understand issues such as this is to temporarily add delimiters to the replacement string so that it is clear what is happening at each stage.
e.g. use "<$1|$2>" This will give results of where x is $1 and y is $2
String str = "*ab**c*d*";
str.replaceAll("(^\\*)|(\\*$)|\\*", "<$1|$2>");
The result is: <*|>ab<|><|>c<|>d<|*>
So for the first asterisk, $1 = * and $2 is empty because (^\\*) matches.
For mid-string asterisks, both $1 and $2 are empty because neither capturing group matches.
For the final asterisk, $1 is empty and $2 is * because (^\\*) does not match but (\\*$) does.