我經常發現需要驗證一組條件,而不是提前失敗(在第一個條件未滿足時返回false或拋出異常),我需要彙總結果並報告個人故障。彙總異常
我現在要麼使用自定義條目列表(基本上是一個條目由失敗類型和一些信息性消息組成)或某種觀察者(這也只是聚合失敗),但我有一種感覺這應該是一個普遍的問題,應該有一些現有的模式來解決這個問題。
我經常發現需要驗證一組條件,而不是提前失敗(在第一個條件未滿足時返回false或拋出異常),我需要彙總結果並報告個人故障。彙總異常
我現在要麼使用自定義條目列表(基本上是一個條目由失敗類型和一些信息性消息組成)或某種觀察者(這也只是聚合失敗),但我有一種感覺這應該是一個普遍的問題,應該有一些現有的模式來解決這個問題。
是的,這是一個常見問題,而且你的方法都很好。
javax.validation.Validator
,這是java驗證的標準,使用前者。它返回的ConstraintViolations
s
如果它適合您的情況,我會建議使用javax.validation
而不是自定義。這是一個規範與多個提供商,其中之一是hibernate-validator(不需要使用休眠來使用驗證項目)
我不認爲你需要一個複雜的解決方案。當我不得不這樣做,我一般只寫類似:
List<String> errors=new ArrayList<String>();
...
if (foo<0)
errors.add("Bad foo");
if (!bar.contains(plugh))
errors.add("No plugh in bar");
... etc, whatever other errors ...
... then at the bottom ...
if (errors.size()>0)
{
... throw exception, display errors, whatever ...
}
... else celebrate and get on with it ...
或者,如果我知道,所有我會與錯誤做的是顯示一個大消息,我可能只是使誤差領域字符串並不斷以任何格式將消息附加到它。
我使用下面的類來收集和顯示幾個例外。它只使用標準的Java。
package util;
import java.io.ByteArrayOutputStream;
import java.io.IOError;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
/**
* This abstract class is to be used for Exception generating by a collection of causes.
* <p />
* Typically: several tries take place to do something in different ways and each one fails. We therefore
* have to collect the exceptions to document why it was not possible at all to do the thing.
*/
public abstract class AggregateException extends Exception
{
/** A generator of random numbers */
private final static Random rand = new Random();
/** The causes of the exception */
private final Vector<Throwable> causes;
/** A (reasonably unique) id for this exception. Used for a better output of the stacktraces */
private final long id = rand.nextLong();
/**
* @see Exception#Exception(String)
* @param message
*/
public AggregateException(String message, Collection<? extends Throwable> causes)
{
super(message);
this.causes = new Vector<Throwable>(causes);
}
/**
* Prints this throwable and its backtrace to the specified print stream.
*
* @param s <code>PrintStream</code> to use for output
*/
public void printStackTrace(PrintStream s) {
synchronized (s) {
s.println(this);
StackTraceElement[] trace = getStackTrace();
for (int i=0; i < trace.length; i++)
s.println("\tat " + trace[i]);
final Throwable ourCause = getCause();
if (ourCause != null)
throw new AssertionError("The cause of an AggregateException should be null");
for (int i = 0; i<causes.size(); i++)
{
final Throwable cause = causes.get(i);
s.println(String.format(
"Cause number %s for AggregateException %s: %s ",
i,
getId(),
cause.toString()
));
final ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(byteArrayOS);
cause.printStackTrace(ps);
ps.close();
final String causeStackTrace = byteArrayOS.toString();
int firstCR = causeStackTrace.indexOf("\n");
s.append(causeStackTrace.substring(firstCR == -1 ? 0 : firstCR+1));
}
}
}
@Override
public String toString()
{
return String.format(
"%s. AggregateException %s with %s causes.",
super.toString(),
getId(),
causes.size()
);
}
@Override
public Throwable initCause(Throwable cause)
{
if (cause != null)
throw new AssertionError("The cause of an AggregateException must be null");
return null;
}
/**
*
* @return {@link #id}
*/
private String getId()
{
return String.format("%xs", id);
}
/**
* Test class
*/
public static class TestException extends AggregateException
{
/**
* Constructor
* @param message
* @param causes
*/
public TestException(String message, Collection<? extends Throwable> causes)
{
super(message, causes);
}
/**
* Test program
*
* @param notused
* @throws AggregateException
*/
public static void main (final String[] notused) throws AggregateException
{
final List<Error> causes = new LinkedList<Error>();
causes.add(new OutOfMemoryError());
try
{
generateIOError();
}
catch (final Error th)
{
causes.add(th);
}
final AggregateException ae = new TestException("No test has sucessed", causes);
throw ae;
}
/**
* For test: generate an IOError caused by an IOException
*/
private static void generateIOError()
{
try
{
generateIOException();
}
catch (final IOException ioex)
{
throw new IOError(ioex);
}
}
/**
* For test: throws an IOException
* @throws IOException
*/
private static void generateIOException() throws IOException
{
throw new IOException("xxx");
}
}
}
如果其他人抓住您的AggregateException並將其作爲原因重新拋出,則不起作用 - printStackTrace不保證以遞歸方式調用。 (另外,您錯過了PrintWriter重載。) – 2013-05-03 19:10:05