I want to replace all occurences of a substring in a String.
But, if the substring is surrounded by double-quotes, I want to keep the substring.
Example:
the actual String: testing<SEP>testing2<SEP>"testing3<SEP>"<SEP>testing4

here I want to replace all occurences of <SEP> except for the one occurence found in the "testing3<SEP>" substring.

Additionally, I want to be able to use the exact phrase (in the example - <SEP>)
as the first argument in the replaceAll-method. Some characters in the substring might be 'special characters' - so I need to specify 'match exactly the substring' too.

Help much appreciated! (I can't figure it out despite extensive reading on regexps)

I think we need to back up a bit. As I read it, the requirement is to take a delimited string and replace any delimiters that aren't inside quotes. My solution just removes the delimiters, but after re-reading the original question, I see that isn't what was asked for. Also, the OP said he doesn't want to have to deal with special characters, which is why I quoted the delimiter with \Q and \E. (Try the other solutions with separators "(SEP)" or "{SEP}" to see what I mean.)

But the replacement string has special-character issues, too. That's because replaceAll() looks for group references like "$1" in the replacement string and substitutes them with whatever was matched by the corresponding groups in the regex. Also, as with the regex, backslashes are used for escaping, so if there are any dollar signs or backslashes in the replacement string you'll get unexpected results, if not errors. Adapting my original solution to allow for a "safe" replacement delimiter is trivial, if somewhat opaque:

The trick here lies in knowing that appendReplacement() does two things: it appends everything between the last match and the current one, then it processes the replacement string as described above and appends the result. Passing it an empty string prevents it from carrying out the second task. Then we append the new delimiter to the StringBuffer ourselves, bypassing the special processing it would otherwise have received.

If you use replaceAll(), as the other solutions here do, that trick isn't available; you just have to pre-process the strings to disable special-character processing. Since JDK 1.5, you can use the methods Pattern.quote() and Matcher.quoteReplacement() for that. But if you are running Java 5+, you can use the new replace(CharSequence, CharSequence) method instead of replaceAll(), and not have to worry about any of this special character stuff.

Additionally, I want to be able to use the exact phrase
(in the example - <SEP>) as the first argument in the
replaceAll-method. Some characters in the substring might
be 'special characters' - so I need to specify 'match
exactly the substring' too.

It follows that special characters should be disabled in the replacement string, too, but most people don't realize at first that there are any.

I just remembered another way to disable regex metacharacters in the search string:

You are so far ahead of me there that you lost me. I did not read all that into the post and still don't, but I am not going to argue with you, since it's clear - and has been clear for a long time - that you are the Regex man ;o)