exceptions - Exception Chaining

本文介绍了一个能够动态添加字段的类DynamicFields,通过实例演示了如何使用此类,并展示了如何处理异常,包括使用initCause()方法进行异常链的创建。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 To chain any other exception types, use the initCause() method rather than the constructor.

// exceptions/DynamicFields.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// A Class that dynamically adds fields to itself to
// demonstrate exception chaining

class DynamicFieldsException extends Exception {}

public class DynamicFields {
  private Object[][] fields;

  public DynamicFields(int initialSize) {
    fields = new Object[initialSize][2];
    for (int i = 0; i < initialSize; i++) {
      fields[i] = new Object[] {null, null};
    }
  }

  @Override
  public String toString() {
    StringBuilder result = new StringBuilder();
    for (Object[] obj : fields) {
      result.append(obj[0]);
      result.append(": ");
      result.append(obj[1]);
      result.append("\n");
    }
    return result.toString();
  }

  private int hasField(String id) {
    for (int i = 0; i < fields.length; i++) {
      if (id.equals(fields[i][0])) {
        return i;
      }
    }
    return -1;
  }

  private int getFieldNumber(String id) throws NoSuchFieldException {
    int fieldNum = hasField(id);
    if (fieldNum == -1) {
      throw new NoSuchFieldException();
    }
    return fieldNum;
  }

  private int makeField(String id) {
    for (int i = 0; i < fields.length; i++)
      if (fields[i][0] == null) {
        fields[i][0] = id;
        return i;
      }
    // No empty fields. Add one:
    Object[][] tmp = new Object[fields.length + 1][2];
    for (int i = 0; i < fields.length; i++) {
      tmp[i] = fields[i];
    }
    for (int i = fields.length; i < tmp.length; i++) {
      tmp[i] = new Object[] {null, null};
    }
    fields = tmp;
    // Recursive call with expanded fields:
    return makeField(id);
  }

  public Object getField(String id) throws NoSuchFieldException {
    return fields[getFieldNumber(id)][1];
  }

  public Object setField(String id, Object value) throws DynamicFieldsException {
    if (value == null) {
      // Most exceptions don't have a "cause"
      // constructor. In these cases you must use
      // initCause(), available in all
      // Throwable subclasses.
      DynamicFieldsException dfe = new DynamicFieldsException();
      dfe.initCause(new NullPointerException()); // [1]
      throw dfe;
    }
    int fieldNumber = hasField(id);
    if (fieldNumber == -1) {
      fieldNumber = makeField(id);
    }
    Object result = null;
    try {
      result = getField(id); // Get old value
      // System.out.println("old value:" + result);
    } catch (NoSuchFieldException e) {
      // Use constructor that takes "cause":
      throw new RuntimeException(e); // [2]
    }
    fields[fieldNumber][1] = value;
    return result;
  }

  public static void main(String[] args) {
    DynamicFields df = new DynamicFields(3);
    System.out.println(df);
    try {
      df.setField("d", "A value for d");
      df.setField("number", 47);
      df.setField("number2", 48);
      System.out.println(df);
      df.setField("d", "A new value for d");
      df.setField("number3", 11);
      System.out.println("df: " + df);
      System.out.println("df.getField(\"d\") : " + df.getField("d"));
      Object field = df.setField("d", null); // Exception
    } catch (NoSuchFieldException | DynamicFieldsException e) {
      e.printStackTrace(System.out);
    }
  }
}
/* My Output:
null: null
null: null
null: null

d: A value for d
number: 47
number2: 48

df: d: A new value for d
number: 47
number2: 48
number3: 11


df.getField("d") : A new value for d
DynamicFieldsException
        at DynamicFields.setField(DynamicFields.java:78)
        at DynamicFields.main(DynamicFields.java:109)
Caused by: java.lang.NullPointerException
        at DynamicFields.setField(DynamicFields.java:79)
        ... 1 more
*/

Class Throwable's method:

initCause

public Throwable initCause(Throwable cause)

Initializes the cause of this throwable to the specified value. (The cause is the throwable that caused this throwable to get thrown.)

This method can be called at most once. It is generally called from within the constructor, or immediately after creating the throwable. If this throwable was created with Throwable(Throwable) orThrowable(String,Throwable), this method cannot be called even once.

An example of using this method on a legacy throwable type without other support for setting the cause is:

 try {
     lowLevelOp();
 } catch (LowLevelException le) {
     throw (HighLevelException)
           new HighLevelException().initCause(le); // Legacy constructor
 }
 

Parameters:

cause - the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted, and indicates that the cause is nonexistent or unknown.)

Returns:

a reference to this Throwable instance.

Throws:

IllegalArgumentException - if cause is this throwable. (A throwable cannot be its own cause.)

IllegalStateException - if this throwable was created with Throwable(Throwable) or Throwable(String,Throwable), or this method has already been called on this throwable.

Since:

1.4

references:

1. On Java 8 - Bruce Eckel

2. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/exceptions/DynamicFields.java

3. https://docs.oracle.com/javase/8/docs/api/java/lang/Throwable.html#initCause-java.lang.Throwable-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值