Comment convertir une trace de pile en chaîne?

1502

Quelle est la façon la plus simple de convertir le résultat de Throwable.getStackTrace()en une chaîne qui représente le stacktrace?

ripper234
la source
6
Parce que la réponse de jqno utilise en fait la méthode Throwable.getStackTrace () que vous avez spécifiée dans votre question, contrairement à Brian. Il utilise à la place Throwable.printStackTrace ().
Stijn de Witt
10
Presque tous les projets Java devraient inclure Apache commons-lang. Il comprend de nombreuses méthodes pratiques mettant en œuvre des besoins de développement extrêmement courants.
Russell Silva
20
@StijndeWitt Ces trois lignes de code ont presque certainement besoin d'être factorisées hors de l'endroit où vous les avez appelées. Comme vous ne savez pas où les mettre, ils iront dans votre boîte à outils utilitaire avec tous les autres extraits utiles. Bingo! vous venez de réinventer goyave / commons-lang / peu importe ... mais pas si bien. Importez plutôt une bibliothèque d'utilitaires judicieux et économisez en réinventant la roue. Le vrai signe d'un novice est de penser que vous pouvez faire un meilleur travail que les écrivains de la bibliothèque.
Andrew Spencer
6
1. Guava has - Throwables.getStackTraceAsString (e) 2. Apache Commons Lang - ExceptionUtils.getFullStackTrace 3. Écrivez nos propres méthodes personnalisées
user2323036
8
@AndrewSpencer Je ne comprends pas pourquoi vous essayez si durement de critiquer StijndeWitt pour avoir voulu y parvenir avec un petit extrait. Il n'y a vraiment pas beaucoup de danger à écrire une minuscule méthode utilitaire (je ne la vois pas comme "ARROGANCE SIMPLE oh nooooo !! il pense qu'il est meilleur qu'Apache !!"). Il y a des tonnes de projets, en particulier dans les langages JVM non Java, qui ne veulent vraiment pas inclure Guava ou Commons Lang juste pour enregistrer une trace de pile. J'écris des bibliothèques Scala & Clojure et ne ferai certainement pas d'Apache Commons Lang une dépendance transitive juste pour une méthode.
jm0

Réponses:

1039

On peut utiliser la méthode suivante pour convertir une Exceptiontrace de pile en String. Cette classe est disponible dans Apache commons-lang qui est la bibliothèque dépendante la plus courante avec de nombreuses sources ouvertes populaires

org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

amar
la source
88
@Stijn - pour être juste (j'ai écrit la réponse la plus votée actuelle ci-dessous), il vaut la peine de regarder commons-lang pour beaucoup plus de fonctionnalités
Brian Agnew
54
@StijndeWitt Commons Lang est assez courant. Il est déjà présent dans la plupart de mes projets / projets au travail.
WhyNotHugo
16
@Hugo merci, allait utiliser le StringWriter pour éviter d'ajouter une nouvelle bibliothèque - il s'avère que c'est déjà une dépendance de 3 de mes dépendances. Alors pour le reste, vérifiez si vous l'avez déjà.
Nathanial
33
@MartinAsenov - selon votre logique, vous n'utiliseriez jamais une telle bibliothèque, n'est-ce pas? Vous ne l'utiliseriez pas à moins que vous ne l'utilisiez déjà?
Brian Agnew
16
FYI, le paquet a changé et la classe est maintenant à: org.apache.commons.lang3.exception.ExceptionUtils.
schmmd
2201

Utilisez Throwable.printStackTrace(PrintWriter pw)pour envoyer la trace de pile à un écrivain approprié.

import java.io.StringWriter;
import java.io.PrintWriter;

// ...

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); // stack trace as a string
System.out.println(sStackTrace);
Brian Agnew
la source
505
Si vous n'aimez pas inclure une bibliothèque externe pour quelque chose d'aussi petit et simple que cela, utilisez cette réponse.
Stijn de Witt
8
Cela coupe la trace de la pile, de la même manière que printStackTrace (). Toutes les exceptions de la pile sont visibles, mais pour chaque exception, la pile peut être tronquée. Quiconque a besoin de la trace entière doit en tenir compte.
Laila Agaev,
5
Il s'avère que c'est à peu près exactement ce que fait la méthode ExceptionUtils.getStackTrace () d'apache. Presque à la lettre en fait.
ticktock
6
@BrianAgnew, ne devriez-vous pas fermer le StringWriteret PrintWriter?
Muhammad Gelbana
13
@BrianAgnew, merci pour la réponse. Cela m'a rendu curieux et voici ce que j'ai trouvé: stackoverflow.com/questions/14542535/…
Muhammad Gelbana
459

Cela devrait fonctionner:

StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
D. Wroblewski
la source
69
Concis dans le contexte java est toujours montagneux. Cela printStackTracedevrait simplement renvoyer une chaîne, laissant la décision de l'imprimer ou non à l'utilisateur :)
dmitry
35
L'impression printStackTrace dans la console est acceptable, mais au moins un getStackTrace le renvoyant en tant que chaîne devrait être disponible par défaut
Mateus Viccari
5
Quelle partie de cela est concise? Vous devez construire 2 objets qui existent à d'autres fins que de mettre la trace de pile dans une chaîne.
ArtOfWarfare
7
@dmitry Une méthode appelée printXXX()devrait afficher XXX.
Marquis de Lorne
2
@Greg En fait, ce n'était même pas du sarcasme, il fallait juste une lecture claire de ce qu'il avait dit.
Andrew
225

Si vous développez pour Android, un moyen beaucoup plus simple consiste à utiliser ceci:

import android.util.Log;

String stackTrace = Log.getStackTraceString(exception); 

Le format est le même que getStacktrace, par exemple

09-24 16:09:07.042: I/System.out(4844): java.lang.NullPointerException
09-24 16:09:07.042: I/System.out(4844):   at com.temp.ttscancel.MainActivity.onCreate(MainActivity.java:43)
09-24 16:09:07.042: I/System.out(4844):   at android.app.Activity.performCreate(Activity.java:5248)
09-24 16:09:07.043: I/System.out(4844):   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.access$800(ActivityThread.java:139)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
09-24 16:09:07.043: I/System.out(4844):   at android.os.Handler.dispatchMessage(Handler.java:102)
09-24 16:09:07.043: I/System.out(4844):   at android.os.Looper.loop(Looper.java:136)
09-24 16:09:07.044: I/System.out(4844):   at android.app.ActivityThread.main(ActivityThread.java:5097)
09-24 16:09:07.044: I/System.out(4844):   at java.lang.reflect.Method.invokeNative(Native Method)
09-24 16:09:07.044: I/System.out(4844):   at java.lang.reflect.Method.invoke(Method.java:515)
09-24 16:09:07.044: I/System.out(4844):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
09-24 16:09:07.044: I/System.out(4844):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
Vicky Kapadia
la source
2
Merci. Dans ce cas, une date et une balise ne sont pas écrites sur chaque ligne comme dans printStackTrace ().
CoolMind du
1
En fait, Log.getStackTraceString utilise dans son noyau les StringWriter et Printwriter mentionnés ci-dessus (de D. Wroblewski).
MikeL
2
La façon la plus simple de l'imprimer dans le journal Android est la suivante: Log.e("TAG", "My message", new Throwable());
Erick M. Sprengel
113

AVERTISSEMENT: n'inclut pas la cause (qui est généralement le bit utile!)

public String stackTraceToString(Throwable e) {
    StringBuilder sb = new StringBuilder();
    for (StackTraceElement element : e.getStackTrace()) {
        sb.append(element.toString());
        sb.append("\n");
    }
    return sb.toString();
}
jqno
la source
1
J'irais avec une extension de cette approche si vous souhaitez couper la trace, par exemple passer un paramètre maxLines et n'ajouter que autant de lignes à la trace
Rich Seller
Les parenthèses après e.getStackTrace sont manquantes. public static String stackTraceToString (Exception e) {StringBuilder sb = new StringBuilder (); pour (élément StackTraceElement: e.getStackTrace ()) {sb.append (element.toString ()); sb.append ("<br />"); } return sb.toString (); }
rlc
2
Pas sûr, mais je pense que cela n'imprimera pas la trace de pile de l'exception de cause racine.
apoorv020
7
Quoi que vous fassiez, ne coupez pas la trace. Il m'est arrivé de nombreuses fois de regarder une trace de pile dans les journaux GlassFish qui avait les parties utiles supprimées.
cayhorstmann
Utilisez String.format("%n")ou quelque chose de similaire au lieu de "\n"faire plaisir aux lamers DOS.
ceving
89

Pour moi, le moyen le plus propre et le plus simple était:

import java.util.Arrays;
Arrays.toString(e.getStackTrace());
Vladas Diržys
la source
37
Le code est propre, mais la sortie ne l'est pas. Vous devez faire un .replaceAll (",", "\ n") à la fin. Cependant, vous perdez l'indentation proposée par printStackTrace.
fureur
4
Ceci est utile lorsque vous enregistrez la trace sur une seule ligne
webjockey
28
public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}
Akira Yamamoto
la source
1
Bonjour, je voudrais simplement souligner que la section des commentaires de la réponse citée souligne que les objets StringWriteret PrintWriterdoivent être closed ... (ou je suppose que seuls les PrintWriterbesoins doivent être fermés car la fermeture devrait fermer le StringWritertrop)
Eric
8
Par inspiré, vous voulez dire copié? Vous ne le mettez que dans une méthode ... Lire les réponses ici, c'est comme regarder "Groundhog Day"
Murmel
26

Le code suivant vous permet d'obtenir l'intégralité de stackTrace avec un Stringformat, sans utiliser d'API comme log4J ou même java.util.Logger:

catch (Exception e) {
    StackTraceElement[] stack = e.getStackTrace();
    String exception = "";
    for (StackTraceElement s : stack) {
        exception = exception + s.toString() + "\n\t\t";
    }
    System.out.println(exception);
    // then you can send the exception string to a external file.
}
Dumonderic
la source
1
ya mais c'est un peu encombrant tu ne crois pas? dans tout cadre de journalisation de projet de taille raisonnable est un must alors pourquoi s'embêter
mzzzzb
Celui-ci ne donne pas le message d'erreur au début. peut être ajouté cependant
kommradHomer
Vous souhaiterez peut-être utiliser un StringBuffer au lieu d'une simple concaténation.
dedda1994
Ceci est utile lorsque vous n'êtes pas autorisé à enregistrer le message pour des raisons de confidentialité.
A1m
Sachez cependant que cette solution
n'enregistrera
19

Voici une version qui peut être copiée directement dans le code:

import java.io.StringWriter; 
import java.io.PrintWriter;

//Two lines of code to get the exception into a StringWriter
StringWriter sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));

//And to actually print it
logger.info("Current stack trace is:\n" + sw.toString());

Ou, dans un bloc de capture

} catch (Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    logger.info("Current stack trace is:\n" + sw.toString());
}
rouble
la source
cela continuera au - delà de la portée de la fonction actuelle, c.-à-d. où le Throwableest défini, non?
n611x007
16
Arrays.toString(thrown.getStackTrace())

Est le moyen le plus simple de convertir le résultat en chaîne Je l'utilise dans mon programme pour imprimer la trace de la pile

LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
Ramanan Durairaj
la source
A fonctionné pour moi, rien ne semble être coupé! Réponse plus simple que les autres sans bibliothèque externe, excellente réponse!
Shaung Cheng
16

Imprimez la trace de pile dans a PrintStream, puis convertissez-la en a String:

// ...

catch (Exception e)
{
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    e.printStackTrace(new PrintStream(out));
    String str = new String(out.toByteArray());

    System.out.println(str);
}
Au four
la source
1
c'est la réponse la plus directe
DaSqy Stc
11

Impression de la trace de pile dans une chaîne

import java.io.PrintWriter;
import java.io.StringWriter;

public class StackTraceUtils {
    public static String stackTraceToString(StackTraceElement[] stackTrace) {
        StringWriter sw = new StringWriter();
        printStackTrace(stackTrace, new PrintWriter(sw));
        return sw.toString();
    }
    public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter pw) {
        for(StackTraceElement stackTraceEl : stackTrace) {
            pw.println(stackTraceEl);
        }
    }
}

Il est utile lorsque vous souhaitez imprimer la trace de la pile de threads actuelle sans créer d'instance de Throwable- mais notez que la création d'une nouvelle Throwabletrace de pile à partir de là est en fait plus rapide et moins coûteuse que d'appeler Thread.getStackTrace.

Jarek Przygódzki
la source
11

Kotlin

L'extension de la classe Throwable vous donnera la propriété String error.stackTraceString:

val Throwable.stackTraceString: String
  get() {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    this.printStackTrace(pw)
    return sw.toString()
  }
vonox7
la source
10
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}
eddyrokr
la source
1
Merci eddyrkokr! Cela fonctionne parfaitement pour tous mes clases. Je viens de l'ajouter dans la classe de base TestNG et il collecte les traces de pile un par un de tous mes tests!
Krzysztof Walczewski
9

Le tir intelligent dans la première série de commentaires a été très amusant, mais cela dépend vraiment de ce que vous essayez de faire. Si vous n'avez pas déjà la bonne bibliothèque, alors 3 lignes de code (comme dans la réponse de D. Wroblewski) sont parfaites. OTOH, si vous avez déjà la bibliothèque apache.commons (comme la plupart des grands projets), alors la réponse d'Amar est plus courte. OK, cela peut vous prendre dix minutes pour obtenir la bibliothèque et l'installer correctement (moins d'une si vous savez ce que vous faites). Mais l'horloge tourne, vous n'aurez donc peut-être pas de temps à perdre. Jarek Przygódzki avait une mise en garde intéressante - "Si vous n'avez pas besoin d'exceptions imbriquées".

Mais si je ne dois les traces de la pile complète, et tous imbriqués? Dans ce cas, le secret consiste à utiliser getFullStackTrace d'apache.common (voir http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29 )

Cela a sauvé mon bacon. Merci, Amar, pour l'astuce!

Tihamer
la source
9

Code d' Apache Commons Lang 3.4 ( JavaDoc ):

public static String getStackTrace(final Throwable throwable) {
    final StringWriter sw = new StringWriter();
    final PrintWriter pw = new PrintWriter(sw, true);
    throwable.printStackTrace(pw);
    return sw.getBuffer().toString();
}

La différence avec les autres réponses est qu'il utilise autoFlush sur le PrintWriter.

IvanRF
la source
8

Sans java.io.*cela, cela peut se faire comme ça.

String trace = e.toString() + "\n";                     

for (StackTraceElement e1 : e.getStackTrace()) {
    trace += "\t at " + e1.toString() + "\n";
}   

Et puis le trace variable contient votre trace de pile. La sortie contient également la cause initiale, la sortie est identique àprintStackTrace()

Exemple, printStackTrace()donne:

java.io.FileNotFoundException: / (Is a directory)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:270)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
    at Test.main(Test.java:9)

La tracechaîne tient, lorsqu'elle est imprimée surstdout

java.io.FileNotFoundException: / (Is a directory)
     at java.io.FileOutputStream.open0(Native Method)
     at java.io.FileOutputStream.open(FileOutputStream.java:270)
     at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
     at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
     at Test.main(Test.java:9)
Gala
la source
5

Version Scala

def stackTraceToString(e: Exception): String = {
  import java.io.PrintWriter
  val sw = new StringWriter()
  e.printStackTrace(new PrintWriter(sw))
  sw.toString
}
samthebest
la source
5

si vous utilisez Java 8, essayez ceci

Arrays.stream(e.getStackTrace())
                .map(s->s.toString())
                .collect(Collectors.joining("\n"));

vous pouvez trouver le code de getStackTrace()fonction fourni par Throwable.java:

public StackTraceElement[] getStackTrace() {
    return getOurStackTrace().clone();
}

et pour StackTraceElement, il fournit toString()comme:

public String toString() {
    return getClassName() + "." + methodName +
        (isNativeMethod() ? "(Native Method)" :
         (fileName != null && lineNumber >= 0 ?
          "(" + fileName + ":" + lineNumber + ")" :
          (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
}

Il suffit donc de rejoindre le StackTraceElement"\ n".

Pengcheng Zhang
la source
Cette solution ne respecte pas le retrait de l'onglet de trace de pile, sinon cela fonctionne très bien!
krizajb
4

une extension de la réponse de Gala qui inclura également les causes de l'exception:

private String extrapolateStackTrace(Exception ex) {
    Throwable e = ex;
    String trace = e.toString() + "\n";
    for (StackTraceElement e1 : e.getStackTrace()) {
        trace += "\t at " + e1.toString() + "\n";
    }
    while (e.getCause() != null) {
        e = e.getCause();
        trace += "Cause by: " + e.toString() + "\n";
        for (StackTraceElement e1 : e.getStackTrace()) {
            trace += "\t at " + e1.toString() + "\n";
        }
    }
    return trace;
}
lin ido
la source
4

La solution consiste à convertir le stackTrace du tableau en type de données chaîne . Voir l'exemple suivant:

import java.util.Arrays;

try{

}catch(Exception ex){
    String stack = Arrays.toString(ex.getStackTrace());
    System.out.println("stack "+ stack);
}
jorge santos
la source
4

Avec l' API Java 8 Stream, vous pouvez faire quelque chose comme ceci:

Stream
    .of(throwable.getStackTrace())
    .map(StackTraceElement::toString)
    .collect(Collectors.joining("\n"));

Il prendra un tableau d'oligo-éléments de pile, les convertira en chaîne et les joindra en chaîne multiligne.

ivanjermakov
la source
2
Cette solution supprime le message et ignore toutes les traces des parents
judovana
3

Mon oneliner pour convertir la trace de la pile en la chaîne multiligne incluse:

Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))

Facile à transmettre à l'enregistreur "tel quel".

Andrey Lebedenko
la source
Vous obtenez quelque chose qui diffère de printStackTrace()Ici, vous perdrez: 1) Exception qui a été levée; 2) Les causes et leur stacktrace
Valijon
La différence est tout à fait attendue, car la conversion du printStackTrace()jamais fait partie de la question.
Andrey Lebedenko
2

Si vous ne souhaitez pas utiliser une bibliothèque externe et que vous ne développez pas pour Android , vous pouvez créer une méthode d'extension comme celle-ci:

public static String getStackTraceString(Throwable e) {
    return getStackTraceString(e, "");
}

private static String getStackTraceString(Throwable e, String indent) {
    StringBuilder sb = new StringBuilder();
    sb.append(e.toString());
    sb.append("\n");

    StackTraceElement[] stack = e.getStackTrace();
    if (stack != null) {
        for (StackTraceElement stackTraceElement : stack) {
            sb.append(indent);
            sb.append("\tat ");
            sb.append(stackTraceElement.toString());
            sb.append("\n");
        }
    }

    Throwable[] suppressedExceptions = e.getSuppressed();
    // Print suppressed exceptions indented one level deeper.
    if (suppressedExceptions != null) {
        for (Throwable throwable : suppressedExceptions) {
            sb.append(indent);
            sb.append("\tSuppressed: ");
            sb.append(getStackTraceString(throwable, indent + "\t"));
        }
    }

    Throwable cause = e.getCause();
    if (cause != null) {
        sb.append(indent);
        sb.append("Caused by: ");
        sb.append(getStackTraceString(cause, indent));
    }

    return sb.toString();
}
Kapé
la source
2

Vieille question, mais je voudrais juste ajouter le cas spécial où vous ne voulez pas imprimer toute la pile , en supprimant certaines parties qui ne vous intéressent pas réellement, à l'exclusion de certaines classes ou packages.

Au lieu d'une PrintWriterutilisation SelectivePrintWriter:

// This filters out this package and up.
String packageNameToFilter = "org.springframework";

StringWriter sw = new StringWriter();
PrintWriter pw = new SelectivePrintWriter(sw, packageNameToFilter);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); 
System.out.println(sStackTrace);

Lorsque la SelectivePrintWriterclasse est donnée par:

public class SelectivePrintWriter extends PrintWriter {
    private boolean on = true;
    private static final String AT = "\tat";
    private String internal;

    public SelectivePrintWriter(Writer out, String packageOrClassName) {
        super(out);
        internal = "\tat " + packageOrClassName;
    }

    public void println(Object obj) {
        if (obj instanceof String) {
            String txt = (String) obj;
            if (!txt.startsWith(AT)) on = true;
            else if (txt.startsWith(internal)) on = false;
            if (on) super.println(txt);
        } else {
            super.println(obj);
        }
    }
}

Veuillez noter que cette classe peut être facilement adaptée pour filtrer par Regex containsou d'autres critères. Notez également que cela dépend des Throwabledétails de mise en œuvre (peu susceptibles de changer, mais quand même).

MarcG
la source
1
Oui, cela fonctionne bien et est en fait une idée assez utile.
gil.fernandes
2
 import java.io.PrintWriter;
import java.io.StringWriter;

public class PrintStackTrace {

    public static void main(String[] args) {

        try {
            int division = 0 / 0;
        } catch (ArithmeticException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            String exceptionAsString = sw.toString();
            System.out.println(exceptionAsString);
        }
    }
}

Lorsque vous exécutez le programme, la sortie sera quelque chose de similaire:

java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Prakhar Nigam
la source
1

Je me demande pourquoi personne n'a mentionné ExceptionUtils.getStackFrames(exception)

Pour moi, c'est le moyen le plus pratique de vider stacktrace avec toutes ses causes jusqu'à la fin:

String.join("\n", ExceptionUtils.getStackFrames(exception));
Andrey Sarul
la source
0

Attention: c'est peut-être un peu hors sujet, mais bon ...;)

Je ne sais pas quelle était la raison originale des affiches pour vouloir la trace de la pile comme chaîne en premier lieu. Lorsque la trace de pile doit se retrouver dans un journal SLF4J / Logback, mais qu'aucune exception n'a été ou ne devrait être levée, voici ce que je fais:

public void remove(List<String> ids) {
    if(ids == null || ids.isEmpty()) {
        LOG.warn(
            "An empty list (or null) was passed to {}.remove(List). " +
            "Clearly, this call is unneccessary, the caller should " + 
            "avoid making it. A stacktrace follows.", 
            getClass().getName(),
            new Throwable ("Stacktrace")
        );

        return;
    }

    // actual work, remove stuff
}

Je l'aime parce qu'il ne nécessite pas de bibliothèque externe (autre que votre backend de journalisation, qui sera bien sûr en place la plupart du temps).

Alexander Wessel
la source