基础篇_开发命令行程序(输入输出,类型、变量、运算符,条件语句,循环语句,方法,package与jar)

文章目录

  • 一. 输入输出
    • 1. System.out
    • 2. System.in
    • 3. Scanner
    • 4. 变量名
    • 5. 关键字
  • 二. 类型、变量、运算符
    • 1. 字符与字符串
      • 字符值与字符串值
      • 转义字符
      • 文本块
    • 2. 类型
      • 何为类型
      • 数字类型
      • 字符类型
    • 3. 变量与运算符
      • 变量
      • 运算符
    • 4. 练习 - 房贷计算器
      • Math.pow()
      • 数字格式化
      • 查阅 Javadoc
  • 三. 条件语句
    • 1. boolean 类型
    • 2. 单条件
    • 3. 多条件
    • 4. 相反条件
  • 四. 循环语句
    • 1. 循环语句语法
    • 2. 变量的作用范围
    • 3. 练习 - 贷款计算详情
  • 五. 方法
    • 1. 定义方法
    • 2. 调用方法
    • 3. 方法的意义
    • 4. 练习 - 贷款计算 - 方法改写
      • 说明1
      • 说明2
      • 说明3
  • 六. package 与 jar
    • 1. package
    • 2. import
    • 3. jar

一. 输入输出

  • 输入的作用,就是由使用者告诉程序要操作的数据
    • 例如,我要通过饿了么订餐,你得告诉程序你要吃什么,送货地址是什么吧
  • 输出的作用,就是由程序向使用者展现执行的结果
    • 还是订餐的例子,程序向你展示骑手接单没有,送到哪里了
  • 将来输入输出来源会有多种,比如 app,网页,终端程序等等

1. System.out

之前已经介绍过【标准输出】:System.out

打开 jshell 用一下,回忆下对象和方法使用格式

对象.方法(参数);

套用一下,对象是 System.out,方法是 println,参数是 “你好”

jshell> System.out.println("你好");
你好

小技巧

  • jshell 中用 Tab 键可以提示对象有哪些方法
  • jshell 中省略 ; 也不会报错

2. System.in

再来看看输入,对象是 System.in,方法叫 read,没有参数

jshell> System.in.read();

运行后,可以看到光标一闪一闪,表示正在等待用户的输入,这时输入小 a

jshell> System.in.read();
a
$1 ==> 97
  • 会显示 97,称之为返回值,代表 read() 读入的结果

    • 因为计算机中所有符号,都是用数字表示,参看下表
  • 前面的 $1 是一个【变量】,将来它就代表 97,也就是刚才输入的小 a

  • 【变量】可以反复被使用

\00010203040506070809101112131415
0000
0016
0032!"#$%&()*+,-./
00480123456789:;<=>?
0064@ABCDEFGHIJKLMNO
0080PQRSTUVWXYZ[\]^_
0096`abcdefghijklmno
0112pqrstuvwxyz{|}~

System.in 的缺点

  1. 字符被转成的数字,不便人类阅读
  2. 只能输入一个字符

3. Scanner

用 Scanner 改进,System.in 是 java 为我们提供好的对象,而 Scanner 需要我们自己创建,语法是

jshell> new Scanner(System.in);
$2 ==> java.util.Scanner...

将来这个 $2 就代表刚才的 Scanner 对象,我们称之为【变量】

Scanner 对象里面最常用的方法是 nextLine,用法如下

jshell> $2.nextLine();
你好啊
$3 ==> "你好啊"

4. 变量名

$2$3 这样作为变量名虽然也可以,但如果用更有意义的名称来表示,更方便人类阅读、记忆。例如

jshell> var scanner = new Scanner(System.in)
scanner ==> java.util.Scanner[delimiters=\p{javaWhitespace}+] ... \E][infinity string=\Q∞\E]jshell> var line = scanner.nextLine()
hello
line ==> "hello"
  • scanner 就代指输入对象
  • line 就代指用 nextLine() 读取到的字符串值
  • var 是关键字,代表某种类型,具体有哪些类型后面再展开

5. 关键字

变量取名时要注意两个规则,不能以数字开头,不能是关键字

什么是关键字呢?关键字就是 java 中有特殊意义的单词,例如见过的有 class,var,new 等等,如果用 idea 中可以通过特殊颜色强调哪些单词是关键字,可以看到这些蓝色的单词都属于关键字

至java 17 为止,共有 67 个关键字,参看这两份表格,这些关键字,都会在今后的课程中陆续学到
在这里插入图片描述

在这里插入图片描述

二. 类型、变量、运算符

1. 字符与字符串

字符值与字符串值

像这样用双引号引起来的值,在 Java 里称为字符串,字符串顾名思义,由多个字符组成,单个字符用单引号表示,例如

jshell> 'a'
$4 ==> 'a'jshell> "abc"
$5 ==> "abc"
  • 单引号里必须由一个字符
  • 双引号里可以有零个、一个、多个字符

转义字符

比如我需要输出一个单引号字符值,''' 这样写行不行?本意是想表示中间的单引号,但遗憾的是java把前两个单引号当成了一对,把它当作了那个空字符了

怎么办呢

为了把真正的单引号跟语法的单引号区分开,需要给它加一个反斜杠标记,告诉java,我想表示真正的单引号,而不是语法中的单引号。试一下。

jshell> System.out.println("\'")
'

这种结合了反斜杠的具有特殊含义的字符,称之为转义字符(Escape Character)

常见的有七个:\' \" \\ \n \t \b \r 刚才已经讲过单引号转义了

继续来看几个例子

jshell> System.out.println("\"") // 双引号转义
"jshell> System.out.println("\\") // 反斜杠本身转义
\jshell> System.out.println("1\n2") // 换行
1
2jshell> System.out.println("123\t4") // 缩进
123     4jshell> System.out.println("123\b4") // 退格
124jshell> System.out.println("123\r4") // 回车,退格是光标退一格,回车是退到头
423

文本块

最后再再来看看文本块,如果有一段文字内,其中需要有很多的转义字符,那么可读性会变得很差,例如

jshell> System.out.println("床前\"明月\"光,\n疑是地上霜。")

因此在 java 14 这个版本引入了文本块来进行改善。

jshell> System.out.println("""床前"明月"光,疑是地上霜。""")

文本块本质上还是属于字符串值,由一对 三个双引号作为起始和结束标记,中间如果想表示双引号、换行这两个特殊字符,无需再转义表示

  • 一个注意事项是 “”" 后需要换个行,不要紧接着写字符。

2. 类型

何为类型

现在让用户输入两个数,求得相加结果

jshell> scanner.nextLine()
1
$22 ==> "1"jshell> scanner.nextLine()
2
$23 ==> "2"jshell> $22 + $23
$24 ==> "12"

显然,这并不是我们想要的结果,它是输入的值当作了字符串,+ 号执行的是字符串连接操作,解决办法如下

jshell> scanner.nextInt()
1
$25 ==> 1jshell> scanner.nextInt()
2
$26 ==> 2jshell> $25 + $26
$27 ==> 3

nextLine() 和 nextInt() 返回的类型是不同的

  • 前者返回的是字符串,类型为 String,+ 表示两个字符串连接
  • 后者返回的是整数,类型为 int,+ 表示两个整数相加

数字类型

类型名说明数字范围类型后缀
byte整数类型,用1个字节表示 [ − 2 7 , 2 7 ) [-2^7,2^7) [27,27) [ − 128 , 128 ) [-128,128) [128,128)
short整数类型,用2个字节表示 [ − 2 15 , 2 15 ) [-2^{15},2^{15}) [215,215)
int整数类型,用4个字节表示 [ − 2 31 , 2 31 ) [-2^{31},2^{31}) [231,231)
long整数类型,用8个字节表示 [ − 2 63 , 2 63 ) [-2^{63},2^{63}) [263,263)L
float浮点小数,用4个字节表示 [ − 1.9999999 ∗ 2 127 , 1.9999999 ∗ 2 127 ] [-1.9999999 * 2^{127},1.9999999 * 2^{127}] [1.99999992127,1.99999992127]F
double浮点小数,用8个字节表示 [ − 1.9999999 ∗ 2 1023 , 1.9999999 ∗ 2 1023 ] [-1.9999999 * 2^{1023},1.9999999 * 2^{1023}] [1.999999921023,1.999999921023]D
  • [] 包含等于,() 不包含等于

  • 类型后缀

    • 不区分大小写,但建议用大写,因为小写的 L 与 1 容易混淆
    • 尾符号 D 可以省略
  • float 和 double 精度不同,即小数点后的位数

    • float 的精度二进制是 23,换算成十进制是 6~7
    • double 的精度二进制是 52,换算成十进制是 15~16

字符类型

类型名说明范围
char字符类型,配合单引号 [ 0 , 2 16 ) [0,2^{16}) [0,216) [ 0 , 65536 ) [0, 65536) [0,65536)
String字符串类型,配合双引号或文本块-

3. 变量与运算符

变量

变量的定义格式为

类型 变量名 =;
  • 从语法可以看到,变量由类型和名称组成,类型决定了变量能存储的数据大小与数据格式,名字用来代表后面的值
  • 这个语法其实咱们前面见过类似的,var scanner = new Scanner(System.in),这里 var 是类型,因为之前我们还没有学习具体有哪些类型,因此使用了 var 来代表某种类型,scanner是变量名,后面这一串就是值,也是 Scanner 对象

= 称之为赋值运算符,可以用来更新变量代表的值。

例如:

int a = 10

这行代码的意思是,定义了整型变量a,更新它的初始值为10

再来一句:

a = 20

这时候为啥不用写前面的类型了呢,因为变量定义只需一次,定义好之后变量就可以反复使用了,这行代码的意思是,将 a 所代表的值更新为 20

变量可以用来保存运算的结果,它自身也能参与运算

运算符

int a = 5 + 3

结果为 8

int a = 5 - 3

结果为 2

int a = 5 * 3

结果为 15

int a = 5 / 3

结果为 1,整数除法有两个注意点

  • 整数除法,只会保留商,而小数部分会被舍弃,并不考虑四舍五入
  • 除0是不合法的,会出错
int a = 5 % 3

结果为 2

小数加减乘除与整数类似,只是小数除法可以保留小数点后的数字,而且可以除零,例如

jshell> 5.0 / 3.0
$40 ==> 1.6666666666666667jshell> 5.0 / 0.0
$41 ==> Infinity

增强赋值运算符

int a = 20; 
a = a + 10; 

意思是,获取 a 的原有值 20,执行加 10 运算,将新的结果重新赋值给 a,a 代表的值被更新成了 30。可以用 += 增强赋值运算符达到类似的效果

a += 10;

先不要看 = 号,获取 a 的原有值 30,执行加 10 运算,运算的结果 40 赋值给 a

a -= 10;

先拿 a 的原有值 40 与后面的 10 做减法,再将结果 30 赋值给 a

自增自减运算符

两个特殊运算符 ++ 与 –

++ 是让变量自增1,-- 是让变量自减1,举个例子

int a = 10;
a++;

结果为 11,++ 和 – 既可以写在变量之前,也可以写在变量之后,这两种写法的区别,我们到高级篇再讲,目前暂不用去了解

4. 练习 - 房贷计算器

【等额本息还款】法计算房贷

术语

  • 等额本息是指一种贷款的还款方式,是在还款期内,每月偿还同等数额的贷款(包括本金和利息)

  • 每月偿还的贷款可以通过下述公式计算

    p ∗ r ∗ ( 1 + r ) m / ( ( 1 + r ) m − 1 ) p * r * (1 + r)^m / ((1 + r)^m - 1) pr(1+r)m/((1+r)m1)

    • p 为贷款本金 principal
    • r 为月利率 monthlyInterestRate
    • m 为还款月数 months

公式中这些都是什么意思呢

例如:贷款 200 万元 ,对应公式中的 p,200 万就是贷款本金,年利率 6%,月利率 mr 就是 6% / 12 = 0.5%,假设 10 年还清,这时还款月数就是 360 个月。套入公式计算即可得到每月还多少钱

要完成这个计算,有一点没学过的是求这里的 1+ mr 的 m 次方,计算它需要用一个求幂方法,这个方法是 jdk 核心类库中 Math 这个类提供的,Math的字面意思是数学,Math 类中提供了很多与数学计算相关的方法,如果你以后有这方面需求,就找它。

Math.pow()

pow 是 static 方法,语法为 类名.方法名(参数值),它需要两个参数,参数1是底数,参数2是指数

jshell> Math.pow(2.0, 1)
$42 ==> 2.0jshell> Math.pow(2.0, 2)
$43 ==> 4.0jshell> Math.pow(2.0, 3)
$44 ==> 8.0

解答

打开 idea,编写 Calculator 类

public class Calculator {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入贷款本金 p");double p = scanner.nextDouble();System.out.println("请输入年利率 r%");double yr = scanner.nextDouble();double mr = yr / 100.0 / 12.0;System.out.println("请输入贷款月数 m");int m = scanner.nextInt();System.out.println(p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1));}
}

数字格式化

对结果的数字进行格式化,让它以货币的格式来显示

需要借助核心类库中一个 NumberFormat 对象,字面意思是数字格式化,使用它的 getCurrencyInstance 方法来获取一个货币格式化对象,再使用它的 format 方法把 double 小数格式化为货币格式,格式化时也会保留两位小数

例子

System.out.println(NumberFormat.getCurrencyInstance(Locale.CHINA).format(1000000.00));   System.out.println(NumberFormat.getCurrencyInstance(Locale.US).format(1000000.00));
System.out.println(NumberFormat.getCurrencyInstance(Locale.GERMANY).format(1000000.00));
System.out.println(NumberFormat.getCurrencyInstance(Locale.KOREA).format(1000000.00));

输出

¥1,000,000.00
$1,000,000.00
1.000.000,00 €
₩1,000,000

如果 Locale 省略不写,默认为中国

房贷计算器可以改写为

double payment = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);       System.out.println(NumberFormat.getCurrencyInstance().format(payment));

查阅 Javadoc

练习做完了,大家学到了什么呢?

有同学说,学会怎么算每月还款了,是吗?并不是,通过这个例子,要认识到 java 核心类库能帮我们解决很多问题,比如说求幂运算,比如说数字格式化,包括之前学过的 Scanner 都是核心类库提供的功能,这就提醒我们,要解决某个编程问题之前,要先想一想核心类库有没有这方面的功能,如果有拿来用就行了,不必自己重新实现某项功能的代码,我们是站在巨人的肩膀上进行编程的。

当然,同学们并不是一开始就知道核心类库都提供了哪些功能,因此,这就需要我们不断去熟悉核心类库,熟悉它都有哪些类,哪些方法,比较重要的功能都在后续的课程中都会陆续介绍到,当然呢,同学们也不能总等着老师来喂知识,也可以自己查阅 javadoc 来扩展自己的知识面

javadoc 就是 java documentation 的缩写,我们下载的 jdk 中已经自带了,无需额外再下载。那怎么查阅 javadoc 呢,如果大家用的是 idea,那么可以通过一些快捷键来查阅java文档

  • 比如想看看类的文档,这时先按 Ctrl + N 查找类,假设我想看 Math 类的文档,输入要查阅的类名 Math,回车,可以跳转到这个类

    在这里插入图片描述

  • 接下来我想看看方法的文档怎么办呢,按一下 ctrl + f12,列出当前类的所有方法,绿色表示可以使用方法,橙色带锁的,表示是该类一种特殊的私有方法,不能直接使用。找感兴趣的方法时,如果你懂一些英文单词,那么会有一定优势,例如你想找一个平方根方法,它对应的英文是 sqrt,这时敲入这几个字母,就会定位到方法,同样可以用翻译查看该方法的功能

    在这里插入图片描述
    在这里插入图片描述

  • 可以查到它的作用:返回一个数的平方根,这是方法名,查看后面括号内可以得知,需要一个参数,代表要求平方根的那个数字,是一个double 小数,方法名称前还有个 double 表示它的结果类型也是一个 double 小数

  • Math 中的方法大部分都是 static 方法,也就是配合类名使用的方法,之前也说过,用法为 类名.方法名(参数)

在平时写代码时,如果忘记了某个方法的作用,可以光标定位到该方法,按 Ctrl + Q 进行查阅,效果是类似的

三. 条件语句

编程时有一种重要的语句叫做条件语句,之前我们学过的都属于顺序语句,也就是从上至下,依次要执行每一行代码。

但是有的情况下,我们并不希望所有代码都执行,而是希望满足条件的代码才执行

例如:要对用户输入数据的合法性进行检查:

  • 贷款本金必须大于0
  • 贷款月数范围在 1 ~ 360 之间
  • 年利率范围在 1% ~ 36% 之间

如果你输入的值连这些条件都不满足,有必要去计算每月还款金额吗?

这种情况下,就要用到条件语句了,它的语法格式为

if(条件) {// 条件为 true 执行这里
} else {// 条件为 false 执行这里
}

什么意思呢,if 本意是如果,如果条件成立,执行代码1,else 本意是否则,即条件不成立,执行代码2,其中 else { } 语句块不是必须的,可以省略

那么条件这部分怎么写呢?对于数字类型可以借助比较运算符的运算结果来充当条件,参考下面的表格,这种表格列出了所有比较运算符

比较运算符含义
a == b判断 a 与 b 是否相等
a > b判断 a 是否 > b
a >= b判断 a 是否 >= b
a < b判断 a 是否 < b
a <= b判断 a 是否 <= b
a != b判断 a 与 b 是否不相等

1. boolean 类型

判断的结果是布尔类型,可以充当条件,它的取值非真即假,真用 true 表示,假用 false 表示

2. 单条件

jshell> int a = 1000;
a ==> 1000jshell> if(a > 0){...>     System.out.println("ok");...> } else {...>     System.out.println("必须>0");...> }
okjshell> a = -1000;
a ==> -1000jshell> if(a > 0){...>     System.out.println("ok");...> } else {...>     System.out.println("必须>0");...> }
必须>0

房贷计算器改写如下

public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入贷款本金 p");double p = scanner.nextDouble();if(p > 0) {System.out.println("请输入年利率 r%");double yr = scanner.nextDouble();double mr = yr / 100.0 / 12.0;System.out.println("请输入贷款月数 m");int m = scanner.nextInt();double payment = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);System.out.println(NumberFormat.getCurrencyInstance().format(payment));} else {System.out.println("贷款金额必须大于0");}}

3. 多条件

刚才我们在判断贷款本金的时候,只需要有一个大于 0 的条件就可以了,但是接下来我们要去检查年利率的时候,他是在一个范围之间,这就必须有两个条件,一个条件呢是要让年利率大于等于 1%,第二个条件呢,是让上年利率必须小于等于 36%,而且呢这两个条件你必须同时成立

多个条件可以用逻辑运算符连接

逻辑运算符含义
条件1 && 条件2&& 意思是并且,两个条件必须同时成立,结果为 true
条件1 || 条件2|| 意思是或者,两个条件有一个成立,结果为 true
! 条件! 意思是取反

举例

jshell> int b = 120;
b ==> 120jshell> if(b >= 1 && b <= 360) {...>     System.out.println("ok");...> } else {...>     System.out.println("必须在1~360之间");...> }
okjshell> b = 0
b ==> 0jshell> if(b >= 1 && b <= 360) {...>     System.out.println("ok");...> } else {...>     System.out.println("必须在1~360之间");...> }
必须在1~360之间jshell> b = 361
b ==> 361jshell> if(b >= 1 && b <= 360) {...>     System.out.println("ok");...> } else {...>     System.out.println("必须在1~360之间");...> }
必须在1~360之间

房贷计算器改写如下

public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入贷款本金 p");double p = scanner.nextDouble();if(p > 0.0) {System.out.println("请输入年利率 r%");double yr = scanner.nextDouble();if (yr >= 1.0 && yr <= 36.0) {double mr = yr / 100.0 / 12.0;System.out.println("请输入贷款月数 m");int m = scanner.nextInt();if (m >= 1 && m <= 360) {double payment = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);System.out.println(NumberFormat.getCurrencyInstance().format(payment));} else {System.out.println("贷款月数范围在 1 ~ 360 之间");}} else {System.out.println("年利率范围在 1% ~ 36% 之间");}} else {System.out.println("贷款金额必须大于0");}
}

4. 相反条件

我们这段代码,逻辑上没错,但你会发现不容易阅读

多层 if 嵌套导致代码的可读性变得很差,一旦大家写代码时出现了两层以上的 if 语句,就要小心了。如何改进呢?

这里给同学们介绍一种方法:可以去除 else 提高代码可读性

比如,现在有两个分支,c 是一个条件,要么走分支1,要么走分支2,用下面的 if else 可以表示

if(c) {// 分支1
} else {// 分支2
}

等价于

if(!c) {// 分支2
} else {// 分支1
}

能不能不写 else 呢?假设进入了分支2,分支2的代码执行后,程序还会继续向下执行,导致分支1也被执行

if(!c) {// 分支2
}
// 分支1 

可以改写为下面的形式,这样就避免了 else 出现

if(!c) {// 分支2return; 
}
// 分支1

总结一下,以上代码的等价转换,有一句口诀:条件取反,if else 倒置,return 一加, else 可去

变换有一定的规律:

原条件相反条件1相反条件2
p > 0.0!(p > 0.0)p <= 0.0
yr >= 1.0 && yr <= 36.0!(yr >= 1.0 && yr <= 36.0)yr < 1.0 || yr > 36.0
m < 1 || m > 360!(m < 1 || m > 360)m >= 1 && m <= 360
  • 用逻辑与连接的两个条件,可以两个条件分别取反,然后&&变||

    • 年利率>=1.0 并且<=36.0 的相反条件是:年利率<1.0 或者 年利率>36.0
  • 用逻辑或连接的两个条件,可以两个条件分别取反,然后||变&&

这种逻辑变换规律称之为反演规则,公式记不住没关系,简单的反演我们自己就能想出来,复杂的变换才用公式保证正确性

房贷计算器改写如下

public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入贷款本金 p");double p = scanner.nextDouble();if (p <= 0.0) {System.out.println("贷款金额必须大于0");return;}System.out.println("请输入年利率 r%");double yr = scanner.nextDouble();if (yr < 1.0 || yr > 36.0) {System.out.println("年利率范围在 1% ~ 36% 之间");return;}double mr = yr / 100.0 / 12.0;System.out.println("请输入贷款月数 m");int m = scanner.nextInt();if (m < 1 || m > 360) {System.out.println("贷款月数范围在 1 ~ 360 之间");return;}double payment = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);System.out.println(NumberFormat.getCurrencyInstance().format(payment));}

四. 循环语句

1. 循环语句语法

for(初始化变量; 终止条件; 更新变量) {// 循环体代码
}
  1. 初始化部分仅执行一次
  2. 执行终止条件,如果为 true 继续循环,如果为 false 退出循环
  3. 执行循环体代码
  4. 执行迭代部分,从 2 开始执行

例如

for(int i = 0; i < 3; i++) {System.out.println(i);
}

执行流程如下

  1. 声明一个变量 i,初始值为 0,用来控制循环次数
  2. 判断 i < 3,此时 i 取值是 0,条件为 true,继续循环
  3. System.out.println(0)
  4. i++,自增为 1
  5. 判断 i < 3,此时 i 取值是 1,条件为 true,继续循环
  6. System.out.println(1)
  7. i++,自增为 2
  8. 判断 i < 3,此时 i 取值是 2,条件为 true,继续循环
  9. System.out.println(2)
  10. i++,自增为 3
  11. 判断 i < 3,此时 i 取值是 3,条件为 false,退出循环

2. 变量的作用范围

上例中 i 的作用范围,仅在循环语句的 {} 内有效,现在要求求 1~100 的整数和,则需要把 sum 这个变量定义在 {} 外层

int sum = 0;
for (int i = 1; i <= 100; i++) {sum += i;
}
System.out.println(sum);

这里能否这样写

for (int i = 1; i <= 100; i++) {int sum = 0;sum += i;
}
System.out.println(sum);

不行,变量有它们各自的作用范围,从变量的定义开始,找到包围它的,右 } 括号为止。

  • 在它上面用它
  • 在右括号外用它

3. 练习 - 贷款计算详情

现在需要计算每月偿还的利息、偿还的本金、剩余的本金

例如,借款 1000 元,利息 100%,两月还清,根据公式计算出来每月还款 1333.33

月份本月还款偿还本金偿还利息剩余本金
11333.33333.331000.00666.67
21333.33666.67666.670
总额2666.671000.001666.67

可以看到

  • 偿还利息 = 剩余本金 ∗ 月利率 偿还利息 = 剩余本金 * 月利率 偿还利息=剩余本金月利率
  • 偿还本金 = 每月还款 − 偿还利息 偿还本金 = 每月还款 - 偿还利息 偿还本金=每月还款偿还利息

房贷计算器改写如下

public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入贷款本金 p");double p = scanner.nextDouble();if (p <= 0.0) {System.out.println("贷款金额必须大于0");return;}System.out.println("请输入年利率 r%");double yr = scanner.nextDouble();if (yr < 1.0 || yr > 36.0) {System.out.println("年利率范围在 1% ~ 36% 之间");return;}double mr = yr / 100.0 / 12.0;System.out.println("请输入贷款月数 m");int m = scanner.nextInt();if (m < 1 || m > 360) {System.out.println("贷款月数范围在 1 ~ 360 之间");return;}double payment = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);System.out.println(NumberFormat.getCurrencyInstance().format(payment));double totalInterest = 0.0;                 // 总利息for (int i = 1; i <= m; i++) {double interest = p * mr;               // 每月偿还利息double principal = payment - interest;  // 每月偿还本金p -= principal;                         // 剩余本金totalInterest += interest;System.out.print(i);System.out.print("\t本月还款:" + NumberFormat.getCurrencyInstance().format(payment));System.out.print("\t偿还本金:" + NumberFormat.getCurrencyInstance().format(principal));System.out.print("\t偿还利息:" + NumberFormat.getCurrencyInstance().format(interest));System.out.println("\t剩余本金:" + NumberFormat.getCurrencyInstance().format(p));}System.out.print("总还款额:" + NumberFormat.getCurrencyInstance().format(payment * m));System.out.println("\t总利息:" + NumberFormat.getCurrencyInstance().format(totalInterest));
}

五. 方法

将来代码多了,全部写在 main 方法里,会显得非常凌乱,难于阅读。这节课的目标是使用方法来改写前面的代码。

1. 定义方法

先来了解一下定义方法的语法

[访问修饰符] [static] 返回结果类型 方法名([参数类型1 参数名1, 参数类型2 参数名2, ...]) {// 方法体return 返回结果
}
  • 其中用 [] 的([] 不是语法的一部分)是可选部分
  • 访问修饰符先省略不写,后面再讲
  • static 这里先写上,这个前面提过,用 static 修饰的方法不属于对象
  • 方法执行完毕后可能会有返回结果
    • 如果没有返回结果,返回值类型填写 void
    • 如果有返回结果,填写实际的类型,例如
      • 返回整数,填写 int
      • 返回小数,填写 double
  • 方法名随便起,但应当做到望文生义
  • 参数是方法执行时需要传入的数据,可以有零到多个,格式为【参数类型 参数名】,多个参数之间用逗号分隔
  • {} 内写方法的具体代码
  • 最后 return 用来结束方法的运行,如果方法有返回结果,也需要配合 return 把结果传递给调用者

例如,想计算一下两个整数的和

class Test {static int add(int a, int b) {return a + b;}
}

2. 调用方法

回忆一下 Math.pow(2.0, 2) 就是一个由 java 提供好的 static 方法,它怎么用呢,Math 是类名,pow 是方法名,括号内是参数,对于我们自己写的 static 方法,用法是类似的:

类名.方法名([参数值1, 参数值2, ...])

Test.add(100,200);

怎么拿到返回结果呢?

int c = Test.add(100,200);

如果是调用本类 static 方法,可以省略前面的类名

3. 方法的意义

学完了方法的定义、调用流程,再来看看方法的意义

方法的一个意义在于隐藏实现细节:

例如,对于前面例子中的【等额本息】方式计算房贷,如果没有方法,那就要求编程者必须非常清楚计算公式

double payment = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);

假设有一位资深程序员(例如你)提供了计算房贷方法,那么编程者就只需要知道:

计算等额本金还款,需要一个名字叫calculate的方法

它需要三个参数,… ,至于具体的计算过程,被隐藏在了方法内部

double payment = calculate(p, mr, m);
  • p 贷款本金
  • mr 月利率
  • m 贷款月数

对于使用它的小白程序员来讲,无需了解它的实现细节,直接拿来用就可以了。小白程序员是站在你的肩膀上编程

方法的另一个意义在于减少重复代码、提高代码的可维护性:

对比以下代码,第一段是没用方法,如果有一处写错了,所有重复的地方都得修改

double p1 = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);
double p2 = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);
double p3 = p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);

用了方法,万一写错,只需要一个地方的代码需要修改

static double calculate(double p, double mr, int m) {return p * mr * Math.pow((1 + mr), m) / (Math.pow((1 + mr), m) - 1);
}

4. 练习 - 贷款计算 - 方法改写

public class Calculator3 {public static void main(String[] args) {double p = inputAndCheckP();double mr = inputAndCheckMr();int m = inputAndCheckM();double payment = Calculator3.calculate(p, mr, m);printDetails(p, mr, m, payment);}static double inputAndCheckP() {Scanner scanner = new Scanner(System.in);System.out.println("请输入本金");double p = scanner.nextDouble();if(p <= 0) {
//            System.out.println("贷款金额必须 > 0");// throw new 异常类型("提示信息")throw new IllegalArgumentException("贷款金额必须 > 0");}return p;}static double inputAndCheckMr() {Scanner scanner = new Scanner(System.in);System.out.println("请输入年利率");double yr = scanner.nextDouble();if(yr < 1.0 || yr > 36.0) {throw new IllegalArgumentException("年利率必须是 1 ~ 36");}return yr / 12.0 / 100;}static int inputAndCheckM() {Scanner scanner = new Scanner(System.in);System.out.println("请输入还款月数");int m = scanner.nextInt();if(m < 1 || m > 360) {throw new IllegalArgumentException("贷款月数必须是 1 ~ 360");}return m;}static void printDetails(double p, double mr, int m, double payment) {for (int i = 0; i < m; i++) {double payInterest = p * mr;                    // 偿还利息double payPrincipal = payment - payInterest;    // 偿还本金p -= payPrincipal;                              // 剩余本金System.out.print ("月份:" + (i + 1));System.out.print("\t本月还款:" + NumberFormat.getCurrencyInstance().format(payment));System.out.print("\t偿还本金:" + NumberFormat.getCurrencyInstance().format(payPrincipal));System.out.print("\t偿还利息:" + NumberFormat.getCurrencyInstance().format(payInterest));System.out.println("\t剩余本金:" + NumberFormat.getCurrencyInstance().format(p));}System.out.println("总还款额:" + NumberFormat.getCurrencyInstance().format(payment * m));}/*** 以等额本息方式计算每月还款金额* @param p 本金* @param mr 月利率* @param m 还款月数* @return 每月还款金额*/static double calculate(double p, double mr, int m) {double pow = Math.pow(1 + mr, m);return p * mr * pow / (pow - 1);}
}

说明1

大家抽取方法时有一个原则,就是把一组完整功能,所对应的多行代码抽取为一个方法,这里我们把计算还款总额和计算还款详情,分别抽取了两个方法

  • calculate
  • printDetails

抽取时,要点如下

  • 方法名要见文知义
  • 返回值不着急写,看看方法的外部需不需要用到这个方法内的变量
    • 需要,返回值定义为结果类型
    • 不需要,返回值定义为 void
  • 参数也不着急写,看方法内缺哪些变量定义,以它们为方法参数

说明2

对于 calculate 这种比较重要的方法定义,最好给它加一个文档,你得告诉将来这个方法的使用者,怎么用这个方法,每个参数是什么意思。

先写斜杠两个星号的开始,不用着急写它的结束,直接一回车。idea 就会自动生成一段 javadoc 文档,你可以在这里介绍方法的作用

  • 在 @param 这里对每个参数进行说明
  • 在 @return 这里对返回值进行说明。

说明3

如果在某些验证不通过,想让剩余代码不要运行,可以利用 throw 语法

  • return 这种语法叫正常返回,也就是当方法调用后,代码还会继续运行
  • 还有就是这种throw 语法,它称为异常返回,如果没有额外处理,代码从方法调用后就中断运行

六. package 与 jar

1. package

随着我们写的类越来越多,把他们都放在一块儿来管理,感觉比较的不规范,因此,我们要引入一个新的package语法,对源文件进行一个更好的管理。

其实这个package说白了就是Java中一种目录结构

|-1|- 从属于包1 的类
|-2|- 从属于包2 的类

语法:

package 包名; // 告诉下面的类从属于此包class{}

包的命名一般都是域名的倒置,如

  • baidu.com 域名的倒置就是 com.baidu
  • bilibilicom 域名的倒置就是 com.bilibili

2. import

与 package 关系非常密切的一个语法:import,如果你的类想使用另外一个类,而两个类不同包,这时就必须用 import,把另一个类导入进来才能使用

package com.itheima.a;import java.util.Scanner;class Calulator {public static void main(String[] args) {// 要用到 Scanner, 这时就用用到上面的 import 语句}
}
  • 有一种特殊情况不需要 import 导入,即 java.lang 包下的类使用时,都不需要 import

3. jar

代码写完了,我们最终要发布成品吧,那是把源文件直接给使用者吗?显然不是吧。最终交给 jvm 运行的是 class 类文件,我们会把这多个 class 类文件打成一个压缩包,交付给用户。

用 idea 可以方便地打包

步骤1:创建工件(artifact)

在这里插入图片描述

步骤2:构建工件
在这里插入图片描述

步骤3:运行 jar 包,需要客户电脑上安装好 jdk

java -jar jar包文件名

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/616852.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是云服务器CVM?

腾讯云服务器CVM提供安全可靠的弹性计算服务&#xff0c;腾讯云明星级云服务器&#xff0c;弹性计算实时扩展或缩减计算资源&#xff0c;支持包年包月、按量计费和竞价实例计费模式&#xff0c;CVM提供多种CPU、内存、硬盘和带宽可以灵活调整的实例规格&#xff0c;提供9个9的数…

MySQL 图书管理系统

1.需求分析 1.1项目需求分析简介 1.1.1信息需求分析 (1) 图书信息&#xff1a;包括书籍编号&#xff0c;书籍名称&#xff0c;出版社&#xff0c;作者&#xff0c;库存量&#xff0c;出版日期&#xff0c;价格&#xff0c;库存&#xff0c;剩余量&#xff0c;类别等&#xf…

Android Retrofit使用详情

一、 Retrofit是什么 Retrofit是Android用来接口请求的网络框架&#xff0c;内部是基于OkHttp实现的&#xff0c;retrofit负责接口请求的封装&#xff0c;retrofit可以直接将接口数据解析为Bean类、List集合等&#xff0c;直接简化了中间繁琐的数据解析过程 二、 Retrofit的简单…

必须掌握的100+个Linux命令大全【持续更新中】

别有一番风趣的alias … note:: 寒蝉凄切&#xff0c;对长亭晚&#xff0c;骤雨初歇。 柳永《雨霖铃》 Linux alias命令用于设置指令的别名&#xff0c;可以将比较长的命令进行简化。 默认情况下会输出当前的设置&#xff1a; $ alias lls -lah lals -lAh llls -lh lsls --…

C++学习笔记——多态与静态联编和动态联编

目录 一、多态 二、静态联编&#xff08;Static Binding&#xff09;和动态联编&#xff08;Dynamic Binding&#xff09; 2.1静态联编 2.2动态联编 一、多态 是C中面向对象编程的一个核心概念&#xff0c;它允许派生类对象替代其基类对象&#xff0c;从而实现代码重用和扩…

代码随想录算法训练营第17天 | 110.平衡二叉树 + 257. 二叉树的所有路径 + 404.左叶子之和

今日内容 110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和 110.平衡二叉树 - Easy 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1…

springboot注解@PropertySource作用

简介 PropertySource 是 Spring 框架中的一个注解&#xff0c;用于指定一个或多个属性文件&#xff08;通常是.properties文件&#xff09;这些文件包含了应用程序需要的配置信息。当你在 Spring 的配置类中使用此注解时&#xff0c;Spring 容器会加载这些属性文件&#xff0c…

01.坦克大战项目-Java绘图坐标体系

01.坦克大战项目- Java绘图 01. Java绘图坐标体系 1. 坐标体系介绍 ​ 下图说明了java坐标系。坐标原点位于左上角&#xff0c;以像素为单位。在Java坐标系中&#xff0c;第一个是x坐标系&#xff0c;表示当前位置为水平方向&#xff0c;距离坐标原点x个像素&#xff1b;第二…

揭露欧拉骗局4.“Σ1/n²=π²/6”里的猫腻

自然数平方倒数求和Σ1/n是一个并不复杂的问题&#xff0c;但它困扰了欧洲大陆整整90年&#xff0c;在欧系数学里它被称为“巴塞尔级数”。 解决巴塞尔级数让欧拉一战成名&#xff0c;然而欧拉采用的方法对数学这门学问是严重的侮辱。数学是工具学科&#xff0c;数学的宗旨是化…

Asp .Net Core 系列: 集成 Consul 实现 服务注册与健康检查

文章目录 什么是 Consul?安装和运行 ConsulAsp .Net Core 如何集成 Consul 实现服务注册和健康检查Consul.AspNetCore 中的 AddConsul 和 AddConsulServiceRegistration 方法 究竟做了什么&#xff1f;AddConsul 方法AddConsulServiceRegistration 方法 配置 Consul 检查服务封…

【椒盐玉兔】GPTs Store 商店的TOP100 自定义GPT使用报告

详细的图文报告有100张图&#xff0c;因为太长就放网盘链接 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;ub2n 解压密码&#xff1a;heehel 更多作品&#xff1a;长期更新国内外&#xff0c;中英文AI人工智能作品 整理获取 通过算法&#xff0c;筛选出了目前访…

每天刷两道题——第十四天

1.1矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用原地算法。 输入&#xff1a;matrix [[0,1,2,0],[3,4,5,2],[1,3,1,5]] 输出&#xff1a;[[0,0,0,0],[0,4,5,0],[0,3,1,0]] 原地算法&#xff08;…

Java面试题(java高级面试题)

线程池的核心线程数设置为多大比较合理&#xff1f; Worker线程在执行的过程中&#xff0c;有一部计算时间需要占用CPU&#xff0c;另一部分等待时间不需要占用CPU&#xff0c;通过量化分析&#xff0c;例如打日志进行统计&#xff0c;可以统计出整个Worker线程执行过程中这两…

书生·浦语大模型--第二节课笔记

书生浦语大模型--第二节课 大模型及InternLM基本介绍实战部分demo部署准备工作模型下载代码准备终端运行web demo 运行 Lagent 智能体工具调用 Demo准备工作Demo 运行 浦语灵笔图文理解创作 Demo环境准备下载模型下载代码运行 大模型及InternLM基本介绍 大模型 定义&#xff…

一阶低通滤波器

一阶低通滤波器 X为输入&#xff0c;Y为滤波后得到的输出值&#xff1b;本次的输出结果主要取决于上次的滤波输出值&#xff0c;其中a是和滤波效果有关的一个参数&#xff0c;称为滤波系数&#xff1b;它决定新采样值在本次滤波结果中所占的权重&#xff1b; 滤波系数a越小&a…

500mA High Voltage Linear Charger with OVP/OCP

一、General Description YHM2810 is a highly integrated, single-cell Li-ion battery charger with system power path management for space-limited portable applications. The full charger function features Trickle-charge, constant current fast charge and const…

Java中的栈和队列操作,相互实现(力扣 232, 225)

栈和队列&#xff08;Java&#xff09; Java中的 栈 & 队列 操作栈的使用队列的使用 LeetCode 232. 用栈实现队列我的代码 LeetCode 225. 用队列实现栈我的代码 Java中的 栈 & 队列 操作 栈的使用 栈的方法功能Stack()构造一个空的栈E push(E e)将e入栈&#xff0c;并…

【开源】基于JAVA语言的民宿预定管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用例设计2.2 功能设计2.2.1 租客角色2.2.2 房主角色2.2.3 系统管理员角色 三、系统展示四、核心代码4.1 查询民宿4.2 新增民宿4.3 新增民宿评价4.4 查询留言4.5 新增民宿订单 五、免责说明 一、摘要 1.1 项目介绍 基于…

Vulnhub-GoldenEye

一、信息收集 nmap探测&#xff1a;nmap -p 1-65535 -T4 -A -v 192.168.1.9 PORT STATE SERVICE VERSION 25/tcp open smtp Postfix smtpd |_smtp-commands: ubuntu, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN |_…

Python基础知识:整理12 JSON数据格式的转换

首先导入python中的内置包json import json 1 准备一个列表&#xff0c;列表内每个元素都是字典&#xff0c;将其转换为JSON 使用json.dumps()方法 data [{"name": "John", "age": 30}, {"name": "Jane", "age":…