Todas as respostas fornecidas anteriormente usam a mesma técnica (correta) para usar um lookahead separado para cada requisito. Mas eles contêm algumas ineficiências e um bug potencialmente enorme, dependendo do back-end que realmente usará a senha.
Vou começar com a regex da resposta aceita:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
Em primeiro lugar, uma vez que o Java suporta \Ae \zeu prefiro usá-los para garantir que toda a string seja validada, independentemente de Pattern.MULTILINE. Isso não afeta o desempenho, mas evita erros quando os regexes são reciclados.
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
Verificar se a senha não contém espaços em branco e verificar seu comprimento mínimo pode ser feito em uma única passagem usando o all de uma vez, colocando o quantificador de variável {8,}na abreviação \Sque limita os caracteres permitidos:
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
Se a senha fornecida contiver um espaço, todas as verificações serão feitas, apenas para que a verificação final falhe no espaço. Isso pode ser evitado substituindo todos os pontos por \S:
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
O ponto só deve ser usado se você realmente quiser permitir qualquer caractere. Caso contrário, use uma classe de caracteres (negada) para limitar sua regex apenas aos caracteres que são realmente permitidos. Embora faça pouca diferença neste caso, não usar o ponto quando algo mais for mais apropriado é um hábito muito bom. Vejo muitos casos de retrocesso catastrófico porque o desenvolvedor estava com preguiça de usar algo mais apropriado do que o ponto.
Como há uma boa chance de os testes iniciais encontrarem um caractere apropriado na primeira metade da senha, um quantificador lento pode ser mais eficiente:
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
Mas agora a questão realmente importante: nenhuma das respostas menciona o fato de que a pergunta original parece ter sido escrita por alguém que pensa em ASCII. Mas em Java, as strings são Unicode. Os caracteres não ASCII são permitidos nas senhas? Em caso afirmativo, apenas espaços ASCII não são permitidos ou todos os espaços em branco Unicode devem ser excluídos.
Por padrão, \scorresponde apenas a espaços em branco ASCII, portanto, seu inverso \Scorresponde a todos os caracteres Unicode (espaços em branco ou não) e todos os caracteres ASCII que não sejam de espaços em branco. Se os caracteres Unicode forem permitidos, mas os espaços Unicode não, o UNICODE_CHARACTER_CLASSsinalizador pode ser especificado para \Sexcluir os espaços em branco Unicode. Se os caracteres Unicode não forem permitidos, eles [\x21-\x7E]podem ser usados em vez de \Spara corresponder a todos os caracteres ASCII que não sejam um espaço ou um caractere de controle.
O que nos leva ao próximo problema potencial: queremos permitir personagens de controle? A primeira etapa para escrever uma regex adequada é especificar exatamente o que você deseja corresponder e o que não. A única resposta 100% tecnicamente correta é que a especificação da senha na pergunta é ambígua, porque não indica se determinados intervalos de caracteres, como caracteres de controle ou caracteres não ASCII, são permitidos ou não.