我经常发现需要验证一组条件,而不是提前失败(在第一个条件未满足时返回false或抛出异常),我需要聚合结果并报告各个失败。
我目前要么使用带有自定义条目的列表(基本上是一个条目包含失败的类型和一些信息性消息)或某种观察者(也只是聚合失败),但我有一种感觉这应该是一个常见的问题,应该有一些现有的模式来解决这个问题。
答案 0 :(得分:9)
是的,这是一个常见的问题,而且你的方法都很好。
javax.validation.Validator
,这是java验证的标准,使用前者。它返回Set
ConstraintViolations
个
如果它适合您的情况,我建议使用javax.validation
而不是自定义。这是一个包含多个提供程序的规范,其中一个是hibernate-validator(不需要使用hibernate来使用验证项目)
答案 1 :(得分:1)
我认为您不需要复杂的解决方案。当我必须这样做时,我通常会写一些类似的东西:
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 ...
或者,如果我知道我将要处理的错误是显示一条大消息,我可能只是将错误字段设为字符串并继续以任何格式向其添加消息。
答案 2 :(得分:1)
我使用以下类来收集和显示几个异常。它只使用标准的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");
}
}
}