Skip to content

Technik Blog

Programmieren | Arduino | ESP32 | MicroPython | Python | Raspberry Pi | Raspberry Pi Pico

Menu
  • Smarthome
  • Arduino
  • ESP32 & Co.
  • Raspberry Pi & Pico
  • Solo Mining
  • Über mich
  • Deutsch
  • English
Menu

Quellcode Optimierung

Posted on 14. Juli 20142. Mai 2023 by Stefan Draeger

Das Thema Quellcode Optimierung geht „Hand in Hand“ mit dem Thema Clean Code Development. Denn wenn ich sauberen Code schreibe, dann ist die Chance groß das dieser auch performant ist, da ich in der Regel mich von Ballast getrennt habe.

  • java.lang.String
  • java.util.Date
  • java.util.Calendar
  • java.text.SimpleDateFormat
  • Boxing und Unboxing
  • Map

java.lang.String

Verwendet man Strings so werden diese in den sogenannten StringPool abgelegt, dieser StringPool ist eine Map<string,string> welche zur gesammten laufzeit der Anwendung existiert und für jeden Thread gleichbleibend ist.

Nehmen wir folgendes kleines Beispiel:

public class Test {

	private static final String HALLO = "Hallo Welt!";

	private void test() {
		String test = "Hallo Welt!";
		System.out.println("test() ->" + (HALLO == test));
	}

	private void testThread() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				String test = "Hallo Welt!";
				System.out.println("testThread() ->" + (HALLO == test));
			}

		}).start();
	}

	public static void main(String... args){
		new Test().test();
		new Test().testThread();
	}
}

wie wird das Ergebnis sein ?

test() ->true
testThread() ->true

Was uns gleich zu der ersten Optimierungsmöglichkeit bringt , werden Strings häufig verwendet, so sollten diese explizit „private static final“ sein.

String.split, String.matches, String.replaceAll, String.replaceFirst

Sollten Sie Strings verändern wollen und dazu Reguläreausdrücke (RegEx) verwenden wollen, so empfiehlt es sich die Klassen Matcher und Pattern dazu zu verwenden da diese sicherer im Umgang mit Regulärenausdrücken sind.
Es ist erwiesen, dass ein per Handgeschriebenes ersetzten um den Faktor 10 langsamer ist als mit den Matcher und Pattern Klassen.

java.util.Date

Die Klasse java.util.Date sollte nur in ausnahmefällen verwendet werden da diese nur eine Wrapperklasse für den Timerstamp „long“ darstellt.

java.util.Calendar

Für die Berechnung und Verarbeitung von Datumsangaben sowie die Internationalisierung von denen ist die Klasse java.util.Calender bestens geeignet jedoch erzeugt die schon bei der Erstellung einen riesen Overhead an Speicherbedarf ohne das ein Zugriff auf eine Funktion erfolgt ist.

java.text.SimpleDateFormat

Das Formatieren und Parsen von Datums werten übernimmt die Klasse java.text.SimpleDateFormat.
Für die Verwendung sollte man beachten das, wenn diese Klasse mehrmals verwendet wird ein Aufruf erfolgen sollte, denn das Erstellen dieser Klasse benötigt schon eine Menge Zeit und Ressourcen.

Hierzu auch ein kleines Beispiel:

public class SimpleDateFormatBeispiel {

	private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy");

	private void test() {
		long before = System.currentTimeMillis();
		for (long i = 0L; i < 10000; i++) {
			DATE_FORMAT.format(new Date(i));
		}
		long after = System.currentTimeMillis();
		System.out.println("test() -> Zeit:" + (after - before) + " ms.");
	}

	private void testNewInstance() {
		long before = System.currentTimeMillis();
		for (long i = 0L; i < 10000; i++) {
			SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
			dateFormat.format(new Date(i));
		}
		long after = System.currentTimeMillis();
		System.out.println("testNewInstance() -> Zeit:" + (after - before) + " ms.");
	}

	public static void main(String... args) {
		new SimpleDateFormatBeispiel().test();
		new SimpleDateFormatBeispiel().testNewInstance();
	}
}

Sicherlich ist das Beispiel etwas überzogen, da, jeder vernünftige Programmierer von selbst darauf kommen würde, jedoch kommt es in einer Batchverarbeitung schon einmal ungewollt zu so einem Ergebnis.

Hier noch zur Vollständigkeit die Ausgabe welche auch keine Überraschung darstellt:

test() -> Zeit:176 ms.
testNewInstance() -> Zeit:332 ms.

Boxing und Unboxing

Wenn man von einer Wrapperklasse zbsp. Integer den primitiven Datentyp int haben möchte oder umgekehrt so ist das in Java relativ einfach da dieses Boxing bzw. unboxing übernommen wird wir brauchen nur:

int a = new Integer(12);

schreiben.

Hier nun ein Beispiel :

public class BoxingUnboxing {

	private void boxing(){
		Integer a = 12;
	}

	private void unBoxing(){
		int a = new Integer(12);
	}

	private void strToIntSlow(){
		long before = System.nanoTime();
		int a = Integer.valueOf("12");
		long after = System.nanoTime();
		System.out.println("strToIntSlow() -> Zeit:" + (after - before) + " ns.");
	}

	private void strToIntFast(){
		long before = System.nanoTime();
		int a = Integer.parseInt("12");
		long after = System.nanoTime();
		System.out.println("strToIntFast() -> Zeit:" + (after - before) + " ns.");
	}

	public static void main(String... args){
		new BoxingUnboxing().boxing();
		new BoxingUnboxing().unBoxing();

		new BoxingUnboxing().strToIntSlow();
		new BoxingUnboxing().strToIntFast();
	}
}

Wie zuerkennen ist muss hier mit „System.nanoTime();“ gearbeitet werden da dieser Vorgang schon relativ schnell ist. Jedoch die Summe aus dem ganzen ist doch schon erschreckend :

strToIntSlow() -> Zeit:15971 ns.
strToIntFast() -> Zeit:5436 ns.

An diesem Beispiel kann man gut erkennen, was das „einfache“ verwenden einer anderen Methode schon bewirken kann.

java.util.Map

Contains vrs. get & null Check

Hat man eine Map mit vielen Einträgen, so kann man, wenn man einen Eintrag sucht die Methode „contains(Object key)“ verwenden, jedoch ist es effizienter einen wahrscheinlich vorhandenen Wert zu holen und diesen auf NULL zu prüfen.

Hierzu ein „kleines“ Beispiel:

public class MapContainsBeispiel {

	private static final Map<integer, string=""> ORTE = new HashMap<integer, string="">();

	static {
		ORTE.put(38364, "Schöningen");
		ORTE.put(39576, "Stendal");
		ORTE.put(38152, "Nienburg/Weser");
		ORTE.put(38144, "Braunschweig");
		ORTE.put(38446, "Wolfsburg");
		ORTE.put(16259, "Altreetz");
		ORTE.put(76707, "Hambrücken");
		ORTE.put(19273, "Amt Neuhaus");
		ORTE.put(49451, "Holdorf");
		ORTE.put(26180, "Rastede");
		ORTE.put(26215, "Wiefelstede");
		ORTE.put(48527, "Nordhorn");
	}

	private void testContains() {
		long before = System.nanoTime();
		boolean result = ORTE.containsKey(39576);
		long after = System.nanoTime();
		System.out.println("testContains() -> Zeit:" + (after - before) + " ns.");
	}

	private void testGetNullCheck() {
		long before = System.nanoTime();
		String result = ORTE.get(39576);
		if (result != null){
			//tue etwas
		}
		long after = System.nanoTime();
		System.out.println("testGetNullCheck() -> Zeit:" + (after - before) + " ns.");
	}

	public static void main(String... args) {
		new MapContainsBeispiel().testContains();
		new MapContainsBeispiel().testGetNullCheck();
	}
}

Möchte man nun nach einem ORT anhand der Postleitzahl suchen, so ergibt sich folgendes Ergebnis :

testContains() -> Zeit:8155 ns.
testGetNullCheck() -> Zeit:6457 ns.

Auch hier spricht das Ergebnis für sich selbst, auch wenn es nur in Nanosekunden Bereich sind so ist doch die Summe des ganzen zu betrachten.

TMap

Wenn man ein Map instaziiert so belegt diese schon einige KiloByte an Speicherplatz obwohl noch keine Werte vorhanden sind, möchte man dieses „Problem“ lösen so kann man auf das externe Paket Trove4J zurückgreifen.

Dieses Paket hat so ziemlich alle Collections, Sets und Maps implementiert und das ganze sehr Speicherfreundlich umgesetzt.

Schreibe einen Kommentar Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Fragen oder Feedback?

Du hast eine Idee, brauchst Hilfe oder möchtest Feedback loswerden?
Support-Ticket erstellen

Newsletter abonnieren

Bleib auf dem Laufenden: Erhalte regelmäßig Updates zu neuen Projekten, Tutorials und Tipps rund um Arduino, ESP32 und mehr – direkt in dein Postfach.

Jetzt Newsletter abonnieren

Unterstütze meinen Blog

Wenn dir meine Inhalte gefallen, freue ich mich über deine Unterstützung auf Tipeee.
So hilfst du mit, den Blog am Leben zu halten und neue Beiträge zu ermöglichen.

draeger-it.blog auf Tipeee unterstützen

Vielen Dank für deinen Support!
– Stefan Draeger

Kategorien

Tools

  • Unix-Zeitstempel-Rechner
  • ASCII Tabelle
  • Spannung, Strom, Widerstand und Leistung berechnen
  • Widerstandsrechner
  • 8×8 LED Matrix Tool
  • 8×16 LED Matrix Modul von Keyestudio
  • 16×16 LED Matrix – Generator

Links

Blogverzeichnis Bloggerei.de TopBlogs.de das Original - Blogverzeichnis | Blog Top Liste Blogverzeichnis trusted-blogs.com

Stefan Draeger
Königsberger Str. 13
38364 Schöningen

Tel.: 01778501273
E-Mail: info@draeger-it.blog

Folge mir auf

  • Impressum
  • Datenschutzerklärung
  • Disclaimer
  • Cookie-Richtlinie (EU)
©2025 Technik Blog | Built using WordPress and Responsive Blogily theme by Superb
Cookie-Zustimmung verwalten
Wir verwenden Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wir tun dies, um das Surferlebnis zu verbessern und um personalisierte Werbung anzuzeigen. Wenn Sie diesen Technologien zustimmen, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn Sie Ihre Zustimmung nicht erteilen oder zurückziehen, können bestimmte Funktionen beeinträchtigt werden.
Funktional Immer aktiv
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Vorlieben
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Statistiken
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt. Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Marketing
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Optionen verwalten Dienste verwalten Verwalten von {vendor_count}-Lieferanten Lese mehr über diese Zwecke
Einstellungen anzeigen
{title} {title} {title}