当try块中的所有内容都已被捕获时达到catch


19

我猜这仅限于Java和C#。

在此编程难题中,您将产生Exception可被捕获但又在catch块末尾再次抛出的。

try
{
    while(true)
        try
        {
            // you are only allowed to modify code between this try { } brackets
        }
        catch(Exception ex2) {  }
}
catch(Exception ex1)
{
    // your goal is to reach this catch block by modifying the code ...
    // in the inner try block above
    // You win if you reach this part and execute on of the following code lines
    Console.WriteLine("You won!"); // for C#
    // Or
    System.out.println("You won!"); // for Java
}

您可以在此代码段之前和之后自由放置代码。

到达外部catch区块的最短代码将获胜。


1
我认为Python也许也可以竞争。
user12205 2014年

1
您可以在代码段之前和之后自由放置代码。
user21634 2014年

2
太糟糕了,它已经关闭了。我有一个解决方案。致@ algorithmshark,Michael和Jan Dvorak:这不是一般的编程问题。这是一个编程难题,类似于什么时候长颈鹿不是长颈鹿?。我提名这个为重新开放。
user12205 2014年

1
啊,哇呀???
TheDoctor 2014年

1
@algorithmshark我将插入的长度之和
user12205

Answers:


24

C#,46(88个样板)

using System;class P{static void Main(){
        try
        {
            while(true)
                try
                {
                    System.Threading.Thread.CurrentThread.Abort();
                }
                catch(Exception ex2) {  }
        }
        catch(Exception ex1)
        {
            // your goal is to reach this catch block by modifying the code ...
            // in the inner try block above
            // You win if you reach this part and execute on of the following code lines
            Console.WriteLine("You won!"); // for C#
        }
}}

Abort()方法引发ThreadAbortException,这是一个特殊的异常,该异常在每个catch块的末尾自动抛出(除非Thread.ResetAbort()被调用)。


20

C# 24个字符

在预期的情况下终止内部try块,使我可以在try块之外引起异常。

}finally{int a=1/0;}try{

1
伙计,这是天才!我为什么没想到呢?(顺便说一句,您能通过实际引发异常而不是引发异常来缩短它吗?例如int a=1/0;?)
user12205 2014年

需要int a=那里吗?某些语言允许您仅编写表达式1/0
gnibbler,2014年

这不是一个完整的工作示例,对吗?因此,这24个字符不算在内...
马特

13

Java,76或31

仅计算对代码的插入,忽略换行。76如果你数了一切我添加的,则为第一行和最后一行,则为31;即仅算int a=1/0;try{}catch(Error e){}

class P{public static void main(String[]A){
try
{
    while(true)
        try
        {
            int a=1/0;try{
        }
        catch(Exception ex2) {  }
}
catch(Exception ex1)
{
    // your goal is to reach this catch block by modifying the code ...
    // in the inner try block above
    // You win if you reach this part and execute on of the following code lines
    //Console.WriteLine("You won!"); // for C#
    // Or
    System.out.println("You won!"); // for Java
}
}catch(Error e){}
}}

糟糕,抱歉,我没有注意您的计数方式。我将更新答案以添加其他计数方法。我认为仅对try块中的字符计数会更好,因为否则我们基本上将比较C#与Java样板。但是,如果有人在try块之外提交具有重要代码的答案(规则允许),则可能会变得复杂。
BenM 2014年

@BenM不用担心,我明白您为什么这样数。只是OP没有指定要计数的方式,所以我认为我会同时包括两者。
2014年

非常聪明的解决方案。
Nicolas Barbulesco

@NicolasBarbulesco说实话,我认为Ryan的回答比我的回答更聪明。毕竟,我在摘要添加了一个catch方块,但他没有。
user12205 2014年

3

警告:这些程序是克隆炸弹(一种不太危险但仍然很危险的叉子炸弹形式);因此,请勿在没有沙箱或资源限制的生产系统上运行它们。克隆炸弹会在一个循环中创建线程(与叉炸弹相反,它会在一个循环中创建进程),因此您可以简单地通过杀死相关进程来停止它们(这使它们比叉炸弹的危险性低得多,这很难做到)清理); 但是它们可能会占用您的大部分CPU,直到您设法这样做为止(或直到​​程序本身赢并自然退出)。要求操作系统对允许使用这些程序的内存量和CPU时间进行限制,应该会创建一个安全的环境来对其进行测试。

Java(OpenJDK 8)65个 60字节(对包装程序进行了少许修改)

Thread x=Thread.currentThread();new Thread(x::stop).start();

在线尝试!

要求catch (Exception …)将问题中的两个实例都更改为catch (Throwable …)。理论上应该是安全,而不是更少,但是它使这种解决方案成为可能。

通过使用方法引用而不是lambda,我在此答案的第一个版本上节省了5个字节。

Java 4,104字节(未经测试,应与原始包装一起使用)

final Thread x=Thread.currentThread();new Thread(){public void run(){x.stop(new Exception());}}.start();

在线尝试!(链接转到Java 8实现,因此无法正常工作)

使用从Java的现代版本中删除的功能,甚至可以解决需要 Exception。可能,至少。(Java 4到目前为止非常老,我不记得它包含和不包含哪些功能。可以看出,那时Java中的功能较少,因此更加冗长;我们没有lambdas,因此我必须创建一个内部类。)

说明

这个问题的大多数解决方案都在C#中(连同通过使用不平衡括号作为代码注入形式作弊的Java解决方案以及Java中也不存在的Perl解决方案)。因此,我认为值得尝试展示如何在Java中“适当”解决这个难题。

这两个程序实际上是相同的(因此,第一个程序可以工作的事实使我很有信心,第二个程序也可以工作,除非我不小心使用了非Java-4功能; Thread#stop很有在Java 5中已弃用)。

Java的Thread#stop方法在后台通过使throwable被抛出到相关线程中而起作用。尽管它允许您抛出任何东西(或习惯于;在API被使用之后的某个时刻),但为此目的而设计的throwable是ThreadDeathError特别是因为人们经常尝试全面捕获异常,而Java的设计师不希望发生这种情况)。在设计时,Java的设计师意识到这是一个非常糟糕的主意,因此删除了直接使用参数的方法版本。当然,即使抛出的版本ThreadDeath也是相当冒险的操作,您几乎无法保证(例如,它可以解决此难题,而“不可能”解决),所以您不应该这样做使用它,但是从Java 8开始,它仍然有效。

该程序通过产生一个新线程,并要求其将异常强制返回主线程来工作。如果幸运的话,它会在我们进入内部catch块之外的某个时间点执行此操作(catch在程序结束之前我们无法逃避外部块,因为周围有一个循环)。因为我们已经方便地添加了循环,所以简单地使用该循环以允许我们继续创建线程是节省字节的,希望它们中的一个最终会达到正确的时间。通常,这似乎会在几秒钟内发生。

(TIO注意:当前版本的TIO倾向于在执行该程序的早期就终止该程序,大概是由于创建了所有线程。它可以在TIO上运行,但不能可靠地运行,因此通常需要进行几次尝试才能完成)获得“您赢了!”输出。)


1

C#

    try
    {
        int i = 0, j = 1, k;

        int flag = 0;
        lbl:
        if (flag == 1)
        {
            k = j / i;
        }

        while (true)
            try
            {
                k = j / i;

            }
            catch (Exception e)
            {
                flag = 1;
                goto lbl;
                //Console.WriteLine("loose");

            }
    }
    catch (Exception e)
    {
        Console.WriteLine("Won");

    }

1
欢迎来到编程难题和代码高尔夫球!由于此问题是对代码高尔夫球的挑战,因此请尝试使代码尽可能短,并在答案的顶部包含字符数。谢谢!
ProgramFOX 2014年

1

Perl 5、37或36字节

eval {
    while (1) {
        eval {

 

use overload'""',sub{die};die bless[]

 

        };
        $@ eq "" or 0;
    }
};
$@ eq "" or print "You won!\n";

在线尝试!

事实证明,这个问题足以将Perl转化为一个有趣的难题。Perl的try等效项称为(有点令人困惑)eval,并通过设置@_为异常(如果发生)来指定一个异常,否则设置为null字符串。这样,catch通过与@_空字符串进行比较来实现一个块。

该解决方案通过创建一个对象来工作(其类是程序的整体;您可以使用诸如类之类的任意Perl文件,有点像Java的相反(您可以使用诸如文件之类的任意类))。这就是这一bless[]部分(bless通常只在构造函数内部深入显示,因为它是将事物首先放入对象的原语,但是如果您确实愿意,可以直接使用它;[]是对象的内存分配器–列表构造函数)情况-并且未提供该类,因此假定该类为当前正在执行的类)。同时,我们通过给予“类”(即主文件)一个自定义的字符串比较方法use overload,并使该方法抛出异常(从而打破循环并解决难题);我们实际上可以把use overload尽管它通常会与其他方法定义一起使用并接近文件的顶部,但我们可以将其放到我们已经给定的空白中,并且仍然可以使用。(如果将其放在文件末尾,则可以省略分号,从而导致一个36字节的解决方案,但这可以说是作弊的,因为它取决于程序的开头是否有分号,即实际上,重载stringify操作并让Perl从中自动生成一个字符串比较要比直接重载字符串比较要短(因为重载某些运算符也使您也重载了其他运算符)要短得多。

现在,我们要做的就是使用抛出对象die。该eval终止,那么当我们试图比较$@为空字符串(查看是否有一个例外),比较抛出另一个异常,我们逃脱外eval

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.