Heim > Java > javaLernprogramm > Wie optimiert man Java-Code und welche praktischen Tipps gibt es für die Arbeit?

Wie optimiert man Java-Code und welche praktischen Tipps gibt es für die Arbeit?

王林
Freigeben: 2023-05-09 08:16:07
nach vorne
1244 Leute haben es durchsucht

1. Minimieren Sie die Sichtbarkeit von Klassenmitgliedern und Methoden.

Beispiel: Wenn es sich um eine private Methode handelt, löschen Sie sie, wenn Sie sie löschen möchten.

Wenn es sich um einen öffentlichen Dienst handelt Methode oder eine öffentliche Mitgliedsvariable löschen, ohne groß darüber nachzudenken. publicservice方法,或者一个public的成员变量,删除一下,不得思考很多。

2.使用位移操作替代乘除法

计算机是使用二进制表示的,位移操作会极大地提高性能。

> 右移相当于除以 2;

>>> 无符号右移相当于除以 2,但它会忽略符号位,空位都以 0 补齐。

a = val << 3;
b = val >> 1;
Nach dem Login kopieren

3.尽量减少对变量的重复计算

我们知道对方法的调用是有消耗的,包括创建栈帧、调用方法时保护现场,恢复现场等。

//反例
for (int i = 0; i < list.size(); i++) {
  System.out.println("result");
}
//正例
for (int i = 0, length = list.size(); i < length; i++) {
  System.out.println("result");
}
Nach dem Login kopieren

list.size()很大的时候,就减少了很多的消耗。

4.不要捕捉RuntimeException

RuntimeException 不应该通过 catch 语句去捕捉,而应该使用编码手段进行规避。

如下面的代码,list 可能会出现数组越界异常。

是否越界是可以通过代码提前判断的,而不是等到发生异常时去捕捉。

提前判断这种方式,代码会更优雅,效率也更高。

public String test1(List<String> list, int index) {
    try {
        return list.get(index);
    } catch (IndexOutOfBoundsException ex) {
        return null;
    }
}
//正例
public String test2(List<String> list, int index) {
    if (index >= list.size() || index < 0) {
        return null;
    }
    return list.get(index);
}
Nach dem Login kopieren

5.使用局部变量可避免在堆上分配

由于堆资源是多线程共享的,是垃圾回收器工作的主要区域,过多的对象会造成 GC 压力,可以通过局部变量的方式,将变量在栈上分配。这种方式变量会随着方法执行的完毕而销毁,能够减轻 GC 的压力。

6.减少变量的作用范围

注意变量的作用范围,尽量减少对象的创建。

如下面的代码,变量 s 每次进入方法都会创建,可以将它移动到 if 语句内部。

public void test(String str) {
    final int s = 100;
    if (!StringUtils.isEmpty(str)) {
        int result = s * s;
    }
}
Nach dem Login kopieren

7.懒加载策略

尽量采用懒加载的策略,在需要的时候才创建

String str = "月伴飞鱼";
if (name == "公众号") {
  list.add(str);
}
if (name == "公众号") {
  String str = "月伴飞鱼";
  list.add(str);
}
Nach dem Login kopieren

8.访问静态变量直接使用类名

使用对象访问静态变量,这种方式多了一步寻址操作,需要先找到变量对应的类,再找到类对应的变量。

 // 反例
int i = objectA.staticMethod();
 // 正例
int i = ClassA.staticMethod();
Nach dem Login kopieren

9.字符串拼接使用StringBuilder

字符串拼接,使用 StringBuilder 或者 StringBuffer,不要使用 + 号。

//反例
public class StringTest {
    @Test
    public void testStringPlus() {
        String str = "111";
        str += "222";
        str += "333";
        System.out.println(str);
    }
}
//正例
public class TestMain {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("111");
        sb.append("222");
        sb.append(333);
        System.out.println(sb.toString());
    }
}
Nach dem Login kopieren

10.重写对象的HashCode

重写对象的HashCode,不要简单地返回固定值

有同学在开发重写 HashCode 和 Equals 方法时,会把 HashCode 的值返回固定的 0,而这样做是不恰当的

当这些对象存入 HashMap 时,性能就会非常低,因为 HashMap 是通过 HashCode 定位到 Hash 槽,有冲突的时候,才会使用链表或者红黑树组织节点,固定地返回 0,相当于把 Hash 寻址功能无效了。

11.HashMap等集合初始化

HashMap等集合初始化的时候,指定初始值大小

这样的对象有很多,比如 ArrayList,StringBuilder 等,通过指定初始值大小可减少扩容造成的性能损耗。

初始值大小计算:

Wie optimiert man Java-Code und welche praktischen Tipps gibt es für die Arbeit?

12.循环内创建对象引用

循环内不要不断创建对象引用

//反例
for (int i = 1; i <= size; i++) {
    Object obj = new Object();    
}
//正例
Object obj = null;
for (int i = 0; i <= size; i++) {
    obj = new Object();
}
Nach dem Login kopieren

第一种会导致内存中有size个Object对象引用存在,size很大的话,就耗费内存了

13.遍历Map 使用 EntrySet 方法

使用 EntrySet 方法,可以直接返回 set 对象,直接拿来用即可;而使用 KeySet 方法,获得的是key 的集合,需要再进行一次 get 操作,多了一个操作步骤,所以更推荐使用 EntrySet 方式遍历 Map。

Set<Map.Entry<String, String>> entryseSet = nmap.entrySet();
for (Map.Entry<String, String> entry : entryseSet) {
    System.out.println(entry.getKey()+","+entry.getValue());
}
Nach dem Login kopieren

14.不要在多线程下使用同一个 Random

Random 类的 seed 会在并发访问的情况下发生竞争,造成性能降低,建议在多线程环境下使用 ThreadLocalRandom 类。

 public static void main(String[] args) {
        ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
        Thread thread1 = new Thread(()->{
            for (int i=0;i<10;i++){
                System.out.println("Thread1:"+threadLocalRandom.nextInt(10));
            }
        });
        Thread thread2 = new Thread(()->{
            for (int i=0;i<10;i++){
                System.out.println("Thread2:"+threadLocalRandom.nextInt(10));
            }
        });
        thread1.start();
        thread2.start();
    }
Nach dem Login kopieren

15.自增推荐使用LongAddr

自增运算可以通过 synchronized volatile 的组合来控制线程安全,或者也可以使用原子类(比如 AtomicLong)。

后者的速度比前者要高一些,AtomicLong 使用 CAS 进行比较替换,在线程多的情况下会造成过多无效自旋,可以使用 LongAdder 替换 AtomicLong 进行进一步的性能提升。

public class Test {
    public int longAdderTest(Blackhole blackhole) throws InterruptedException {
        LongAdder longAdder = new LongAdder();
        for (int i = 0; i < 1024; i++) {
            longAdder.add(1);
        }
        return longAdder.intValue();
    }
}
Nach dem Login kopieren

16.程序中要少用反射

反射的功能很强大,但它是通过解析字节码实现的,性能就不是很理想。

现实中有很多对反射的优化方法,比如把反射执行的过程(比如 Method)缓存起来,使用复用来加快反射速度。

Java 7.0 之后,加入了新的包java.lang.invoke

2. Verwenden Sie Verschiebungsoperationen anstelle von Multiplikation und Division. 🎜🎜Computer verwenden eine binäre Darstellung, und Verschiebungsoperationen verbessern die Leistung erheblich. 🎜🎜list.size() sehr groß ist, reduziert es den Verbrauch erheblich. 🎜🎜4. RuntimeException nicht abfangen🎜🎜RuntimeException sollte nicht durch Catch-Anweisungen abgefangen, sondern mithilfe von Codierungsmethoden vermieden werden. 🎜🎜Wie im folgenden Code gezeigt, kann in der Liste eine Array-Ausnahme außerhalb der Grenzen auftreten. 🎜🎜Ob es außerhalb der Grenzen liegt, kann im Voraus anhand des Codes beurteilt werden, anstatt darauf zu warten, eine Ausnahme abzufangen, wenn sie auftritt. 🎜🎜Wenn Sie diese Methode im Voraus beurteilen, wird der Code eleganter und effizienter. 🎜rrreee🎜5. Verwenden Sie lokale Variablen, um eine Zuweisung auf dem Heap zu vermeiden. 🎜🎜Da die Heap-Ressourcen von mehreren Threads gemeinsam genutzt werden und der Hauptbereich sind, in dem der Garbage Collector arbeitet, können Sie lokale Variablen verwenden, um Ordnen Sie Variablen auf dem Stapel zu. Auf diese Weise werden die Variablen zerstört, wenn die Methodenausführung abgeschlossen ist, was den Druck auf den GC verringern kann. 🎜🎜6. Reduzieren Sie den Umfang von Variablen🎜🎜Achten Sie auf den Umfang von Variablen und minimieren Sie die Erstellung von Objekten. 🎜🎜Wie im folgenden Code gezeigt, wird die Variable s bei jeder Eingabe der Methode erstellt und kann innerhalb der if-Anweisung verschoben werden. 🎜rrreee🎜7. Versuchen Sie, die Lazy-Loading-Strategie zu verwenden und sie nur bei Bedarf zu erstellen. 🎜rrreee🎜8. Um auf statische Variablen zuzugreifen, verwenden Sie Objekte, um auf statische Variablen zuzugreifen Weitere Schritte: Für Adressoperationen müssen Sie zuerst die der Variablen entsprechende Klasse und dann die der Klasse entsprechende Variable finden. 🎜rrreee🎜9. Verwenden Sie StringBuilder zum String-Spleißen🎜🎜Verwenden Sie zum String-Spleißen StringBuilder oder StringBuffer, verwenden Sie nicht das +-Zeichen. 🎜rrreee🎜10. Schreiben Sie den HashCode des Objekts neu🎜🎜Schreiben Sie den HashCode des Objekts neu, geben Sie nicht einfach einen festen Wert zurück🎜🎜Einige Schüler geben den HashCode-Wert auf einen festen Wert von 0 zurück, wenn sie die überschreibenden Methoden HashCode und Equals entwickeln , und das ist Es ist unangemessen, dies zu tun🎜🎜Wenn diese Objekte in HashMap gespeichert werden, ist die Leistung sehr gering, da HashMap den Hash-Slot über HashCode findet. Bei einem Konflikt wird eine verknüpfte Liste oder ein verwendet Rot-Schwarz-Baum, um die Knoten zu organisieren und sie fest auf 0 zurückzugeben, was einer Ungültigmachung der Hash-Adressierungsfunktion entspricht. 🎜🎜11. Initialisierung von Sammlungen wie HashMap🎜🎜Geben Sie beim Initialisieren von Sammlungen wie HashMap die Anfangswertgröße an🎜🎜Es gibt viele solcher Objekte wie ArrayList, StringBuilder usw. Durch die Angabe der Anfangswertgröße entsteht ein Leistungsverlust Die durch die Ausdehnung verursachten Schäden können reduziert werden. 🎜🎜🎜Berechnung der Anfangswertgröße: 🎜🎜🎜Praktische Codeoptimierung in Java-Arbeit Was sind die Techniken🎜🎜12. Erstellen Sie Objektverweise innerhalb einer Schleife🎜
🎜Erstellen Sie nicht kontinuierlich Objektverweise innerhalb einer Schleife🎜
rrreee🎜Die erste Methode führt dazu, dass große Objektverweise in der vorhanden sind Speicher, Größe Wenn es zu groß ist, wird es Speicher verbrauchen🎜🎜13. Verwenden Sie die EntrySet-Methode, um die Map zu durchlaufen. Mit der EntrySet-Methode können Sie das festgelegte Objekt direkt zurückgeben und es direkt verwenden, während Sie die KeySet-Methode verwenden. Sie erhalten eine Sammlung von Schlüsseln, die ausgeführt werden müssen. Für die Ausführung einer Get-Operation ist ein weiterer Operationsschritt erforderlich. Es wird daher eher empfohlen, die EntrySet-Methode zum Durchlaufen der Karte zu verwenden. 🎜rrreee🎜14. Verwenden Sie nicht dasselbe Random in Multithreads. Der Startwert der Random-Klasse konkurriert beim gleichzeitigen Zugriff, was zu einer verringerten Leistung führt. Es wird empfohlen, die ThreadLocalRandom-Klasse in einer Multithread-Umgebung zu verwenden. 🎜rrreee🎜15. Es wird empfohlen, LongAddr für die automatische Inkrementierung zu verwenden🎜🎜Der automatische Inkrementierungsvorgang kann die Thread-Sicherheit durch die Kombination von synchronized und volatile steuern, oder Sie kann auch atomare Klassen verwenden (z. B. AtomicLong ). 🎜🎜Letzteres ist schneller als ersteres. Wenn es viele Threads gibt, kann es zur weiteren Leistungsverbesserung durch LongAdder ersetzt werden . . 🎜rrreee🎜16. Verwenden Sie weniger Reflexion in Ihrem Programm🎜🎜Reflexion ist sehr leistungsfähig, wird jedoch durch das Parsen von Bytecode implementiert, sodass die Leistung nicht sehr ideal ist. 🎜🎜In Wirklichkeit gibt es viele Optimierungsmethoden für die Reflexion, z. B. das Zwischenspeichern des Reflexionsausführungsprozesses (z. B. Methode) und die Verwendung von Multiplexing zur Beschleunigung der Reflexion. 🎜🎜Nach Java 7.0 wurde ein neues Paket java.lang.invoke und eine neue JVM-Bytecode-Anweisung invokedynamic hinzugefügt, um den direkten Zugriff auf Zielmethoden über Zeichenfolgen von der JVM-Ebene aus zu unterstützen. 🎜

Das obige ist der detaillierte Inhalt vonWie optimiert man Java-Code und welche praktischen Tipps gibt es für die Arbeit?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:yisu.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage