原型图是这样的(下图),要求算出每个月不同的还款方式的明细
废话不多说,代码
package org.com.rsmall.wx.vo;
import org.com.rsmall.db.vo.RepaymentDetailVo;
import java.math.BigDecimal;
import java.util.List;
/**
* 银行还款计算
*/
public class BankRefund {
/**
* 先息后本
* @param money 贷款总额
* @param yearRate 贷款商业利率
* @param months 贷款月数
*/
public static void foreInterest(Double money, Double yearRate, Integer months,List<RepaymentDetailVo> repaymentDetails){
BigDecimal amount = new BigDecimal(money.toString());
BigDecimal monthRate=resBigDecimalMonthRate(yearRate);
BigDecimal interest = monthRate.multiply(amount).setScale(6,BigDecimal.ROUND_HALF_UP);
BigDecimal totalMonthly=new BigDecimal("0");
BigDecimal totalMonthlyCapital=new BigDecimal("0");
BigDecimal totalMonthlyInterest=new BigDecimal("0");
for (int i = 1; i <= months; i++) {
RepaymentDetailVo repaymentDetailVo = new RepaymentDetailVo();
repaymentDetailVo.setPeriods(i+"");
if(months==i){
repaymentDetailVo.setMonthlyCapital(amount.toString());
repaymentDetailVo.setCapitalBalance("0.0000");
repaymentDetailVo.setMonthly(amount.add(interest).toString());
}else {
repaymentDetailVo.setMonthlyCapital("0.0000");
repaymentDetailVo.setCapitalBalance(amount.toString());
repaymentDetailVo.setMonthly(interest.toString());
}
repaymentDetailVo.setMonthlyInterest(interest.toString());
repaymentDetails.add(repaymentDetailVo);
totalMonthly=totalMonthly.add(new BigDecimal(repaymentDetailVo.getMonthly()));
totalMonthlyCapital=totalMonthlyCapital.add(new BigDecimal(repaymentDetailVo.getMonthlyCapital()));
totalMonthlyInterest=totalMonthlyInterest.add(new BigDecimal(repaymentDetailVo.getMonthlyInterest()));
}
RepaymentDetailVo totalRepayment = new RepaymentDetailVo();
totalRepayment.setPeriods("总计");
totalRepayment.setCapitalBalance("---");
totalRepayment.setMonthly(totalMonthly.toString());
totalRepayment.setMonthlyInterest(totalMonthlyInterest.toString());
totalRepayment.setMonthlyCapital(totalMonthlyCapital.toString());
repaymentDetails.add(totalRepayment);
}
/**
* 等额本金还款法【利息少,但前期还的多】
* @param money 贷款总额
* @param yearRate 贷款商业利率
* @param months 贷款月数
*/
public static void principal(Double money, Double yearRate, Integer months,List<RepaymentDetailVo> repaymentDetailVos) {
//月利率
Double monthRate = resDoubleMonthRate(yearRate);
//每月还款本金
Double monthPri = money / months;
//还款总利息
Double totalInterest = (months + 1) * money * monthRate / 2;
//还款总额
Double totalMoney = money + totalInterest;
//第一个月还款金额
Double firstMonth = monthPri + money * monthRate;
//每月利息递减
Double decreaseMonth = monthPri * monthRate;
//总计已还款本金
Double totalCapital=0.00;
//每月利息
Double interest=0.00;
for (int i = 1; i <= months; i++) {
RepaymentDetailVo repaymentDetailVo = new RepaymentDetailVo();
repaymentDetailVo.setPeriods(i + "");
repaymentDetailVo.setMonthlyCapital(monthPri.toString());
//每月利息
if(i==1){
interest=firstMonth-monthPri;
}else {
interest=interest-decreaseMonth;
}
repaymentDetailVo.setMonthlyInterest(interest.toString());
//每月还款总额=每月利息+本金
Double monthly=Double.valueOf(repaymentDetailVo.getMonthlyCapital())+Double.valueOf(repaymentDetailVo.getMonthlyInterest());
repaymentDetailVo.setMonthly(monthly.toString());
totalCapital=totalCapital+monthPri;
//总本金额减去已还款本金为剩余本金
Double capitalBalance=money-totalCapital;
repaymentDetailVo.setCapitalBalance(capitalBalance.toString());
repaymentDetailVos.add(repaymentDetailVo);
}
//最后一条为总计
RepaymentDetailVo rd = new RepaymentDetailVo();
rd.setPeriods("总计");
rd.setMonthlyCapital(money+"");
rd.setMonthly(totalMoney.toString());
rd.setMonthlyInterest(totalInterest.toString());
rd.setCapitalBalance("---");
repaymentDetailVos.add(rd);
}
/**
* 等额本息还款【利息多】
* @param money 贷款总额
* @param rate 贷款商业利率
* @param months 贷款月数
*/
public static void interest(Double money, Double rate, Integer months,List<RepaymentDetailVo> repaymentDetailVos) {
//月利率
Double monthRate = resDoubleMonthRate(rate);
//月还款本息(本金+利息)
Double monthly = (money * monthRate * Math.pow((1 + monthRate), months)) / (Math.pow((1 + monthRate), months) - 1);
//还款总额(本金+利息)
Double totalMoney = monthly * months;
//总利息
Double totalInterest = totalMoney - money;
//总计已还款本金
Double totalCapital=0.00;
for (int i = 1; i <= months; i++) {
RepaymentDetailVo repaymentDetailVo = new RepaymentDetailVo();
repaymentDetailVo.setPeriods(i + "");
repaymentDetailVo.setMonthly(monthly.toString());
//每月本金
Double monthCapital = (money* monthRate.doubleValue() * (Math.pow((1+monthRate.doubleValue()),i-1)))/(Math.pow(1+monthRate.doubleValue(),months)-1);
repaymentDetailVo.setMonthlyCapital(monthCapital.toString());
//每月利息
Double monthlyInterest=monthly-monthCapital;
repaymentDetailVo.setMonthlyInterest(monthlyInterest.toString());
//本金叠加
totalCapital=totalCapital+Double.valueOf(repaymentDetailVo.getMonthlyCapital());
//总本金额减去已还款本金为剩余本金
Double capitalBalance=money-totalCapital;
repaymentDetailVo.setCapitalBalance(capitalBalance.toString());
repaymentDetailVos.add(repaymentDetailVo);
}
//最后一条为总计
RepaymentDetailVo rd = new RepaymentDetailVo();
rd.setPeriods("总计");
rd.setMonthlyCapital(money+"");
rd.setMonthly(totalMoney.toString());
rd.setMonthlyInterest(totalInterest.toString());
rd.setCapitalBalance("---");
repaymentDetailVos.add(rd);
}
/**
* 转换为月利率
* @param rate
* @return
*/
public static BigDecimal resBigDecimalMonthRate(Double rate) {
return new BigDecimal(rate).divide(new BigDecimal("12"),6,BigDecimal.ROUND_HALF_UP).divide(new BigDecimal("100")).setScale(6,BigDecimal.ROUND_HALF_UP);
}
public static Double resDoubleMonthRate(Double rate) {
return rate / (100 * 12);
}
}
package org.com.rsmall.db.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
/**
* @ClassName 还款明细
* @Author yupanpan
* @Date 2020/11/12 16:41
*/
@ToString
public class RepaymentDetailVo {
@ApiModelProperty("期数")
private String periods;
@ApiModelProperty("月供")
private String monthly;
@ApiModelProperty("月供本金")
private String monthlyCapital;
@ApiModelProperty("月供利息")
private String monthlyInterest;
@ApiModelProperty("本金余额")
private String capitalBalance;
public String getPeriods() {
return periods;
}
public void setPeriods(String periods) {
this.periods = periods;
}
public String getMonthly() {
return monthly;
}
public void setMonthly(String monthly) {
this.monthly = new BigDecimal(monthly).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
public String getMonthlyCapital() {
return monthlyCapital;
}
public void setMonthlyCapital(String monthlyCapital) {
this.monthlyCapital = new BigDecimal(monthlyCapital).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
public String getMonthlyInterest() {
return monthlyInterest;
}
public void setMonthlyInterest(String monthlyInterest) {
this.monthlyInterest = new BigDecimal(monthlyInterest).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
public String getCapitalBalance() {
return capitalBalance;
}
public void setCapitalBalance(String capitalBalance) {
if (StringUtils.isNotBlank(capitalBalance)) {
if (capitalBalance.equals("---")) {
this.capitalBalance = capitalBalance;
} else {
if (BigDecimal.ZERO.compareTo(new BigDecimal(capitalBalance)) == 1) {
capitalBalance = "0.00";
}
this.capitalBalance = new BigDecimal(capitalBalance).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
} else {
if (BigDecimal.ZERO.compareTo(new BigDecimal(capitalBalance)) == 1) {
capitalBalance = "0.00";
}
this.capitalBalance = new BigDecimal(capitalBalance).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
}
}
最后的测试结果
和银行的结果全部一致(以下取自招行的计算结果)