简体   繁体   English

Java代码优化-如何优化此remove()函数?

[英]Java code optimization - how can I optimize this remove() function?

I am making a custom language as a project for a class called Compilers. 我正在将自定义语言作为名为Compilers的类的项目。 The whole project is in Java, using JFlex as my lexical analyzer, and Cup as my syntactic analyzer. 整个项目使用Java,使用JFlex作为我的词法分析器,并使用Cup作为我的语法分析器。

I created a simple text editor for the language, which basically consists of a JTextPane, where the user can type the custom code that will be parsed. 我为该语言创建了一个简单的文本编辑器,该编辑器主要由JTextPane组成,用户可以在其中键入将要分析的自定义代码。 This JTextPane has a DefaultStyledDocument, used to set character attributes, eg change the color for keywords, comments, strings, numbers, etc., for the code (text) inside the JTextPane. 此JTextPane具有DefaultStyledDocument,用于设置字符属性,例如,为JTextPane中的代码(文本)更改关键字,注释,字符串,数字等的颜色。

Here is the code I am using: 这是我正在使用的代码:

        DefaultStyledDocument doc = new DefaultStyledDocument() {
        @Override
        public void insertString(int offset, String str, AttributeSet a) throws BadLocationException { //cuando se insertan caracteres.
            super.insertString(offset, str, a);
            String text = getText(0, getLength());
            syntax = new SyntaxHighlighter(new java.io.StringReader(text));
            Token val;
            try {
                while ((val = syntax.yylex()) != null) {
                    switch (val.type) {
                        case TokenType.KEYWORD:
                            setCharacterAttributes(val.start, val.length, keyword, true);
                            break;
                        case TokenType.COMMENT:
                            setCharacterAttributes(val.start, val.length, comment, true);
                            break;
                        case TokenType.STRING:
                            setCharacterAttributes(val.start, val.length, string, true);
                            break;
                        case TokenType.FUNCTION:
                            setCharacterAttributes(val.start, val.length, function, true);
                            break;
                        case TokenType.NUMBER:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                        case TokenType.OPERATOR:
                            setCharacterAttributes(val.start, val.length, operator, true);
                            break;
                        case TokenType.READ:
                            setCharacterAttributes(val.start, val.length, number, true);
                            break;
                        default:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                    }
                }
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(rootPane, "Oops! Exception triggered\n" + ex.getMessage());
            }
        }

        @Override
        //this is the method I want to optimize
        public void remove(int offs, int len) throws BadLocationException { 
            super.remove(offs, len);
            String text = getText(0, getLength());
            syntax = new SyntaxHighlighter(new java.io.StringReader(text));
            Token val;
            try {
                while ((val = syntax.yylex()) != null) {
                    switch (val.type) {
                        case TokenType.KEYWORD:
                            setCharacterAttributes(val.start, val.length, keyword, true);
                            break;
                        case TokenType.COMMENT:
                            setCharacterAttributes(val.start, val.length, comment, true);
                            break;
                        case TokenType.STRING:
                            setCharacterAttributes(val.start, val.length, string, true);
                            break;
                        case TokenType.FUNCTION:
                            setCharacterAttributes(val.start, val.length, function, true);
                            break;
                        case TokenType.NUMBER:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                        case TokenType.OPERATOR:
                            setCharacterAttributes(val.start, val.length, operator, true);
                            break;
                        case TokenType.READ:
                            setCharacterAttributes(val.start, val.length, number, true);
                            break;
                        default:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                    }
                }
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(rootPane, "Oops! Exception triggered\n" + ex.getMessage());
            }
        }
    };

this.codeTextPane.setStyledDocument(doc);

The SyntaxHighlighter class is basically a lexer (made with JFlex) used only as a way to search specific pieces of text (keywords, strings, etc). SyntaxHighlighter类基本上是一个词法分析器(由JFlex制成),仅用作搜索特定文本(关键字,字符串等)的方式。 Everything works perfectly, but... 一切正常,但是...

The problem: 问题:

When the JTextPane has a decent amount of text in it, holding down the backspace key to remove text makes the program lag pretty hard. 当JTextPane中包含大量文本时,按住退格键以删除文本会使程序滞后。 The reason I think this happens is probably because the SyntaxHighlighter runs with every character being removed, because holding down the backspace key calls the remove() function for each character being deleted. 我认为发生这种情况的原因可能是因为SyntaxHighlighter在删除每个字符的情况下运行,因为按住退格键会为要删除的每个字符调用remove()函数。 Inserting text is not a problem really because you can either load the code from a file (where the whole text in that file will be analyzed by the SyntaxHighlighter as a whole), or you just can't type fast enough to notice the lag. 插入文本并不是真正的问题,因为您可以从文件中加载代码(该文件中的整个文本将由SyntaxHighlighter整体进行分析),或者您输入的速度不够快而无法注意到滞后。

Is there a way I can optimize this? 有办法优化吗? Thank you all! 谢谢你们!

My first instinct would be to employ a windowing strategy. 我的第一个直觉是采用窗口化策略。 In your code maintain a tree or some other structure capable of representing self-contained scope. 在您的代码中,维护一棵树或其他能够表示自包含范围的结构。 Then adapt the syntax highlighter and other parts of the code to work only on the parts of the tree (or whatever) they know are affected. 然后,修改语法突出显示部分和代码的其他部分,使其仅在他们知道受影响的树的部分(或任何其他部分)上起作用。

Abstractly, you might have a relationship like this: 抽象地,您可能具有如下关系:

class
  |
+----------+
method1    method2
              |
           +--------+--------+
           line1    line2    line3

... which allows a delete in line3 to be understood in the context of what doesn't change ...允许在不改变的情况下理解第3行中的删除

All in all this code seems to be structured and clear I understood it very fast. 总而言之,这些代码似乎是结构化的,而且很清楚,我理解得非常快。 So my suggestion: leave it as it is as long as possible (forcing open-closed principle). 因此,我的建议是:将其保留为尽可能长的时间(强制采用开闭原则)。

The only change I would suggest is to separate character removal from highlighting. 我建议的唯一更改是将字符删除与突出显示分开。 This was already mentioned. 已经提到过了。 But the reason why you should do this is: You will be able to delay syntax highlighting until the user has remove a chunk of characters. 但是,您应该这样做的原因是:您将能够延迟语法突出显示,直到用户删除了大部分字符为止。 So syntax highlighting will not be trigerred every time you remove only one char. 因此,每次只删除一个字符时,不会突出显示语法突出显示。

I think you should break apart the main text into syntactical units and then apply the syntax highlighting only on changed syntactical units. 我认为您应该将正文分成句法单元,然后仅在更改的句法单元上应用突出显示的语法。 The main problem is the parsing and the identification of the changed unit. 主要问题是已更改单位的解析和标识。

As a previous author mentioned isolating syntax highlighting into a separated thread will improve performance as well. 正如先前的作者所提到的,将语法高亮隔离到单独的线程中也将提高性能。

These changes are not trivial but possible. 这些变化并非微不足道,但可能的。

Define the class field javax.swing.Timer syntaxTimer . 定义类字段javax.swing.Timer syntaxTimer

On each insert() or remove() check whether the syntaxTimer is null or not. 在每个insert()remove()检查syntaxTimer是否为null。

If it's null create the syntaxTimer instance with 500 msec delay (could be 300 or 1000 as you wish) and start the syntaxTimer . 如果为null,请创建一个延迟500毫秒(可以根据需要设置300或1000)的syntaxTimer实例,然后启动syntaxTimer If not just skip the timer initialization because you already have it initialized. 如果不是,则跳过计时器初始化,因为您已经将其初始化。

When the syntaxTimer 's actionPerformed() is called do your SyntaxHighlighter related logic and clear the syntaxTimer (stop it and set the syntaxTimer=null ). syntaxTimeractionPerformed() ,请执行与SyntaxHighlighter相关的逻辑,并清除syntaxTimer (将其停止并设置syntaxTimer=null )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM