достичь catch, когда все в блоке try уже поймано


19

Это ограничено Java и C # синтаксисом, который я предполагаю.

В этой задаче программирования вы должны производить Exceptions, которые могут быть перехвачены, но снова выброшены в конце блока 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

1
Вы можете свободно размещать код до и после моего фрагмента.
user21634

2
Жаль, что это закрыто. У меня есть решение . @Algorithmshark, Michael и Jan Dvorak: это НЕ общий вопрос программирования. Это головоломка, похожая на « Когда жираф не жираф? , Я назначаю это для открытия.
user12205

1
Uhhhhhh, Whaaat ???
TheDoctor

1
@algorithmshark Я бы пошел с суммой длин вставок
user12205

Ответы:


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 , который представляет собой специальное исключение, которое автоматически вызван повторно в конце каждого блока улова (если Thread.ResetAbort()не называется).


20

C # 24 символов

завершает внутренний блок try раньше запланированного, что позволяет мне вызвать исключение за пределами блока try.

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

1
Человек это гений! Почему я не подумал об этом? (Кстати, вы можете сократить его, фактически вызвав исключение, а не выбрасывая исключение? Например int a=1/0;?)
user12205

Тебе int a=там нужно ? Некоторые языки позволяют просто написать выражение1/0
gnibbler

Это не полный рабочий пример, не так ли? Так что 24 символа не в счет ...
Мэтт

13

Ява, 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

@BenM Не беспокойся, и я понимаю, почему ты так считал. Просто в ОП не было указано, какой способ считать, поэтому я решил включить оба.
user12205

Очень умное решение.
Николас Барбулеско

@NicolasBarbulesco Честно говоря, я думаю, что ответ Райана более умный, чем мой. В конце концов, я добавил catchблок после фрагмента, он не сделал.
user12205

3

Предупреждение : Эти программы представляют собой бомбы-клоны (разновидность менее опасной, но все же опасной формы вилочной бомбы); как таковые, не запускайте их в производственной системе без песочницы или ограничений ресурсов . Клонированные бомбы создают потоки в цикле (в отличие от вилочных бомб, которые создают процессы в цикле), таким образом, вы можете остановить их, просто убив рассматриваемый процесс (делая их намного менее опасными, чем вилочные бомбы, что может быть очень трудно проясняться); но они, скорее всего, будут связывать большую часть вашего процессора, пока вам не удастся это сделать (или пока программа не выйдет и не выйдет естественным путем сама). Если ваша операционная система ограничивает объем памяти и процессорного времени, которые эти программы могут использовать, должна создать безопасную среду для их тестирования.

Java (OpenJDK 8) , 65 60 байт (с небольшой модификацией оболочки)

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

Попробуйте онлайн!

Требует, чтобы оба экземпляра catch (Exception …)в вопросе были изменены на catch (Throwable …). Теоретически это должно быть более безопасным, а не менее, но оно позволяет сделать это решение возможным.

Я сохранил 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 было намного меньше функций, и поэтому она была более многословной; у нас не было лямбды, поэтому мне пришлось создать внутренний класс.)

Пояснения

Большинство решений этого вопроса находятся на C # (вместе с решением Java, которое обманывает, используя несбалансированные скобки в качестве формы внедрения кода, и решением Perl, которое также отсутствует в Java). Поэтому я подумал, что стоит попытаться показать, как эта головоломка может быть решена «правильно» и в Java.

Обе программы фактически идентичны (поэтому тот факт, что первая программа работает, дает мне высокую уверенность в том, что вторая программа тоже будет работать, если только я случайно не использовал функцию, отличную от Java-4; Thread#stopв Java 5 она устарела).

Thread#stopМетод Java работает за кулисами, заставляя бросаемый объект бросаться в рассматриваемый поток. Функция throwable предназначена для этой цели ThreadDeathErrorчастности, потому что люди часто пытаются скрыть исключения, а разработчики Java не хотят, чтобы это происходило), хотя она позволяет вам что-либо генерировать (или раньше) в некоторый момент после того, как API был Разработчики 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
Добро пожаловать в Программирование Пазлов и Code Golf! Поскольку этот вопрос является код-гольф вызова, пожалуйста , попробуйте сделать код как можно короче и включает количество символов в верхней части вашего ответа. Благодарность!
ProgramFOX

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, чтобы и там создать интересную загадку. tryЭквивалент Perl вызывается (немного запутанно) evalи определяет исключение, устанавливая @_исключение, если оно произошло, и нулевую строку в противном случае. Таким образом, catchблок реализуется путем сравнения @_с пустой строкой.

Это решение работает путем создания объекта (классом которого является программа в целом; вы можете использовать произвольные файлы Perl, такие как классы, что-то вроде обратного Java (где вы можете использовать произвольные классы, такие как файлы)). Это та bless[]часть, которая blessобычно появляется только глубоко внутри конструкторов, как примитив, который в первую очередь превращает вещи в объекты, но вы можете использовать его напрямую, если действительно хотите; []это распределитель памяти для объекта - конструктор списка, в этом case - и класс не указан, поэтому предполагается, что он выполняется в данный момент). Между тем, мы передаем нашему «классу» (то есть основному файлу) специальный метод сравнения со строкой с помощью use overloadэтого метода и заставляем этот метод генерировать исключение (таким образом выход из цикла и решение головоломки); мы можем поставитьuse overloadв любом месте, и хотя он традиционно будет соответствовать другим определениям методов и приближаться к вершине файла, мы можем поместить его в промежуток, который нам дали, и он все еще работает. (Если мы поместим его в конец файла, мы можем опустить точку с запятой после него, что приведет к 36-байтовому решению, но это, вероятно, обман, так как это зависит от программы, в которой конечная точка с запятой находится в первую очередь, то есть не гарантировано.) На самом деле короче перегрузить операцию stringify и позволить Perl автоматически сгенерировать сравнение строк, чем это было бы, если бы перегрузить сравнение строк напрямую (потому что перегрузка некоторых операторов заставляет вас перегружать и другие операторы).

Теперь все, что нам нужно сделать, это бросить наш объект, используя die. Завершается eval, затем, когда мы пытаемся сравнить $@с пустой строкой (чтобы увидеть, было ли исключение), сравнение выдает другое исключение, и мы избегаем внешнего eval.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.