Насколько ресурсоемкими являются Listeners в java?

Я новичок в программировании на Java, но опытный программист на С++. Я учился программировать графические интерфейсы с использованием swing. Мне было интересно, насколько ресурсоемкими (время работы, а также память) являются ActionListeners? Существует ли общее правило для общего числа слушателей, которое нужно создать в конкретной программе? Сколько пока затронута производительность?

В настоящее время я изучаю Java через книгу Deitel Developer Series Java for Programmers. В конкретном примере у них есть массив JRadioButtonItems как приватная переменная для класса. Они также создали класс ItemHandler, расширенный от класса ActionListener, который провел линейный поиск по всему массиву переключателей, чтобы определить тот, который был выбран, и соответствующим образом изменил состояние программы. Все переключатели в массиве совместно используют один и тот же прослушиватель. Это казалось довольно неэффективным для линейного поиска информации, поэтому я переписал класс ActionListener, чтобы принять предложенное значение для модификации в конструкторе и дал каждому переключателю свой собственный ActionListener с предлагаемым значением, переданным конструктором, чтобы избежать делая линейный поиск. Какой метод будет лучше? Я прошу прощения за звучание, как noob, я просто пытаюсь разработать хороший набор привычек для программирования на Java. Приложен небольшой пример кода. Спасибо.

    /************************************************************************
    Original code in Deitel book with linear search of selected Radio button in Actionlistener
    ****************************************************************************/
    import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;


public class MenuTest extends JFrame{
    private final Color colorValues[] = {Color.BLACK, Color.WHITE, Color.GREEN};
    private JRadioButtonMenuItem colorItems[];      
    private ButtonGroup colorButtonGroup;


    public MenuTest(){
        super("Menu Test");
        JMenu fileMenu = new JMenu("File");

        JMenuBar bar = new JMenuBar();
        setJMenuBar(bar);
        bar.add(fileMenu);

        String colors[] = {"Black", "White", "Green"};
        JMenu colorMenu = new JMenu("Color");
        colorItems = new JRadioButtonMenuItem[colors.length];
        colorButtonGroup = new ButtonGroup();

        ItemHandler itemHandler = new ItemHandler();

        for(int count = 0; count < colors.length; count++){
            colorItems[count] = new JRadioButtonMenuItem(colors[count]);
            colorMenu.add(colorItems[count]);
            colorButtonGroup.add(colorItems[count]);
            colorItems[count].addActionListener(itemHandler);
        }

        colorItems[0].setSelected(true);
        fileMenu.add(colorMenu);
        fileMenu.addSeparator();

    }

    private class ItemHandler implements ActionListener{
        public void actionPerformed(ActionEvent event){
            for(int count = 0; count < colorItems.length; count++){
                if(colorItems[count].isSelected()){
                    getContentPane().setBackground(colorValues[count]);
                }
            }
        }
    }


    public static void main(String args[]){
        MenuTest menuFrame = new MenuTest();
        menuFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        menuFrame.setSize(600,400);
        menuFrame.setVisible(true);
        menuFrame.getContentPane().setBackground(menuFrame.colorValues[0]);
    }
}
    /************************************************************************
    My Code redefined version of Deitel w/o linear search in ActionListener
    ************************************************************************/

        import java.awt.Color;
        import java.awt.event.ActionEvent;
        import java.awt.event.ActionListener;

        import javax.swing.ButtonGroup;
        import javax.swing.JFrame;
        import javax.swing.JLabel;
        import javax.swing.JMenu;
        import javax.swing.JMenuBar;
        import javax.swing.JMenuItem;
        import javax.swing.JRadioButtonMenuItem;

        public class MenuTest extends JFrame{
        private final Color colorValues[] = {Color.BLACK, Color.WHITE, Color.GREEN};
        private JRadioButtonMenuItem colorItems[];      
        private ButtonGroup colorButtonGroup;


        public MenuTest(){
            super("Menu Test");
            JMenu fileMenu = new JMenu("File");

            JMenuBar bar = new JMenuBar();
            setJMenuBar(bar);
            bar.add(fileMenu);

            String colors[] = {"Black", "White", "Green"};
            JMenu colorMenu = new JMenu("Color");
            colorItems = new JRadioButtonMenuItem[colors.length];
            colorButtonGroup = new ButtonGroup();

            ItemHandler itemHandler = new ItemHandler();

            for(int count = 0; count < colors.length; count++){
                colorItems[count] = new JRadioButtonMenuItem(colors[count]);
                colorMenu.add(colorItems[count]);
                colorButtonGroup.add(colorItems[count]);
                colorItems[count].addActionListener(new ItemHandler(colorValues[count]));
            }

            colorItems[0].setSelected(true);
            fileMenu.add(colorMenu);
            fileMenu.addSeparator();

        }

        private class ItemHandler implements ActionListener{
            private Color setColor;
            public ItemHandler(Color inColor){
                super();
                setColor = inColor;
            }
            public void actionPerformed(ActionEvent event){
                getContentPane().setBackground(setColor);
                repaint();
            }
        }
        public static void main(String args[]){
            MenuTest menuFrame = new MenuTest();
            menuFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            menuFrame.setSize(600,400);
            menuFrame.setVisible(true);
            menuFrame.getContentPane().setBackground(menuFrame.colorValues[0]);
        }
    }

Ответы

Ответ 1

Использование ЦП: близко к нулю. Слушатели вызываются только при изменении состояния объекта, который они прослушивают. Они действительно не "слушают". Объект, к которому они прослушивают, вызывает их, когда это необходимо. (Примечание: это упрощение)

Использование памяти: чаще всего ActionListener не имеет состояния. Таким образом, общая длительная память - это минимум, необходимый для любого объекта. В вашем примере есть состояние, так как у вас есть поле setColor. Но использование памяти невелико.

IMO, слушатели эффективны, и вы можете использовать столько, сколько хотите.

Ответ 2

Слушатели очень низкие по сравнению с компонентами, к которым они привязаны. Просто иметь сотни слушателей вряд ли будет иметь большое значение для процессора или памяти. Тем не менее, общий объем работы слушателей является более важным. Если вы видите проблему с производительностью, вы можете использовать профилировщик CPU/памяти для определения и оптимизации причины. Это не то, что вам нужно, чтобы беспокоиться о слишком большом авансе.

Ответ 3

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

Для фактических размеров объектов вы можете выполнить анализ влияния конверта. Около 20 байтов объекта. Скажем, у вас есть 10 000 из них, 200K. На 1 ГБ машине, которая составляет 0,02% от вашей памяти компьютеров, идущей на слушателях - я бы не беспокоился об этом на сотовом телефоне.

Больше изображений - сколько классов вы загружаете. Мой эксперимент (на Usenet где-то) дал около 2K накладных расходов для каждого относительно небольшого анонимного внутреннего класса, загруженного. 10 000 из них - 20 МБ. 2% от нашей машины 1 ГБ. Я бы беспокоился об этом для широко распространенного программного обеспечения, но не для нескольких десятков машин в компании или отделе среднего размера. Несмотря на это, важен более важный способ получить программное обеспечение, которое действительно работает и является ремонтопригодным (по-видимому, 85% затрат на разработку программного обеспечения находятся в обслуживании (для некоторого определения), и большинство проектов никогда не доходят до этого).

Получение загруженного кода - относительно дорогостоящая операция. Хотя, к счастью, у нас теперь есть банки, а не открытие нового сокета для выполнения запроса HTTP 1.0 для каждого файла класса (апплеты не запускались - как это произошло?). Тем не менее, строки должны быть просмотрены, метод разрешен, проверен байт-код и т.д. И он все еще интерпретируется для 1500 итераций, прежде чем мы понесем расходы на компилятор.

После того, как вы работаете (он не работает до его производства), поддерживаемое программное обеспечение, вы можете захотеть оценить тонкую настройку (хотя, быть противоречивым, хорошо иметь хедз-ап). Настройте самую медленную часть. С процессорами в ГГц ответ на каждый маленький щелчок мыши имеет тенденцию идти более чем достаточно быстро. Замедление имеет тенденцию быть такими, как открытие нового диалогового окна.

Итак, для нас мы хотим сократить время настройки, но мы можем быть весьма неэффективны при пожаре событий. 50 мс - это время отклика, на которое мы должны стремиться, и на машине с частотой 1 ГГц, которая составляет 20 000 000 циклов (партии!). Таким образом, подходящая стратегия состоит в том, чтобы использовать несколько типов слушателей. Используйте один тип слушателя (возможно, экземпляр), чтобы прослушивать достаточное количество модели. Игнорируйте аргументы события (обычно это хорошая идея для прослушивателя изменений состояния) и проверяйте, что нужно сделать (помните, что у нас много времени).

Я чувствую необходимость повториться здесь. Сделайте свой код приятным. Пойдите для многих входных слушателей (и команд). Слушатели изменения состояния должны игнорировать свои аргументы.

Ответ 4

Я программист Swing с 5 лет. Согласно моему опыту, никогда не бывает проблемой, как могут быть слушатели. Важно отменить регистрацию слушателей, когда они больше не интересуются событиями.

просто помните, что в приложениях с графическим интерфейсом время ответа более важно, чем память. Вы можете быть заинтересованы в моих статьях:

Используйте слабых слушателей, чтобы избежать утечек памяти
Знайте, когда ваш объект получает сбор мусора
Долгоживущие модели могут вызывать утечки памяти

Ответ 5

Помните, что прослушивание - это не то же самое, что ожидание. Слушатель регистрируется в списке заинтересованных сторон через посредственные методы-посредники. В большинстве шаблонов слушателя очень мало теряется процессорное время.

Ответ 6

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

На самом деле не ответив на вопрос, но как только вы ушли так далеко, вы обнаружите, что вы можете уменьшить область применения большинства полей MenuTest в качестве переменных метода в конструкторе.

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

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

В конструкторе он устанавливает выбранный пункт меню, затем в основном методе он обращается к полю colorValues объекта и устанавливает значение фона. Очевидно, что это не удается как для скрытия информации, так и для инкапсуляции.

Если вместо этого вы используете ChangeListener, чтобы проверить, установлен ли элемент меню, как выбранный, тогда у вас нет двух отдельных частей логики для поддержания того же состояния, что и цвет, заданный в ответ на вызов setSelected, и вам не нужно просачивать поле colorValues вызывающему.

for ( int count = 0; count < colors.length; count++ ){
    colorItems[count] = new JRadioButtonMenuItem(colors[count]);
    colorMenu.add(colorItems[count]);
    colorButtonGroup.add(colorItems[count]);

    final Color color = colorValues[count];

    colorItems[count].addChangeListener ( new ChangeListener() {
        public void stateChanged ( ChangeEvent event ){
            if ( ( ( AbstractButton ) event.getSource() ).isSelected () ) 
                getContentPane().setBackground ( color );
        }
    });
}

colorItems[0].setSelected(true);

// no call to setBackgroundColour() in main() 

Вы также можете иметь вторую конечную переменную, чтобы удерживать colorItem и избегать приведения на event.getSource().

Также возможно реализовать прослушиватель изменений, чтобы также прослушивать изменения, задающие цвет фона в кадре, и выбирать соответствующий пункт меню, если цвет изменяется с помощью setBackground().

Вызов setBackground() автоматически помечает панель как поврежденную, поэтому нет необходимости переписывать ее позже.

Ответ 7

Хорошо, рассмотрим самую основную реализацию слушателя: все, что вы делаете, это в основном добавление объекта в список Listeners, не более того. Зарегистрируйте функцию обратного вызова, если хотите. Итак, реализация этой строки:

someObject.addListener(new someAnonymousListener{ ... });

по существу будет:

someListenerList.add(new someAnonymousListener{ ... });

До сих пор никакого вреда не было. Объект просто сидит в списке со всеми другими зарегистрированными слушателями.

Однако заметьте, что происходит, когда событие запускается на объект:

for (SomeListener l : someListenerList) {
    l.doSomeAction();
}

Хлоп. Здесь вы должны быть осторожны. Убедитесь, что ваш слушатель не делает ничего слишком сложного или вы увидите узкое место, которое будет отображаться во время профилирования.

Нижняя строка: просто удерживание слушателя на объекте почти бесплатное. Просто убедитесь, что вы не регистрируете слишком много слушателей, и что каждый из них сохраняет его действия простыми и точными.