challenge 例外処理

例外処理の適当なサンプルを書いてください。

但し、言語によって例外処理がサポートされている場合はそれを利用してください。

Posted feedbacks - Flatten

Nested Hidden
Rubyではbegin-rescure-ensure-endを使用します。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
begin
    # 処理本体はここに記述します
    raise "サンプル例外です。"
rescue => e
    puts "例外が発生しました。(「#{e.message}」)"
else
    puts "例外が発生しなかった場合に実行されます。"
ensure
    puts "例外の発生如何に関わらず実行されます。"
end

 perlには例外用の構文はありませんが,evalを使用して処理するのが一般的です。

1
2
3
4
5
eval {
    # 処理本体はここに記述
    die "サンプルエラーです。";
};
print "例外が発生しました。(「$@」)\n" if ($@);

RにはJavaライクな例外処理が実装されています。

> tryCatch(expr(1), error=e.handler, finally=f.handler())
[1] "finished"
<simpleError: Exception>
> tryCatch(expr(0), error=e.handler, finally=f.handler())
[1] "not error"
[1] "finished"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
expr <- function(n=1){
  if(n==1){
    stop(simpleError("Exception"))
  }
  print("not error")
}
e.handler <- function(e) e
f.handler <- function() print("finished")

tryCatch(expr(1), error=e.handler, finally=f.handler())
tryCatch(expr(0), error=e.handler, finally=f.handler())

以下の2要素を組み合わせました。

- エラーが起きた時点で実行を中断 → set -e
- それ(とシグナル)を捕捉 → trap、サブシェル

$ sh q245.sh
beginning of program
begenning of foo
begenning of bar
Catch!
end of program
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/sh

bar() {
  echo 'begenning of bar'
  [ 1 = 2 ]             # raise error
  echo 'end of bar'
}

foo() (                 # () runs subshell
  echo 'begenning of foo'

  # catch
  set -e
  trap 'echo "Catch!"' EXIT

  bar
  echo 'end of foo'
)

echo 'beginning of program'
foo
echo 'end of program'

Limboでは処理ブロックの後にexceptionブロックを
つけることで例外処理が実現できるそうです。

例外処理ブロックはcase文と似た構文で、
"要因" =>
の後にその要因に対応する処理を書きます。

要因は
out of memory
zero divide
等が指定でき、*でワイルドカードが使えるようです。
1
2
3
4
5
6
7
    {
        # 処理本体
    } exception e {
       # 例外処理ブロック
    "*" =>
        # 処理内容
    }

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
class P
{
    static void Main(string[] args)
    {
        int a;
        string str;
        Console.WriteLine("逆数を求めます。整数を入力してください。");
        str = Console.ReadLine();
        try
        {
            a = (int)double.Parse(str);
            Console.WriteLine("1 / {0} = {1}", str, 1.0 / a);
        }
        catch (FormatException)
        {
            Console.WriteLine("{0}は整数として有効ではありません。", str);
        }
        catch (DivideByZeroException)
        {
            Console.WriteLine("0では割れません。");
        }
    }
}

javaではtry-catch-finallyを使います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class ExTest {
    public static void main( String[] args ) {
        try {
            throw new Exception();
        } catch ( Exception e ) {
            System.out.println( "例外が発生しました。" );
            // スタックトレースを表示する。
            e.printStackTrace();
        } finally { 
            System.out.println( "必ず実行されます。" );
        }
    }
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
component doukaku245
  export Executable

  object NewException extends Exception
    toString(): String = "Exception occured!"
  end

  run(args: String...): () = do
    try
      throw NewException
    catch e
      NewException => fail(e.toString())
    finally
      println("End of Exception test.")
    end

  end
end

std::vectorで範囲外エラー (std::out_of_rangeクラスが投げられる) を起こさせました。なお、catchではconst無しの参照 (std::exception& e) で受け取るのが一般的ですが、自分はconstを付ける派なのです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <vector>

int main()
{
    try
    {
        std::vector<int> v(2); //要素数2つ
        std::cout << "3つ値を入力してください。" << std::endl;
        std::cin >> v.at(0);
        std::cin >> v.at(1);
        std::cin >> v.at(2); //いや、そんなにないですって
    }
    catch (std::exception const& e)
    {
        std::cout << e.what() << std::endl;
    }
}

C言語、ただしシグナルやsetjmpではありません。Windowsの構造化例外処理 (SEH) です。

例外を投げるにはRaiseException関数を呼ぶ方法もありますが、今回はCPUに例外を発生させました。

_exceptの丸括弧の中の式では、例外をキャッチするか否かを指定する値を指定します。filterexception関数内で、判定を行っています。ちなみに、今回使いませんでしたが、EXCEPTION_CONTINUE_EXECUTIONという__exceptブロック{}を実行せず、例外が発生した場所から実行再開するという指定もあります。

また、GetExceptionCodeの代わりにGetExceptionInformationを使うと詳しい情報の入ったEXCEPTION_POINTERS構造体(へのポインタ)が得られます。RaiseExceptionと組み合わせればC++などのようなオブジェクトの引き渡しを模倣できるはずです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <windows.h>
#include <stdio.h>

int filter_exception(DWORD exceptionCode)
{
    return exceptionCode == EXCEPTION_ACCESS_VIOLATION
        ? EXCEPTION_EXECUTE_HANDLER
        : EXCEPTION_CONTINUE_SEARCH;
}

int main(void)
{
    __try
    {
        int* p = NULL;
        *p = 42; // ぬるぽ
    }
    __except(filter_exception(GetExceptionCode())) //例外をキャッチして処理する
    {
        fputs("ガッ!\n", stderr);
    }
    return 0;
}

1
2
3
4
5
6
7
8
9
def hoge():
  arr = []
  return arr[100]

try:
  hoge()
except Exception, e:
    print('hoge() faild')
    print(e)

HSPには例外処理機構が無いので、マクロで実装します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#define global try %tExcepHandling %i0 %i0 %i0 %i0 if (1)
#define global end_try %tExcepHandling *%p1 : %o0 %o0 %o0 %o0
#define global catch_list %tExcepHandling \
    if (0) : *%p : %p3 = 0
#define global TEMP_CATCH(%1,%2) %tExcepHandling \
    if ( %p3 ) { goto *%p1 } else { %p3 = 1 }\
    } if (%1) { %2 = THREW_VALUE
#define global ctype catch(%1,%2=THREW_VALUE) %tExcepHandling \
    TEMP_CATCH ( vartype(THREW_VALUE) == vartype("%1") ), %2
#define global ctype finally(%1=THREW_VALUE) %tExcepHandling \
TEMP_CATCH 1, %1
#define global throw(%1) %tExcepHandling \
THREW_VALUE = %1 : goto *%p
#define global try_break %tExcepHandling goto *%p1
#define global THREW_VALUE %tExcepHandling %p2

// サンプル・スクリプト
#if 1
    randomize
    repeat
        wait 50
        try {
            // メイン処理、この中でしか throw できない。
            switch ( rnd(3) )
                case 0 : throw 2147483647 : swbreak
                case 1 : throw "Hello, world!" : swbreak
                case 2 : throw 3.141592 : swbreak
            swend
            
        } catch_list {
            // throw されたらここに来る。
            catch (int, x)
                mes "int\t: "+ x
                
            catch(str)
                mes "str\t: \""+ THREW_VALUE +"\""
                
            finally()
                mes "final\t: "+ THREW_VALUE
        } end_try
        // catch_list を抜けるとここに来る
    loop
    stop
#endif

 ScalaはJavaと同じくtry-catch-finallyとなりますが,例外の振り分けにcaseによるマッチングを使う様になっている所がらしいでしょうか。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
object ExceptionSample {
    def main(args:Array[String]):Unit = {
        try {
            println("処理本体")
            args.size match {
                case 0 => throw new IllegalArgumentException("引数が指定されていません")
                case 1 => printf("引数: %s\n", args.first)
                case _ => throw new Exception("引数の指定が不正です")
            }
        } catch {
            case e:IllegalArgumentException => printf("例外発生(「%s」)\n", e.getMessage)
            case e => e.printStackTrace
        } finally {
            println("例外の発生如何に関わらず実行")
        }
    }
}

以下のjavaの投稿を参考に、
groovy風に書き換えてみました。

どう書く?org 8769 nattou_curry: javaではtry-catch-fina...(例外処理) - 投稿の詳細 <http://ja.doukaku.org/comment/8769/>
1
2
3
4
5
6
7
8
try {
    throw new Exception()
} catch ( e ) {
    println( "例外が発生しました。" )
    e.printStackTrace()
} finally {
    println( "必ず実行されます。" )
}

Smalltalk では、例外処理は #on:do: を、後処理は #ensure: を用います。

1
2
3
4
5
[1/0]
    on: ZeroDivide 
    do: [:ex | Float infinity]   "#=> Infinity"

[self error: 'エラー発生'] ensure: [Transcript cr; show: '必ず実行']

1
2
3
4
5
6
7
8
9
try:
    # 処理本体はここに記述します
    raise Exception("サンプル例外です。")
except Exception, e:
    print "例外が発生しました。(「%s」)" % e
else:
    print "例外が発生しなかった場合に実行されます。"
finally:
    print "例外の発生如何に関わらず実行されます。"

InstallShield Scriptです。

InstallShield Scriptは Windowsアプリケーション用のインストーラーを作成するための
言語ですが、ヘルプを見ていて意外にも(?) 例外処理をサポートしていることに気がつき
ました。

以下はヘルプに載っている内容を手直ししたものですが、この処理だと try ... catchを
利用するメリットは... ありませんよね。(すみません。)

# InstallShield Profesional 7.01でビルドして動作を確認しました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "ifx.h"
#include "ErrorsObj.h"

NUMBER n;
STRING p;

program
    _:
    AskText("ファイルのパスを入力してください。", "", p);

    try
        if (!Is(FILE_EXISTS, p)) then
            Err.Raise(OBJ_STATUS_FILENOTFOUND);
        endif;
        MessageBox("指定されたファイルは存在します。", INFORMATION);
    catch
        n = Err.Number;
        switch (n)
            case OBJ_STATUS_FILENOTFOUND : 
                MessageBox("指定されたファイルは存在しません。", WARNING);
            default : 
                MessageBox(Err.Description, SEVERE);
        endswitch;
    endcatch;

    if (AskYesNo("パスを再入力しますか? ", YES) = YES) goto _;

    abort;
endprogram

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-module(exception).
-export([exception/0]).

f() -> throw("exception").

exception() ->
    X =  try f()
    catch
        throw : Y -> "catch : " ++ Y
    end,
    io:format(X).

Haskellの例外処理は世代がいくつかあるみたいですが、Control.Exceptionのやつを使ってみました…

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
module Main where

import Prelude hiding (catch)
import Control.Exception

thrower :: IO ()
thrower = do
    putStrLn "thrower throws exception"
    throwIO (ErrorCall "can't call this")

catcher :: ErrorCall -> IO ()    
catcher e = putStrLn $ "caught \"" ++ (show e) ++ "\" exception."

main = catch thrower (catcher)

いろいろな例外。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
object ExceptionSample {
  def main(args : Array[String]) : Unit = {
    try{
      val a = Array(1,2,3)
      println (a(5)) // --> java.lang.ArrayIndexOutOfBoundsException
      val f=new java.io.FileReader("\\.txt") // -->java.io.FileNotFoundException
      val re = "[A-Za-0]".r //--> java.util.regex.PatternSyntaxException
      
      ()
    }catch{
      case e:java.io.IOException => println( "IO Err "+e)
      case e:Exception => println ("Err "+e)
      case _ => println ("Unknown error")
    }finally{
      println ("Done")
    }
    
  }
}

F#ではtry~withで例外処理を行えます。
with部分で例外の種類を特定するのにパターンマッチを使用する点が特徴です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#light

open System

exception Original of string * string    // F#例外の定義

type Example() =
    member this.Func() =
        Original("ユーザー定義例外", "例外発生") |> raise
    interface IDisposable with
        member this.Dispose() =
            printfn "資源解放"

try
    use ex = new Example()
    ex.Func()
with
    | :? NullReferenceException as e ->  // .NET例外の捕捉
        printfn "ぬるぽ %s" e.Message
        rethrow()
    | Original(name, msg) ->             // F#例外の捕捉
        printfn "例外名:%s メッセージ:%s" name msg

Index

Feed

Other

Link

Pathtraq

loading...