Как избежать многократного повторения пустого кода?

Есть условно большой массив (несколько десятков тысяч элементов) и 3 коротких(0-5 элементов). Заранее количество элементов в коротких массивах неизвестно. Необходимо пошагово пройти по большому массиву и, если определенный короткий не пуст, запускать соответствующий ему метод, а если пуст метод не запускается. Схематически код на Java получился такой:

for (String sw: bigMass) {
     if(!shortMass.isEmpty())
          MethodOne();
     if(!shortMass2.isEmpty())
          MethodTwo();
     if(!shortMass3.isEmpty())
          MethodThree();
}

Все работает, но вот если какие-то из коротких массивов пустые - как избавится от проверки на каждом шаге? Нельзя ли после получения данных о коротких массивах спроектировать цикл так, чтобы не было ненужных опросов? Можно решить задачу с помощью фильтров, но тогда большой массив будет сканироваться неоднократно, пусть от фильтра к фильтру он и будет уменьшаться.


Ответы (2 шт):

Автор решения: Максим
  1. Можно вынести вычисление isEmpty за цикл, даст совершенно незначительную экономию, так как этот метод не тяжелый:
var sm1 = !shortMass.isEmpty();
var sm2 = !shortMass2.isEmpty();
var sm3 = !shortMass3.isEmpty();
for (String sw: bigMass) {
     if(sm1)
          MethodOne();
     if(sm2)
          MethodTwo();
     if(sm3)
          MethodThree();
}
  1. Можно сделать отдельные циклы для каждой из ситуаций получиться 6 блоков:
var sm1 = !shortMass.isEmpty();
var sm2 = !shortMass2.isEmpty();
var sm3 = !shortMass3.isEmpty();

if(sm1 && !sm2 && !sm3){
    for (String sw: bigMass) {
         MethodOne();
    }
}
if(!sm1 && sm2 && !sm3){
    for (String sw: bigMass) {
         MethodTwo();
    }
}
if(!sm1 && !sm2 && sm3){
    for (String sw: bigMass) {
         MethodThree();
    }
}
if(sm1 && sm2 && !sm3){
    for (String sw: bigMass) {
         MethodOne();
         MethodTwo();
    }
}
if(!sm1 && sm2 && !sm3){
    for (String sw: bigMass) {
         MethodTwo();
         MethodThree();
    }
}
if(sm1 && !sm2 && sm3){
    for (String sw: bigMass) {
         MethodOne();
         MethodThree();
    }
}
if(sm1 && sm2 && sm3){
    for (String sw: bigMass) {
         MethodOne();
         MethodTwo();
         MethodThree();
    }
}

Оптимальнее не куда, но читаемость приноситься в жертву.

Похоже вы пытаетесь оптимизировать, то что не требует оптимизации.

→ Ссылка
Автор решения: Nowhere Man

Создаёте "список" методов с учётом их сигнатур, который заполняется в зависимости от пустоты соответствующих массивов и вызываете каждый метод во вложенном цикле / при помощи forEach:

private List<Runnable> fillMethodList() {
    List<Runnable> methods = new ArrayList<>();

    if (!shortMass1.isEmpty()) methods.add(this::Method1);
    if (!shortMass2.isEmpty()) methods.add(this::Method2);
    if (!shortMass3.isEmpty()) methods.add(this::Method3);

    return methods;
}

List<Runnable> methods = fillMethodList();

for (String sw: bigMass) {
    methods.forEach(Runnable::run);
}

Если понадобится передавать параметр sw внутрь методов Method1(String s), следует использовать Consumer<String> вместо Runnable.

private List<Consumer<String>> fillConsumerList() {
    List<Consumer<String>> methods = new ArrayList<>();

    if (!shortMass1.isEmpty()) methods.add(this::consume1);
    if (!shortMass2.isEmpty()) methods.add(this::consume2);
    if (!shortMass3.isEmpty()) methods.add(this::consume3);

    return methods;
}

    List<Consumer<String>> methods = fillConsumerList();
    String[] bigMass = {"a", "b"};

    for (String sw: bigMass) {
        methods.forEach(action -> action.accept(sw));
    }
→ Ссылка