Перейти к основному содержанию
`Ctrl`+`K`

# Контроль выполнения: условия, функции и обработка ошибок

В этом разделе описаны основные конструкции управления выполнением кода в JEXL: условные операторы, циклы, методы и функции, обработка ошибок. Материал содержит синтаксис и практические примеры для каждого элемента.

## Условные конструкции и циклы

### Условия if-else

Синтаксис:

    if (условие) {
        // блок кода при true
    } else {
        // блок кода при false
    }

Пример:

    if (order.total > 10000) {
        discount = 0.1;
    } else if (order.total > 5000) {
        discount = 0.05;
    } else {
        discount = 0;
    }

### Тернарный оператор

Синтаксис:

    условие ? значение_если_true : значение_если_false

Пример:

    // Простой пример
    var access = (id >= 18) ? "Разрешено" : "Запрещено";

### Циклы

#### While

Синтаксис:

    while (условие) {
        // действие
    }

Пример:

    // Простой пример
    var i = 0;
    while (i < 10) {
        total++;
        i++;
    }

#### For

При использовании циклов важно понимать область видимости переменных:

- Если итерируемая переменная объявлена с `let` или `const` - она доступна только внутри блока цикла.

- Если переменная объявлена без ключевого слова (неявно) - она ведёт себя как var:

  - Доступна после выполнения цикла.

  - Сохраняет последнее присвоенное значение.

  - Если переменная с таким именем уже существовала, то переменная созданная в цикле затрет значение ранее объявленной переменной.

Способ 1:
Классический C-подобный цикл с индексом.

Синтаксис:

    for (инициализация; условие; шаг) {
        // тело цикла
    }

Пример:

    let x = 0;
    for (let i = 0; i < 10; ++i) {
        x += i
    }
    dialogs.showMessage(toString(x));

Подходит также для массивоподобных структур, где есть доступ по индексу `(array[i])`:

    let x = 0;
    let array = [100, 200, 300];
    for (let i = 0; i < size(array); ++i) {
        x += array[i];
    }

Позволяет гибко управлять индексом коллекции (например, менять шаг i += 2).

Способ 2:

Синтаксис:

    for (let элемент : коллекция) {
        // тело цикла
        // элемент доступен только здесь
    }

Используется для перебора элементов итерируемой структуры (массива, коллекции и т. д.). Итерируемая переменная получает значение каждого элемента на каждой итерации.

    let x = 0;
    let array = [1, 2, 3];
    for (let item : array) {
        x += item;
    }

Переменная item доступна только внутри цикла (если используется `let`).

Способ 3:

Синтаксис:

    for (элемент : коллекция) {
        // тело цикла
        // элемент доступен здесь
    }
    // элемент ДОСТУПЕН и здесь (ведёт себя как var)

Если итерируемую переменную не объявлять никаким ключевым словом(`let`, `const`, `var`), то она будет объявлена как `var`, и будет иметь последнее присвоенное значение.

Пример коллекции:

    let x = 0;
    let array = [1, 2, 3];
    for (item : array) {
        x += item;
    }
    dialogs.showMessage(toString(item)); // Будет выведено значение '3'

- item не объявляется явно — она создаётся неявно и «живёт» после цикла.

- Может привести к неожиданным эффектам, если item уже была определена ранее.

- Обход результатов объектного запроса с преобразованием в список.

      var l= toJRops(Btk_SomeEntityApi.byParent(rop)).asList()
      for(r:l){
          logInfo(r.id);
          logInfo(r.sSystemName)
      }

Пример множества:

    var mvStock = {"P-1001", "P-1002", "P-1003"};
    for(item : mvStock) {
        dialogs.showMessage(item);
    }

Пример карты:

    var mvStock = {"P-1001" : 1, "P-1002" : 2, "P-1003" : 3};
    for(item : mvStock) {
        dialogs.showMessage(item); // Здесь item это значения словаря по ключу
    }

#### Foreach

Синтаксис:

    коллекция.foreach(элемент -> {
        // действия с элементом
    });

В JEXL оператор `foreach` используется исключительно для функционального подхода, когда данные поступают в виде потока (например, из SQL-запроса или коллекции).

Ключевые особенности:

- потоковая обработка;

- нет возвращаемого значения.

Пример:

    sql("SELECT name FROM users").foreach(row -> {
        logInfo("User: " + row.name);
    });

## Вызов методов и функций в JEXL

### Базовый вызов методов

Синтаксис:

    объект.метод(параметры)

Пример:

    dialogs.showMessage(ropvInvoice);
    dialogs.showMessage(toString(ropvInvoice.nsum));

Поддерживается цепочка вызовов:

    sheet.getRow(0).getCell(1)

### Определение пользовательской функции

Синтаксис:

    function имяФункции(параметры) {
        // тело функции
        результат; // опционально
    }

Пример:

    function calculateSum(a, b) {
        // Тело функции
        a + b; // Возвращаемый результат (неявный return)
    }

    dialogs.showMessage(toString(calculateSum(2, 3)));

### Объявление локальных функций

Синтаксис:

    var fun_LoadInvoiceTemplate = function(x) {
        // Тело функции
        return true;
    };

Пример:

    function test(params) {
        dialogs.showMessage("hello world");
    }

    const FX_DeleteInvisibleSymbolsF = function(sText) {
        var querry = sql(`Select regexp_replace('${sText}', '[\\s\\u200B\\u200C\\u200D\\uFEFF]', '', 'g') as ShortText;`).asSingle();
        return querry.shorttext;
    }

    //--------------------------------------------------------------------------
    //main code block
    //--------------------------------------------------------------------------
    {
        var sCaptionLong = 'А 694 ЕМ 147_2024 12 105'
        var sCaptionFunc = FX_DeleteInvisibleSymbolsF(sCaptionLong);
        dialogs.showMessage('FUNC: '+ sCaptionFunc);
    }

    const FX_DeleteInvisibleSymbolsF = function(sText) {
        var querry = sql(`
            SELECT regexp_replace('${sText}', '[\\s\\u200B\\u200C\\u200D\\uFEFF]', '', 'g') AS ShortText;
        `).asSingle();
        return querry.shorttext;
    }

    //--------------------------------------------------------------------------
    // Main code block
    //--------------------------------------------------------------------------
    {
        var sCaptionLong = 'А 694 ЕМ 147_2024 12 105';
        var sCaptionFunc = FX_DeleteInvisibleSymbolsF(sCaptionLong);
        dialogs.showMessage('FUNC: ' + sCaptionFunc);
    }

## Обработка ошибок

Jexl в ядре не поддерживает исключения, механизм исключений реализован через аннотации.

Синтаксис:

    @begin{
        //code
    }@exception function(e){
        // code
    }

Для бросания исключения можно воспользоваться командой raise: `raise("Текст исключения")`

Внимание

Конструкция `try - catch` не работает. Вместо нее обязательно необходимо использовать `@begin - @exception`.

Пример:

    const ErrorHandler = new java.util.concurrent.atomic.AtomicReference(null); // Объявим обработчик ошибок

    ... // Произвольный блок кода

    var svLogList = ''; // Переменная для лога успешности и ошибок
    ErrorHandler.set(null); // Сбросим обработчик ошибок перед попыткой поймать ошибку

    @begin { // Блок кода, в котором попытаемся поймать ошибку
        ... // Произвольный блок кода
        raise("Текст ошибки"); // Событие, которое вызывает ошибку
    }
    @exception function(vEx1) { // Обработка исключения
        ErrorHandler.set(vEx1); // Сохраняем ошибку в наш обработчик
    }; // Обязательно ставим точку с запятой

    const ErrorCatch = ErrorHandler.get(); // Запросим значение из обработчика

    if (isNotNull(ErrorCatch)) { // Проверяем, была ли ошибка
        svLogList += `\r\n - Ошибка! ${ErrorCatch.getCause().getMessage()}`;
    } else {
        svLogList += `\r\n - Успешно!`;
    }

    dialogs.showMessage(svLogList); // Отображение логов на экране

### Ограничения именованных параметров

В JEXL синтаксис именованных параметров `method(paramName = value)` не работает.

Неверно: `Act_TransDocApi.createBySrc(gidpSrc = aroDoc.gid())`

Верно: `Act_TransDocApi.createBySrc(aroDoc.gid())` — только позиционная передача аргументов в порядке сигнатуры.