赞
踩
在之前的代码中,我们总是使用System.out.println()
来向屏幕输出一些内容。
println
是print line的缩写,表示输出并换行,因此如果想不换行,可使用print()
public class Main{
public static void main(String[] args) {
System.out.print("A,");
System.out.print("B,");
System.out.print("C.");
System.out.println();
System.out.println("END");
//A,B,C.
//END
}
}
为什么要格式化输出?因为计算机表示的数据不一定适合人来阅读,如下输出的结果:
public class Main {
public static void main(String[] args) {
double d = 12900000;
System.out.println(d); // 1.29E7
}
}
如果要把数据显示成我们期望的格式,就需要使用格式化输出的功能。格式化输出使用System.out.printf()
,通过使用占位符%?
,printf()
可以把后面的参数格式化成指定格式
public class Main{
public static void main(String[] args) {
double d = 3.1415926;
System.out.printf("%.2f\n",d); // 显示两位小数3.14
System.out.printf("%.4f\n",d); // 显示4位小数3.1416
}
}
占位符 | 说明 |
---|---|
%d | 格式化输出整数 |
%x | 格式化输出十六进制整数 |
%f | 格式化输出浮点数 |
%e | 格式化输出科学计数法表示的浮点数 |
%s | 格式化字符串 |
注意:由于%表示占位符,因此,连续两个%%表示一个%字符本身。
占位符本身还可以有更详细的格式化参数。下面的例子把一个整数格式化成十六进制,并用0补足8位:
public class Main {
public static void main(String[] args) {
int n = 12345000;
System.out.printf("n=%d, hex=%08x", n, n); // 注意,两个%占位符必须传入两个数
// n=12345000, hex=00bc5ea8
}
}
import java.util.Scanner; public class Main{ public static void main(String[] args) { // 创建Scanner对象 Scanner scanner = new Scanner(System.in); // 打印提示 System.out.println("输入你的id"); // 读取一行输入并获取字符串 String name = scanner.nextLine(); // 打印提示 System.out.println("输入你的年龄"); // 读取一行输入,并获取整数 int age = scanner.nextInt(); System.out.printf("Hi,%s,you are %d\n",name,age); } }
首先,我们通过import
语句导入java.util.Scanner
,impor
是导入某个类的语句,必须放到Java源代码的开头。
然后,创建Scanner
对象并传入System.in
。System.out
代表标准输出流,而System.in
代表标准输入流。直接使用System.in
读取用户输入虽然是可以的,但是需要更复杂的代码,二通过Scanner
就可以简化后续的代码。
有了Scanner
对象后,要读取用户输入的字符串,使用scanner.nextLine()
,要读取用户输入的整数,使用scanner.nextInt()
。Scanner
会自动转换数据类型,因此不必手动转换。
Java提供Scanner对象来方便输入,读取对应的类型可以使用:
scanner.nextLine()
/nextInt()
/nextDouble()
/nextFloat()
/…
用法与JavaScript中基本一致,下列几点需注意
由于浮点数有精度误差,因此浮点数使用==
判断是否相等不靠谱。
正确的方法是利用差值小于某个临界值来判断:
public class Main {
public static void main(String[] args) {
double x = 1 - 9.0 / 10;
if (Math.abs(x - 0.1) < 0.00001) {
System.out.println("x is 0.1");
} else {
System.out.println("x is NOT 0.1");
}
}
}
判断引用类型是否相等可以使用==
运算符,但是,判断引用类型的变量是否相等,==
表示"引用是否相等",或者说,”是否指向同一个对象“。例如,下面的两个String类型,他们的内容是相同的,但是,分别指向不同的对象,用==
判断,结果为false
.
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "HELLO".toLowerCase();
System.out.println(s1);
System.out.println(s2);
if (s1 == s2) {
System.out.println("s1 == s2");
} else {
System.out.println("s1 != s2");
}
}
}
注意:要判断引用类型的变量内容是否相等,必须使用
equals()
方法
public class Main {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "HELLO".toLowerCase();
System.out.println(s1);
System.out.println(s2);
if (s1.equals(s2)) {
System.out.println("s1 equals s2");
} else {
System.out.println("s1 not equals s2");
}
}
}
注意:执行语句
s1.equals(s2)
时,如果变量s1
为null
,会报NullPointerException
要避免NullPointerException
,可使用&&
进行短路判断
public class Main {
public static void main(String[] args) {
String s1 = null;
//短路判断
if (s1 != null && s1.equals("hello")) {
System.out.println("hello");
}
//非短路判断
if (s1.equals("hello")) {
System.out.println("hello");
}
}
}
switch
语句根据siwtch(表达式)
计算的结果,跳转到匹配的case
结果,然后继续执行后续语句,直到遇到break
结束执行。
public class Main { public static void main(String[] args) { int option = 1; switch (option) { case 1: System.out.println("Selected 1"); break; case 2: System.out.println("Selected 2"); break; case 3: System.out.println("Selected 3"); break; default: System.out.println("Not selected"); break; } } }
但option
的值在1
,2
,3
中没有匹配到时,将会执行default
的代码,若没有default
,将什么都不执行。
在有多个==
判断时,switch
语句比if
语句更加清晰
注意:
case
语句没有{}
,且case
语句具有穿透性
,漏写break
将会持续向下执行,直到遇见break
当有几个case
语句执行的是同一组语句块时,可合并写
public class Main { public static void main(String[] args) { int option = 2; switch (option) { case 1: case 2: case 3: System.out.println("Selected 1, 2, 3"); break; default: System.out.println("Not selected"); break; } } }
switch
语句还可以使用枚举类型,枚举类型后面会进行学习
使用switch
时,如果遗漏了break
,就会造成严重的逻辑错误,而且不易在源代码中发现错误。从Java 12开始,switch
语句升级为更简洁的表达式语法,使用类似模式匹配(Pattern Matching)的方法,保证只有一种路径会被执行,并且不需要break
语句:
public class Main {
public static void main(String[] args) {
String fruit = "apple";
switch (fruit) {
case "apple" -> System.out.println("Selected apple");
case "pear" -> System.out.println("Selected pear");
case "mango" -> {
System.out.println("Selected mango");
System.out.println("Good choice!");
}
default -> System.out.println("No fruit selected");
}
}
}
注意新语法使用->
,如果有多条语句,需要用{}
括起来。不要写break
语句,因为新语法只会执行匹配的语句,没有穿透效应。
很多时候,我们还可能用switch
语句给某个变量赋值。例如:
int opt;
switch (fruit) {
case "apple":
opt = 1;
break;
case "pear":
case "mango":
opt = 2;
break;
default:
opt = 0;
break;
}
使用新的switch
语法,不但不需要break
,还可以直接返回值。把上面的代码改写如下:
public class Main {
public static void main(String[] args) {
String fruit = "apple";
int opt = switch (fruit) {
case "apple" -> 1;
case "pear", "mango" -> 2;
default -> 0;
}; // 注意赋值语句要以;结束
System.out.println("opt = " + opt);
}
}
用yield
返回一个值作为switch
语句的返回值:
public class Main {
public static void main(String[] args) {
String fruit = "orange";
int opt = switch (fruit) {
case "apple" -> 1;
case "pear", "mango" -> 2;
default -> {
int code = fruit.hashCode();
yield code; // switch语句返回值
}
};
System.out.println("opt = " + opt);
}
}
while (条件表达式) {
循环语句
}
while
循环在每次循环开始之前,首先判断条件是否成立。如果为true
,就把循环体内的语句执行一遍,如果为false
,那就直接跳到while
循环的末尾,继续往下执行。
public class Main {
public static void main(String[] args) {
int sum = 0;
int n = 1;
while (n <= 100) { //循环条件是n <= 100
sum += n;
n++;
}
System.out.println(sum);// 5050
}
}
注意:
while
循环是先判断循环条件,再循环,因此,有可能一次循环都不做
while
循环时先判断,再执行循环,而do while
是先执行循环,再进行判断
do {
执行循环语句
} while(条件表达式)
因此,
do while
循环至少循环一次
把对1到100的求和用do while
循环改写一下:
public class Main {
public static void main(String[] args) {
int n = 1;
int sum = 0;
do {
sum += n;
n++;
} while(n <= 100)
System.out.println(sum);
}
}
for (初始条件; 循环检测条件; 循环后更新计数器) {
// 执行语句
}
示例
public class Main {
public static void main(String[] args) {
int sum = 0;
for (int i=1; i<=100; i++) {
sum = sum + i;
}
System.out.println(sum);
}
}
public class Main{
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
for(int item: arr ){
System.out.println(item);
}
}
}
和for
循环相比,for each
循环的变量(item)不再是计数器,而是直接对应到数组的每个元素。for each
循环的写法也更简洁。但是,for each
循环无法指定遍历顺序,也无法获取数组的索引。
除了数组外,for each
循环能够遍历所有“可迭代”的数据类型,包括后面会介绍的List
、Map
等。
无论是while
循环还是for
循环,有两个特别的语句可以使用,就是break
语句和continue
在循环过程中,可以使用break
语句跳出当前循环
public class Main{
public static void main(String[] args) {
int sum = 0;
for (int i=1; ; i++) {
sum = sum + i;
if (i == 100) {
break;
}
}
System.out.println(sum);
}
}
使用for
循环计算从1到100时,我们并没有在for()
周设置循环退出的检测条件。但是在内部,通过if
判断,如果i==100
,就通过break
跳出当前循环
break
语句通常都是配合if
使用。要注意:break
语句总是跳出自己所在的那一层循环
public class Main { public static void main(String[] args) { for (int i=1; i<=10; i++) { System.out.println("i = " + i); for (int j=1; j<=10; j++) { System.out.println("j = " + j); if (j >= i) { break; } } // break跳到这里 System.out.println("breaked"); } //不会跳到这里 } }
break
会跳出当前循环,也就是整个循环都不会执行了.而continue
是提前结束本次循环,直接继续执行下一次循环.
public class Main {
public static void main(String[] args) {
int sum = 0;
for (int i=1; i<=10; i++) {
System.out.println("begin i = " + i);
if (i % 2 == 0) {
continue; // continue语句会结束本次循环
}
sum = sum + i;
System.out.println("end i = " + i);
}
System.out.println(sum); // 25
}
}
在多层嵌套的循环中,
continue
语句同样是结束本次自己所在的循环。
可使用for
循环,或者for each
循环进行遍历
public class Main { public static void main(String[] args) { int[] ns = { 1, 4, 9, 16, 25 }; // for 循环 for (int i=0; i<ns.length; i++) { int n = ns[i]; System.out.println(n); } // for each 循环 for (int n : ns) { System.out.println(n); } } }
直接打印数组,得到的是数组在 JVM 中的引用地址
int[] ns = { 1, 1, 2, 3, 5, 8 };
System.out.println(ns); // 类似 [I@7852e922
想获得数组的值,应使用for each
循环,或者Java提供的Arrays.toString()
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] ns = { 1, 1, 2, 3, 5, 8 };
// for each循环
for (int n : ns) {
System.out.print(n + ", ");
}
// Arrays.toString()
System.out.println(Arrays.toString(ns));
}
}
常用的排序算法有,冒泡排序
、插入排序
和快速排序
等。
//冒泡排序 int[] arr = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 }; System.out.println("排序前: " + Arrays.toString(arr)); for (int i = 0; i < arr.length ; i++) { for (int j = 0; j < arr.length - 1; j++) { if (arr[j] > arr[j+1]){ int midNum = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = midNum; } } System.out.println("排序中 === " + Arrays.toString(arr)); } System.out.println("排序后: " + Arrays.toString(arr));
冒泡排序的特点: 每一轮循环后, 将最大的一位交换到末尾
Java内置数组排序 JDK Arrays.sort()
int[] arr = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
必须注意,对数组排序实际上修改了数组本身。例如,排序前的数组是:
int[] ns = { 9, 3, 6, 5 };
在内存中,这个整型数组表示如下:
┌───┬───┬───┬───┐
ns───>│ 9 │ 3 │ 6 │ 5 │
└───┴───┴───┴───┘
当我们调用Arrays.sort(ns);
后,这个整型数组在内存中变为:
┌───┬───┬───┬───┐
ns───>│ 3 │ 5 │ 6 │ 9 │
└───┴───┴───┴───┘
即变量ns
指向的数组内容已经被改变了。
二维数组:
public class Main{
public static void main(String[] args) {
int[][] arr = {
{1,2,3},
{4,5,6},
{7,8,9}
};
System.out.println(arr.length);
System.out.println(Arrays.deepToString(arr));
}
}
使用Java标准库的Arrays.deepToString()
可以打印多维数组
三维数组:
int[][][] ns = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
},
{
{10, 11},
{12, 13}
},
{
{14, 15, 16},
{17, 18}
}
};
Java程序的入口是main
方法,而main
方法可以接受一个命令参数,它是一个String[]
数组。
这个命令行参数由 JVM接受用户输入并传给main
方法
public class My{
public static void main(String[] args) {
for(String arg: args) {
System.out.println(arg);
}
}
}
我们可以利用接收到的命令行参数,根据不同的参数执行不同的代码。例如,实现一个-version
参数,打印程序版本号:
public class Main {
public static void main(String[] args) {
for (String arg : args) {
if ("-version".equals(arg)) {
System.out.println("v 1.0");
break;
}
}
}
}
上面这个程序必须在命令行执行,我们先编译它:
$ javac Main.java
然后,执行的时候,给它传递一个-version
参数:
$ java Main -version
v 1.0
这样,程序就可以根据传入的命令行参数,作出不同的响应。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。