Got a question that the wiki doesn't answer? Ask on the forum (preferred), or join us on IRC.

BeastNode

CommandHelper/Staged/Exceptions

From EngineHub.org Wiki
Jump to: navigation, search


Exceptions can be thrown by various functions at runtime. This indicates that there was some issue with the input data. There is a straightforward way to deal with these errors however, using a try/catch block.

Example

A good example is code that takes a user input. Assume that we want to validate that the user has provided us with an integer like string. We might write the following:

1   @userInput = _getUserInput();
2   @value = integer(@userInput);
3   _doSomethingWithTheValue(@value);


In this case, if the user input procedure returns '2', then the code will work as intended. If it returns 'string' however, it will throw an exception. As it stands, with no exception handling in place, you would see a similar error to this:

CastException: Expecting a double, but received string instead
        <<main code>>:Interpreter:2

This is the default exception handling mechanism. It prints out the exception type, exception message, and a stacktrace. But perhaps we want to print a custom message to the user. In this case, we can trap the exception using a try/catch block, and handle it in a custom way. In this case, we want to "catch" the CastException that is "thrown".

1   try {
2      @userInput = _getUserInput();
3      @value = integer(@userInput); // Can throw CastException
4      _doSomethingWithTheValue(@value);
5   } catch(CastException @e){
6      // This will run if integer(@userInput) throws a CastException
7      msg("The value must be an integer");
8   }


This will message the user if the value is not correct, using a custom error message.

Multicatch

Sometimes, a block of code might throw multiple types of exceptions, and we want to handle each type differently. Perhaps our _doSomethingWithTheValue procedure was capable of throwing an IOException. We could wrap the entire block in a second try catch block, but there's an easier way, using multicatch.

1   try {
2      @userInput = _getUserInput();
3      @value = integer(@userInput); // Can throw CastException
4      _doSomethingWithTheValue(@value); // Can throw IOException
5   } catch(CastException @e) {
6      msg("The value must be an integer");
7   } catch(IOException @e) {
8      msg("There was an error with the disk, and your request could not be completed.");
9   }


Each catch block will only run if the exception thrown matches the type. If an exception is thrown that doesn't match any of the types, it will continue up the stack as if there were no try/catch in place at that point.

Catch clause specificity

When an exception is thrown, the catch clauses are checked one by one, in declaration order, for exception matches. This means that you should order your catch clauses from most specific to least specific. Consider the following code:

1   try {
2      code();
3   } catch(Exception @e){
4      msg("Will catch the exception");
5   } catch(IOException @e){
6      msg("Will never run, because the catch-Exception clause will always catch the exception first, because"
7         . " IOException extends Exception");
8   }


Be sure to always order your catch clauses appropriately.

The exception object

The exception that is thrown is an associative array that has some perhaps useful information in it, such as the exception message, line number, and things like that. Here is an implementation of the default handling, except it is being handled from within the script.

01   try {
02      code();
03   } catch(CastException @e) {
04      @classType = @e['classType'];
05      @message = @e['message'];
06      @stackTrace = @e['stackTrace'];
07      msg(colorize("&c@classType&f: @message"));
08      foreach(@element in @stackTrace){
09         @procedureName = @element['id']; // This could be a procedure or a closure, or a few other things
10         @file = @element['file'];
11         @line = @element['line'];
12         msg(colorize("\t&a@procedureName&f:&6@file&f:&b@line"));
13      }
14   }


The above example demonstrates the complex usage of the exception object. In addition, it's worth noting that if you are having trouble with code, you could get a stacktrace by throwing and catching a custom exception, however, it's more straightforward to use get_stack_trace()

The Throwable type

All exceptions extend the Exception type, which further extends the Throwable type. Another type of Throwable is a the Error type (and subclasses). If you specifically catch Errors, they can be caught, but this is not recommended, as it usually indicates a very severe error. While it is possible to directly catch a Throwable of any type, you should generally not catch that, and instead catch specific types that you are interested in, or Exception, if need be.

Throwing your own exceptions

You may also throw your own exceptions. See the documentation for Template:Functions for more information.

finally clause

Sometimes you may want to run code after the try block, regardless of what happens in the try block, including successful invocation of the code, an exception being thrown and further exceptions being thrown from the catch block, or simply return()ing in the try block. The finally clause can be used to accomplish this. The finally clause must come after all catch clauses, but may be used even if no catch clauses are defined (this is called a try/finally block). This is most useful for cleanup that needs to happen regardless of how the code exited.

There are three specific examples that this might be useful for:


  1. If code within the `try` block exits via `return`
  2. If code within a catch block either rethrows the caught exception, or--accidentally or intentionally--ends up throwing a new one.
  3. If the code within the `try` block encounters an exception for which there is no catch.

Take the following examples:

1   try {
2      @value = codeThatOpensAResource();
3      return(@value);
4   } finally {
5      cleanUpResource();
6   }


1   try {
2      code();
3   } catch(Exception @e) {
4      throw(IOException, "Another exception");
5   } finally {
6      // This section still runs
7   }


1   try {
2      codeThatThrowsANullPointerException();
3   } catch(IOException @e) {
4      // This block won't be run in this case
5   } finally {
6      // This code runs anyways, though the NPE will be thrown further up
7   }


Caused By, and rethrowing

Exceptions might need to be rethrown. This is supported by throw(). For instance:

1   try {
2      throw(IOException, 'message');
3   } catch(IOException @e){
4      if(/* some condition is true */){
5         // We don't care about this exception
6      } else {
7         throw(@e);
8      }
9   }


This can be used if you want to conditionally handle the exception, but continue to throw the exception up the chain in other cases.

You may find that you have to throw an exception due to another exception. To do this, you may also used the Caused By mechanism. This will cause the exception to chain. This is also supported with throw().

1   try {
2      try {
3         throw(IOException, 'ioexception');
4      } catch(IOException @e){
5         throw(CastException, 'castexception'@e);
6      }
7   } catch(CastException @e){
8      msg(@e['causedBy']); // This will be the IOException
9   }


This can be useful for times that you need to throw another exception from within the catch block, but don't want to hide the original exception, or when you need to otherwise wrap the original exception. It is quite useful to know what exception originally caused this chain. This can be accessed from the causedBy index in the exception object.


Old usage

There is an old, now deprecated usage as well, see the article here for information on how to use it. For new code, however, the new format should always be used.

Known Exception Types

Exception types can be added by extension authors, but here is a list (and documentation) for all known exceptions.

ByteArrayReadOnlyException

An exception which is thrown if the array copied from a byte array is attempted to be written to.

Since: 3.3.1

BadEntityException

Thrown if an entity is looked up by id, but doesn't exist.

Since: 3.3.1

BadEntityTypeException

Thrown if an entity has the wrong type.

Since: 3.3.1

BindException

This exception is thrown if an error occurs when trying to bind() an event, or if a event framework related error occurs.

Since: 3.3.1

CastException

This exception is thrown if a value cannot be cast into an appropriate type. Functions that require a numeric value, for instance, would throw this if the string "hi" were passed in.

Since: 3.3.1

EnchantmentException

If an enchantment is added to an item that isn't supported, this is thrown.

Since: 3.3.1

Error

Indicates a serious error occurred. It is not recommended to catch Error directly, but instead catch a specific subtype.

Since: 3.3.1

EventException

Thrown if something is wrong with the event object. Usually this indicates a bigger problem with the server configuration or plugin issue, rather than an error in the script.

Since: 3.3.2

Exception

A generic exception. All normal exceptions extend this type.

Since: 3.3.1

FormatException

This exception is thrown if a function expected a string to be formatted in a particular way, but it could not interpret the given value.

Since: 3.3.1

IOException

This exception is thrown if a file cannot be read or written to.

Since: 3.3.1

IllegalArgumentException

Thrown if an argument was illegal in the given context.

Since: 3.3.1

IncludeException

This exception is thrown if there is a problem with an include. This is thrown if there is a compile error in the included script.

Since: 3.3.1

IndexOverflowException

This exception is thrown if a value is requested from an array that is above the highest index of the array, or a negative number.

Since: 3.3.1

InsufficientArgumentsException

Some var arg functions may require at least a certain number of arguments to be passed to the function

Since: 3.3.1

InsufficientPermissionException

This exception is thrown if the user running the command does not have permission to run the function

Since: 3.3.1

InvalidPluginException

This exception is thrown if a function uses an external plugin, and that plugin is not loaded, or otherwise unusable.

Since: 3.3.1

InvalidProcedureException

This exception is thrown if a procedure is used without being defined, or if a procedure name does not follow proper naming conventions.

Since: 3.3.1

InvalidWorldException

If a function requests a world, and the world given doesn't exist, this is thrown

Since: 3.3.1

LengthException

This exception is thrown if a function expected the length of something to be a particular value, but it was not.

Since: 3.3.1

NotFoundException

Thrown if data was not found, but expected.

Since: 3.3.1

NullPointerException

If a null is sent, but not expected, this exception is thrown. Additionally, this is thrown if null is dereferenced.

Since: 3.3.1

PlayerOfflineException

This exception is thrown if a function expected an online player, but that player was offline, or the command is being run from somewhere not in game, and the function was trying to use the current player.

Since: 3.3.1

PluginChannelException

Thrown if trying to register a plugin channel that is already registered, or unregister one that isn't registered.

Since: 3.3.1

PluginInternalException

This exception is thrown when a plugin is loaded, but a call to the plugin failed, usually for some reason specific to the plugin. Check the error message for more details about this error.

Since: 3.3.1

RangeException

This exception is thrown if a function expected a numeric value to be in a particular range, and it wasn't

Since: 3.3.1

ReadOnlyException

Thrown if a field was read only, but a write operation was attempted.

Since: 3.3.1

SQLException

Thrown if an SQL related exception occurs.

Since: 3.3.1

ScoreboardException

Thrown if a scoreboard error occurs, such as attempting to create a team or objective with a name that is already in use, or trying to access one that doesn't exist.

Since: 3.3.1

SecurityException

This exception is thrown if a script tries to read or write to a location of the filesystem that is not allowed.

Since: 3.3.1

ShellException

Thrown if a shell exception occurs.

Since: 3.3.1

StackOverflowError

Thrown if a stack overflow error happens. This can occur if a function recurses too deeply.

Since: 3.3.1

UnageableMobException

If an age function is called on an unageable mob, this exception is thrown.

Since: 3.3.1

UntameableMobException

If an untameable mob is attempted to be tamed, this exception is thrown

Since: 3.3.1




Navigation menu