import java.math.BigDecimal; import java.math.MathContext; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.ParseException; import java.time.Month; import java.time.YearMonth; import java.util.Locale; class Darlehenberechner { private static final class Konfiguration { private BigDecimal darlehenswert; private BigDecimal zinssatzReal; private BigDecimal monatlicheRate; private Integer laufzeitJahre; private Integer aktTilgungsfreieZeit; private YearMonth anfangsmonat; private BigDecimal sondertilgungReal; public BigDecimal getDarlehenswert() { return darlehenswert; } public Konfiguration setDarlehenswert(BigDecimal darlehenswert) { this.darlehenswert = darlehenswert; return this; } public BigDecimal getZinssatz() { return zinssatzReal; } public Konfiguration setZinssatzProzent(BigDecimal zinssatzProzent) { this.zinssatzReal = zinssatzProzent.divide(EINHUNDERT, MathContext.DECIMAL128); return this; } public BigDecimal getMonatlicheRate() { return monatlicheRate; } public Konfiguration setMonatlicheRate(BigDecimal monatlicheRate) { this.monatlicheRate = monatlicheRate; return this; } public Integer getLaufzeitJahre() { return laufzeitJahre; } public Konfiguration setLaufzeitJahre(Integer laufzeitJahre) { this.laufzeitJahre = laufzeitJahre; return this; } public Integer getaktTilgungsfreieZeit() { return aktTilgungsfreieZeit; } public Konfiguration setaktTilgungsfreieZeit(Integer aktTilgungsfreieZeit) { this.aktTilgungsfreieZeit = aktTilgungsfreieZeit; return this; } public YearMonth getAnfangsmonat() { return anfangsmonat; } public Konfiguration setAnfangsmonat(YearMonth anfangsmonat) { this.anfangsmonat = anfangsmonat; return this; } public BigDecimal getSondertilgung() { return sondertilgungReal; } public Konfiguration setSondertilgungProzent(BigDecimal sondertilgungProzent) { this.sondertilgungReal = sondertilgungProzent.divide(EINHUNDERT, MathContext.DECIMAL128); return this; } } private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,##0.00", new DecimalFormatSymbols(Locale.GERMAN)); private static final BigDecimal ZWOELF = BigDecimal.valueOf(12); private static final BigDecimal EINHUNDERT = BigDecimal.valueOf(100); private final Integer laufzeitJahre; private final BigDecimal zinssatz; private BigDecimal sondertilgung; private int summeMonate = 0; private BigDecimal aktRestschuld; private BigDecimal aktMonatlicheRate; private BigDecimal aktZinsbetrag; private BigDecimal aktTilgungsbetrag; private Integer aktTilgungsfreieZeit; private YearMonth aktMonat; private BigDecimal jahressummeZinsenKalenderjahr = BigDecimal.ZERO; private BigDecimal jahressummeZinsenKreditjahr = BigDecimal.ZERO; private BigDecimal summeZinsen = BigDecimal.ZERO; private BigDecimal jahressummeTilgungKalenderjahr = BigDecimal.ZERO; private BigDecimal jahressummeTilgungKreditjahr = BigDecimal.ZERO; private BigDecimal summeTilgung = BigDecimal.ZERO; private BigDecimal jahressummeRatenKalenderjahr = BigDecimal.ZERO; private BigDecimal jahressummeRatenKreditjahr = BigDecimal.ZERO; private BigDecimal summeRaten = BigDecimal.ZERO; public static void main(String[] args) throws ParseException { new Darlehenberechner(new Konfiguration() .setDarlehenswert(BigDecimal.valueOf(168_000)) .setZinssatzProzent(BigDecimal.valueOf(3.73)) .setMonatlicheRate(BigDecimal.valueOf(1_500)) .setaktTilgungsfreieZeit(0) .setAnfangsmonat(YearMonth.of(2024, Month.SEPTEMBER)) .setSondertilgungProzent(BigDecimal.valueOf(2.5)) ).berechneWerte(); return; /*new Darlehenberechner(new Konfiguration() .setDarlehenswert(BigDecimal.valueOf(168_000)) .setZinssatzProzent(BigDecimal.valueOf(3.73)) .setMonatlicheRate(BigDecimal.valueOf(1_500)) .setaktTilgungsfreieZeit(0) .setLaufzeitJahre(11) .setAnfangsmonat(YearMonth.of(2024, Month.SEPTEMBER)) ).berechneWerte(); return;*/ /*var konfig = new Konfiguration(); int count = 0; DECIMAL_FORMAT.setParseBigDecimal(true); while (count < args.length) { String arg = args[count]; if (arg.equals("-hilfe")) { System.out.println("-darlehenswert 1000,00 -zinssatz 3,73 -monatlicheRate 30,00 -anfangsmonat 2024-09" + "[-laufzeitJahre 11] [-aktTilgungsfreieZeit 5]"); } if (arg.equals("-darlehenswert")) { count++; konfig.setDarlehenswert((BigDecimal) DECIMAL_FORMAT.parse(args[count])); } if (arg.equals("-zinssatz")) { count++; konfig.setZinssatzProzent((BigDecimal) DECIMAL_FORMAT.parse(args[count])); } if (arg.equals("-sondertilgung")) { count++; konfig.setSondertilgungProzent((BigDecimal) DECIMAL_FORMAT.parse(args[count])); } if (arg.equals("-monatlicheRate")) { count++; konfig.setMonatlicheRate((BigDecimal) DECIMAL_FORMAT.parse(args[count])); } if (arg.equals("-aktTilgungsfreieZeit")) { count++; konfig.setaktTilgungsfreieZeit(Integer.parseInt(args[count])); } if (arg.equals("-laufzeitJahre")) { count++; konfig.setLaufzeitJahre(Integer.parseInt(args[count])); } if (arg.equals("-anfangsmonat")) { count++; konfig.setAnfangsmonat(YearMonth.parse(args[count])); } count++; } new Darlehenberechner(konfig).berechneWerte();*/ } private Darlehenberechner(Konfiguration konfig) { laufzeitJahre = konfig.getLaufzeitJahre(); zinssatz = konfig.getZinssatz(); sondertilgung = konfig.getSondertilgung() != null ? konfig.getSondertilgung().multiply(konfig.getDarlehenswert()) : BigDecimal.ZERO; aktRestschuld = konfig.getDarlehenswert(); aktMonatlicheRate = konfig.getMonatlicheRate(); aktTilgungsfreieZeit = konfig.getaktTilgungsfreieZeit(); aktMonat = konfig.getAnfangsmonat(); } private void berechneWerte() { druckeUeberschrift(); while (laufzeitNichtVorbei()) { erhoeheSummeMonate(); zahleSondertilgung(); berechneBeitragAufteilung(); berechneRestschuld(); druckeAktuelleMonatswerte(); berechneSummen(); druckeJahressumeBedingt(); aktualisiereZeitwerte(); } druckeFinaleSummen(); druckeLaufzeitUndRestschuld(); } private void druckeUeberschrift() { System.out.println("Monat: Rate = Zinsen + Tilgung| Restschuld"); } private boolean laufzeitNichtVorbei() { return (laufzeitJahre == null || summeMonate < (laufzeitJahre * 12)) && aktRestschuld.signum() > 0; } private boolean laufzeitVorbei() { return !laufzeitNichtVorbei(); } private void erhoeheSummeMonate() { summeMonate++; } private void zahleSondertilgung() { if (sondertilgung.signum() == 0) { return; } boolean sondertilgungFaellingErstesJahr = summeMonate < 12 && aktMonat.getMonth() == Month.DECEMBER; if (sondertilgungFaellingErstesJahr || summeMonate > 1 && aktMonat.getMonth() == Month.JANUARY) { aktRestschuld = aktRestschuld.subtract(sondertilgung); System.out.println(aktMonat + ": " + DECIMAL_FORMAT.format(sondertilgung) + " = 0,00 + " + DECIMAL_FORMAT.format(sondertilgung) + " | " + DECIMAL_FORMAT.format(aktRestschuld)); } } private void berechneBeitragAufteilung() { aktZinsbetrag = aktRestschuld.multiply(zinssatz) .divide(ZWOELF, MathContext.DECIMAL128); if (aktMonatlicheRate.compareTo(aktRestschuld) > 0) { aktMonatlicheRate = aktRestschuld.add(aktZinsbetrag); // die letzte Rate ist gleich der Restschuld + Zinsen } aktTilgungsbetrag = aktTilgungsfreieZeit != null && aktTilgungsfreieZeit > 0 ? BigDecimal.ZERO : aktMonatlicheRate.subtract(aktZinsbetrag); } private void berechneRestschuld() { aktRestschuld = aktRestschuld.subtract(aktTilgungsbetrag); } private void druckeAktuelleMonatswerte() { System.out.println(aktMonat + ": " + DECIMAL_FORMAT.format(aktMonatlicheRate) + " = " + DECIMAL_FORMAT.format(aktZinsbetrag) + " + " + DECIMAL_FORMAT.format(aktTilgungsbetrag) + " | " + DECIMAL_FORMAT.format(aktRestschuld)); } private void berechneSummen() { jahressummeZinsenKalenderjahr = jahressummeZinsenKalenderjahr.add(aktZinsbetrag); jahressummeZinsenKreditjahr = jahressummeZinsenKreditjahr.add(aktZinsbetrag); summeZinsen = summeZinsen.add(aktZinsbetrag); jahressummeTilgungKalenderjahr = jahressummeTilgungKalenderjahr.add(aktTilgungsbetrag); jahressummeTilgungKreditjahr = jahressummeTilgungKreditjahr.add(aktTilgungsbetrag); summeTilgung = summeTilgung.add(aktTilgungsbetrag); jahressummeRatenKalenderjahr = jahressummeRatenKalenderjahr.add(aktMonatlicheRate); jahressummeRatenKreditjahr = jahressummeRatenKreditjahr.add(aktMonatlicheRate); summeRaten = summeRaten.add(aktMonatlicheRate); } private void druckeJahressumeBedingt() { boolean kreditjahrVergangen = summeMonate > 1 && summeMonate % 12 == 0 || laufzeitVorbei(); if (kreditjahrVergangen || aktMonat.getMonth() == Month.DECEMBER) { BigDecimal jahressummeZinsen; BigDecimal jahressummeTilgung; BigDecimal jahressummeRaten; String desc; if (kreditjahrVergangen) { jahressummeZinsen = jahressummeZinsenKreditjahr; jahressummeTilgung = jahressummeTilgungKreditjahr; jahressummeRaten = jahressummeRatenKreditjahr; jahressummeZinsenKreditjahr = BigDecimal.ZERO; jahressummeTilgungKreditjahr = BigDecimal.ZERO; jahressummeRatenKreditjahr = BigDecimal.ZERO; desc = "Kreditjahr " + summeMonate / 12; } else { jahressummeZinsen = jahressummeZinsenKalenderjahr; jahressummeTilgung = jahressummeTilgungKalenderjahr; jahressummeRaten = jahressummeRatenKalenderjahr; jahressummeZinsenKalenderjahr = BigDecimal.ZERO; jahressummeTilgungKalenderjahr = BigDecimal.ZERO; jahressummeRatenKalenderjahr = BigDecimal.ZERO; desc = "Kalenderjahr " + aktMonat.getYear(); } System.out.println("Summe " + desc + ":\n" + DECIMAL_FORMAT.format(jahressummeRaten) + " = " + DECIMAL_FORMAT.format(jahressummeZinsen) + " + " + DECIMAL_FORMAT.format(jahressummeTilgung)); } } private void aktualisiereZeitwerte() { aktMonat = aktMonat.plusMonths(1); if (aktTilgungsfreieZeit != null) { aktTilgungsfreieZeit--; } } private void druckeFinaleSummen() { System.out.println("Summe:\n" + DECIMAL_FORMAT.format(summeRaten) + " = " + DECIMAL_FORMAT.format(summeZinsen) + " + " + DECIMAL_FORMAT.format(summeTilgung)); } private void druckeLaufzeitUndRestschuld() { int laufzeitJahreFinal = laufzeitJahre == null ? summeMonate / 12 : laufzeitJahre; int teillaufzeitMonateFinal = summeMonate - (laufzeitJahreFinal * 12); System.out.println("Laufzeit: " + laufzeitJahreFinal + " Jahre " + teillaufzeitMonateFinal + " Monate"); System.out.println("Restschuld: " + DECIMAL_FORMAT.format(aktRestschuld)); } }