Paradigmen und Programmierkonzepte: RPG und Java im Vergleich

tiny-tool.de

tiny-tool.de

Die Wahl zwischen IBM RPG (fully free) und Java ist auch eine Entscheidung für ein bestimmtes Programmierparadigma – prozedural oder objektorientiert. In diesem Artikel vergleiche ich zentrale Konzepte und zeige, wie sich typische Anwendungsfälle in beiden Sprachen unterscheiden.

Prozedurale vs. objektorientierte Ansätze

RPG folgt traditionell einem prozeduralen Ansatz, bei dem zentrale Variablen direkt manipuliert werden. Im Vergleich dazu setzt Java auf Objektorientierung, bei der Daten und Funktionen (bei Java spricht man von Methoden) in Klassen gekapselt sind. Diese grundlegenden Unterschiede zeigen sich bereits in einfachen Beispielen wie der Verwaltung eines Bankkontos.

Praxisbeispiele

RPG-Code:

Im gezeigten Beispiel wird der Kontostand in einer globalen Variable balance gespeichert, die direkt von den Prozeduren DEPOSIT und WITHDRAW manipuliert wird. Dieses Vorgehen war in der Vergangenheit weit verbreitet und findet sich auch heute noch häufig in RPG-Code – selbst in der modernen „fully free“-Variante.

Der gezeigte Ansatz verdeutlicht, wie direkter Zugriff auf globale Variablen die Kapselung untergräbt und zu unerwarteten Seiteneffekten führen kann. Statt Rückgabewerte von Prozeduren zu verwenden oder Variablen gezielt zu kapseln, wird hier die zentrale Variable direkt verändert. Der Code dient somit als Beispiel für eine Praxis, die in modernen Programmieransätzen vermieden werden sollte.

RPG DCL-S balance PACKED(7:2) INZ(0); // Speichert den aktuellen Kontostand P DEPOSIT B   DCL-PI *N;     amount PACKED(7:2);   END-PI;   // Fügt den Betrag zum Kontostand hinzu   balance += amount; // Globaler Wert wird direkt geändert. Vermeiden! P DEPOSIT E P WITHDRAW B   DCL-PI *N;     amount PACKED(7:2);   END-PI;   // Zieht den Betrag vom Kontostand ab   balance -= amount; // Globaler Wert wird direkt geändert. Vermeiden! P WITHDRAW E // Prozeduraufrufe DEPOSIT(100.00); // 100 hinzufügen WITHDRAW(50.00); // 50 abheben // Kontostand anzeigen DSPLY 'Aktueller Kontostand: ' + balance; // Gibt den aktuellen Kontostand aus

Dieser Ansatz ist kompakt, birgt jedoch das Risiko von Seiteneffekten, da balance von überall aus geändert werden kann.

Verbesserter RPG-Ansatz:

Moderneres RPG setzt auf Kapselung, um die Datenintegrität zu schützen. Der Zugriff auf balance erfolgt nur über Service-Prozeduren wie GETBALANCE und DEPOSIT:

RPG DCL-S balance PACKED(7:2) INZ(0); // Speichert den aktuellen Kontostand P DEPOSIT B   DCL-PI PACKED(7:2);     amount PACKED(7:2);   END-PI;   RETURN balance + amount; // Fügt den Betrag zum Kontostand hinzu P DEPOSIT E P WITHDRAW B   DCL-PI PACKED(7:2);     amount PACKED(7:2);   END-PI;   RETURN balance - amount; // Zieht den Betrag vom Kontostand ab P WITHDRAW E P GETBALANCE B   DCL-PI PACKED(7:2);   END-PI;   RETURN balance; // Gibt den aktuellen Kontostand zurück P GETBALANCE E // Prozeduraufrufe balance = DEPOSIT(100.00); // 100 einzahlen balance = WITHDRAW(50.00); // 50 abheben balance = GETBALANCE(); // Kontostand abfragen DSPLY 'Aktueller Kontostand: ' + balance; // Gibt den aktuellen Kontostand aus

Die globale Variable wird durch Kapselung vor direktem Zugriff geschützt, was die Integrität der Daten sicherstellt. Anstatt die balance-Variable überall im Code direkt zu manipulieren, wird der Zugriff über klar definierte Prozeduren geregelt. Das erhöht die Wartbarkeit des Codes, da Änderungen an der Implementierung der Prozeduren keinen Einfluss auf andere Teile des Programms haben. Zudem wird das Risiko von Seiteneffekten minimiert, da die Variable nicht versehentlich von anderen Prozeduren oder Funktionen verändert wird.

Java-Code:

In Java wird derselbe Fall durch eine Klasse BankAccount umgesetzt. Die zentrale Idee hinter der Kapselung besteht darin, Daten vor unkontrolliertem Zugriff zu schützen und nur über definierte Schnittstellen – in diesem Fall öffentliche Methoden – zu manipulieren. Die Felder der Klasse sind privat, was verhindert, dass andere Klassen oder Objekte direkten Zugriff auf die Variablen erhalten.

Dieser Ansatz bietet mehrere Vorteile:

  • Datenintegrität: Der Kontostand (balance) kann nur über kontrollierte Methoden wie deposit oder withdraw verändert werden.
  • Erweiterbarkeit: Änderungen an der Implementierung, z. B. das Hinzufügen neuer Regeln oder Berechnungen, können vorgenommen werden, ohne den Aufrufercode zu beeinflussen.
  • Lesbarkeit und Wartbarkeit: Der Code bleibt modular und gut verständlich, da die Logik zur Manipulation der Daten zentral in der Klasse gekapselt ist.
Java public class BankAccount {     private double balance; // Speichert den aktuellen Kontostand     public double deposit(double amount) { // Fügt den Betrag zum Kontostand hinzu         this.balance += amount; // Aktualisiert den Kontostand         return this.balance; // Gibt den neuen Kontostand zurück     }     public double withdraw(double amount) { // Zieht den Betrag vom Kontostand ab         this.balance -= amount; // Aktualisiert den Kontostand         return this.balance; // Gibt den neuen Kontostand zurück     }     public double getBalance() { // Gibt den aktuellen Kontostand zurück         return this.balance;     } } public class Main {     public static void main(String[] args) {         BankAccount account = new BankAccount(); // Erstellt ein neues Konto         account.deposit(200.00); // 200 einzahlen         account.withdraw(50.00); // 50 abheben         double currentBalance = account.getBalance(); // Aktuellen Kontostand abrufen         System.out.println("Aktueller Kontostand: " + currentBalance); // Ausgabe des Kontostands     } }

Diese Struktur schützt vor unkontrollierten Zugriffen und ist einfacher zu erweitern.

Strukturelle Unterschiede

Die Organisation von Code unterscheidet sich in RPG und Java grundlegend. RPG folgt einem prozeduralen Aufbau, der auf unabhängigen Source-Membern basiert, während Java auf einer hierarchischen, objektorientierten Struktur mit Paketen und Klassen aufbaut.

Organisation des Codes

RPG:

In RPG werden Source-Member in sogenannten Source-Dateien organisiert. Jedes Member ist eine eigenständige Einheit und kann Prozeduren, Subroutinen oder Datenstrukturen enthalten:

  • Prozeduren: Logische Operationen werden in klar abgegrenzten Blöcken implementiert.
  • Subroutinen: Kleinere, wiederverwendbare Codeabschnitte innerhalb eines Members.
  • Datenstrukturen und Variablen: Globale oder lokale Datenfelder, die innerhalb des Members genutzt werden.

Ein Beispiel für eine typische RPG-Organisation:

Source-Datei: BANKSRC
Member: DEPOSIT (Prozedur für Einzahlungen)
Member: WITHDRAW (Prozedur für Abhebungen)
Member: BALANCE (Variable für Kontostand)

Java:

Java organisiert Code in einer klaren Hierarchie aus Paketen, Klassen und Methoden. Diese Struktur fördert Modularität und Wiederverwendbarkeit:

  • Pakete: Gruppieren verwandte Klassen (z. B. com.bank).
  • Klassen: Definieren Daten und Verhalten für ein spezifisches Konzept (z. B. BankAccount).
  • Methoden: Enthalten die Logik für spezifische Operationen (z. B. deposit()).

Ein Beispiel für eine typische Java-Organisation:

Paket: com.bank
Klasse: BankAccount
Feld: balance (Kontostand)
Methode: deposit (Einzahlungen)
Methode: withdraw (Abhebungen)

Aufbau eines Programms

RPG:

  • Kontrollspezifikationen
  • Dateispezifikationen
  • Datenbeschreibungen
  • Prozeduren

Java:

  • Paket- und Import-Anweisungen
  • Klassen- und Schnittstellendefinitionen
  • Felder und Konstruktoren
  • Methoden

Vergleich der Ansätze zur Fehlerbehandlung

RPG: In RPG werden Fehler direkt in der Prozedur behandelt, in der sie auftreten. Dies erfolgt meist durch Kontrollstrukturen wie MONITOR und ON-ERROR. Sobald ein Fehler erkannt wird, kann die Prozedur darauf reagieren, ohne dass der Fehler explizit weitergegeben werden muss.

Dieser Ansatz hat Vor- und Nachteile:

  • Vorteile:
    • Die Fehlerbehandlung ist lokal und einfach. Jede Prozedur ist dafür verantwortlich, ihre eigenen Fehler zu handhaben.
    • Die Implementierung ist übersichtlich, da keine zusätzlichen Mechanismen wie das Weiterreichen von Fehlern erforderlich sind.
  • Nachteile:
    • Die Fehlerbehandlung bleibt auf die jeweilige Prozedur beschränkt. Das bedeutet, dass Fehler nicht von einer übergeordneten Prozedur oder einem anderen Kontext behandelt werden können.
    • Es erschwert die Wiederverwendbarkeit und Modularität, da jede Prozedur ihre eigene Fehlerlogik implementieren muss.

Ein typisches Beispiel:

MONITOR;   fileHandle = OPEN(''/path/to/file'': ''O''); // Versucht die Datei zu öffnen ON-ERROR;   DSPLY 'Fehler beim Öffnen der Datei'; // Gibt eine Fehlermeldung aus ENDMON;

Hier wird der Fehler direkt in der gleichen Prozedur abgefangen, in der er auftritt. Es gibt keine Möglichkeit, diesen Fehler an einen anderen Teil des Programms weiterzugeben.

Fehlerbehandlung:
Java verwendet ein flexibles und strukturiertes Exception-Handling-System. Fehler werden in Form von Exceptions geworfen (throw) und können entlang der Aufrufkette weitergereicht werden – bis hin zu einer zentralen Fehlerbehandlung. Das ermöglicht eine saubere, modulare Trennung von Fachlogik und Fehlerreaktion.

In RPG hingegen erfolgt die Fehlersteuerung häufig über Rückgabewerte, globale Fehlerindikatoren oder Statuscodes. Auch wenn moderne Ansätze auf IBM i hier ebenfalls zu mehr Struktur führen können, bleibt die Fehlerbehandlung oft näher an der prozeduralen Logik.

Ein Beispiel für die Weitergabe von Fehlern in Java:

public void readFile(String filePaththrows FileNotFoundException {
    File file = new File(filePath); // Erstellt ein File-Objekt
    Scanner scanner = new Scanner(file); // Öffnet die Datei zum Lesen
    while (scanner.hasNextLine()) {
        System.out.println(scanner.nextLine()); // Gibt die nächste Zeile aus
    }
    scanner.close(); // Schließt den Scanner
}

Hier ist die readFile-Methode nicht dafür verantwortlich, den Fehler zu behandeln, wenn die Datei nicht gefunden wird. Die Methode könnte auch selbst den Fehler behandeln, ähnlich wie es in RPG der Fall ist, jedoch wirft sie die Exception weiter, damit der Fehler von einer anderen Methode behandelt werden kann. Dadurch entsteht mehr Flexibilität:

  • Vorteile:
    • Fehler können auf unterschiedlichen Ebenen behandelt werden, z. B. zentral in einer „Controller“-Schicht.
    • Der Code bleibt modularer, da Methoden nicht mit überflüssiger Fehlerlogik überladen werden müssen.
    • Java erlaubt es, verschiedene Arten von Fehlern gezielt zu behandeln, indem spezifische Exception-Klassen verwendet werden (FileNotFoundException, IOException, etc.).
  • Nachteile:
    • Es ist oft mehr Aufwand erforderlich, da die Fehler entweder weitergegeben oder auf verschiedenen Ebenen behandelt werden müssen.
    • Entwickler müssen sicherstellen, dass wichtige Fehler nicht unbehandelt bleiben.

Vergleich der Ansätze

  • Direkte Behandlung des Errors (RPG): Einfach und lokal, aber weniger flexibel.
  • Weitergeben der Exception (Java): Flexibler und modularer, ermöglicht zentralisierte Fehlerbehandlung.

Schlusswort

Die Wahl zwischen RPG und Java hängt stark von den Anforderungen und der jeweiligen Projektumgebung ab. RPG überzeugt durch seine enge Integration in die IBM i-Plattform und erlaubt durch den prozeduralen Ansatz eine schnelle, zielgerichtete Umsetzung – besonders bei klar umrissenen Aufgaben in etablierten Unternehmensprozessen.

Java hingegen punktet mit universeller Einsetzbarkeit, objektorientierten Prinzipien und einer hohen Wiederverwendbarkeit. Seine Flexibilität macht es ideal für modulare, skalierbare Systeme und moderne Softwarearchitekturen.

Die Unterschiede – von der Datenkapselung über die Codeorganisation bis zur Fehlerbehandlung – spiegeln unterschiedliche Philosophien wider, wie Softwareprobleme gelöst werden können. Während RPG auf Pragmatismus und Effizienz setzt, bietet Java ein breites Spektrum an Gestaltungsmöglichkeiten.

Am Ende schließen sich die beiden Ansätze nicht aus – sie ergänzen sich. RPG bleibt unschlagbar, wenn es um die robuste Verarbeitung von Daten und Geschäftslogik direkt auf IBM i geht. Java glänzt, wenn komplexe Anwendungen, APIs oder moderne Schnittstellen gefragt sind.

Ich selbst arbeite gern in beiden Welten – RPG und Java. Jede Sprache hat ihre Stärken, und genau das macht die Kombination so spannend. Wer sich auf beide Paradigmen einlässt, erweitert nicht nur sein technisches Repertoire, sondern schafft auch bessere, nachhaltigere Lösungen auf IBM i und darüber hinaus.

Dieser Artikel bietet einen kompakten Überblick über die Unterschiede zwischen RPG und Java und dient als Einstieg in die beiden Programmierwelten. Für eine tiefere Auseinandersetzung und weiterführende Informationen empfehlen wir die folgenden Ressourcen: