Java foreach эффективность

Для справки я создаю пример, используя ваш подход; в то время как он работает, он также предлагает проблему фокуса в другом месте вашего кода. Привязки клавиш избегают этого, как показано здесь здесь .

Приложение: Вот ссылка на мое рабочее ключевое слово.

private static class TestPanel extends JPanel {

    private static final String LEFT = "Left";
    private Action left = new AbstractAction(LEFT) {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println(LEFT);
        }
    };
    private static final String RIGHT = "Right";
    private Action right = new AbstractAction(RIGHT) {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println(RIGHT);
        }
    };

    public TestPanel() {
        this.getInputMap().put(
            KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
        this.getActionMap().put(LEFT, left);
        this.getInputMap().put(
            KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
        this.getActionMap().put(RIGHT, right);
    }
}

Оригинал SSCCE :

import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @see https://stackoverflow.com/a/16531380/230513
 */
public class Test {

    private void display() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new TestPanel());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static class TestPanel extends JPanel implements KeyListener {

        public TestPanel() {

            this.addKeyListener(this);
            this.setFocusable(true);
            this.requestFocusInWindow();
        }

        @Override
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                System.out.println("Right");
            }

            if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                System.out.println("Left");
            }
        }

        @Override
        public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyReleased(KeyEvent e) {
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test().display();
            }
        });
    }
}

22
задан Carl Manaster 30 July 2009 в 09:25
поделиться

6 ответов

If you want to be absolutely certain, then compile it both ways and decompile it and compare. I did this with the following source:

public void test() {
  Map<String, String> myMap = new HashMap<String, String>();

  for (String key : myMap.keySet()) {
    System.out.println(key);
    System.out.println(myMap.get(key));
  }

  Set<String> keySet = myMap.keySet();
  for (String key : keySet) {
    System.out.println(key);
    System.out.println(myMap.get(key));
  }
}

and when I decompiled the class file with Jad, I get:

public void test()
{
    Map myMap = new HashMap();
    String key;
    for(Iterator iterator = myMap.keySet().iterator(); iterator.hasNext(); System.out.println((String)myMap.get(key)))
    {
        key = (String)iterator.next();
        System.out.println(key);
    }

    Set keySet = myMap.keySet();
    String key;
    for(Iterator iterator1 = keySet.iterator(); iterator1.hasNext(); System.out.println((String)myMap.get(key)))
    {
        key = (String)iterator1.next();
        System.out.println(key);
    }
}

So there's your answer. It is called once with either for-loop form.

65
ответ дан 29 November 2019 в 03:18
поделиться

keySet() вызывается только один раз. «Расширенный цикл for» основан на интерфейсе Iterable, который он использует для получения Iterator, который затем используется для цикла. Даже невозможно перебрать Set любым другим способом, так как нет индекса или чего-либо еще, с помощью чего вы могли бы получить отдельные элементы.

Однако, что вы действительно должны сделать, так это полностью отказаться от такого рода проблем микрооптимизации - если у вас когда-либо возникают реальные проблемы с производительностью, вероятность составляет около 99%, что вы никогда не задумывались сами по себе.

9
ответ дан Michael Borgwardt 29 November 2019 в 03:18
поделиться

Звонят только один раз. На самом деле для решения этой задачи используется итератор.

Кроме того, в вашем случае, я думаю, вам следует использовать

for (Map.Entry<String, String> entry : myMap.entrySet())
{
    System.out.println(entry.getKey());
    System.out.println(entry.getValue());
}

, чтобы каждый раз избегать поиска на карте.

35
ответ дан 29 November 2019 в 03:18
поделиться

Да, в любом случае он вызывается только один раз

5
ответ дан 29 November 2019 в 03:18
поделиться

Я считаю, что компилятор оптимизирован для запуска только один раз для каждой записи цикла.

-3
ответ дан 29 November 2019 в 03:18
поделиться

Ответ находится в Спецификации языка Java, декомпилировать не нужно :) Это то, что мы можем прочитать о расширенном операторе for :

Расширенный оператор for имеет форму :

 EnhancedForStatement: 
for (VariableModifiersopt Type Identifier: Expression) Statement 
 

Выражение должно иметь тип Iterable , иначе он должен иметь тип массива (§10.1), иначе возникает ошибка времени компиляции .

Объем локальной переменной, объявленной в части FormalParameter расширенного оператора for (§14.14), является содержащимся в нем оператором

Значение расширенного оператора для дается путем перевода в базовый оператор для .

Если тип Выражения является подтипом Iterable , то пусть I будет типом выражение Выражение. итератор () . Расширенный оператор for эквивалентен базовому оператору for формы :

 for (I #i = Expression.iterator ( ); # i.hasNext ();) {
 
Идентификатор типа VariableModifiersopt = #i.next (); 
Оператор 
} 
 

Где #i - генерируемый компилятором идентификатор , отличный от любого { {1}} другие идентификаторы (генерируемые компилятором или иначе), которые находятся в области действия (§6.3) в точке, где происходит расширенный оператор for .

В противном случае Выражение обязательно имеет тип массива, T [] . Пусть L1 ... Lm будет (возможно, пустой) последовательностью меток, непосредственно предшествующей расширенному оператору для . Тогда значение расширенного оператора for задается следующим основным оператором for :

 T [] a = Expression; {{ 1}} L1: L2: ... Lm: 
for (int i = 0; i 

Где a и i - генерируемые компилятором идентификаторы , отличные от любых {{ 1}} другие идентификаторы (генерируемые компилятором или иначе), которые находятся в области видимости в точке , где происходит расширенный оператор for .

В вашем случае myMap.keySet () возвращает подтип Iterable , поэтому ваш расширенный оператор for эквивалентен следующему базовому для Оператор :

for (Iterator<String> iterator = myMap.keySet().iterator(); iterator.hasNext();) {
   String key = iterator.next();

   System.out.println(key);
   System.out.println(myMap.get(key)); 
}

И myMap.keySet () , таким образом, вызывается только один раз.

7
ответ дан 29 November 2019 в 03:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: