Java 关键字 – 基础数据类型

Java 是面向对象语言, 但有几个特例,就是基础数据类型。

Java定义了八种基本的数据类型,分为四类:

整数类型:

  • byte:占用1个字节(8位),取值范围从-128到127。
  • short:占用2个字节(16位),取值范围从-32,768到32,767。
  • int:占用4个字节(32位),取值范围从-2^31到2^31-1。这是最常用的整数类型。
  • long:占用8个字节(64位),取值范围从-2^63到2^63-1。

浮点数类型:

  • float:占用4个字节(32位),是单精度浮点数类型。
  • double:占用8个字节(64位),是双精度浮点数类型。这是最常用的浮点数类型。

字符类型:

  • char:占用2个字节(16位),用于表示单个Unicode字符。

布尔类型:

  • boolean:理论上占用1个比特,但实际大小取决于虚拟机实现。只有两个取值:true和false。
//下面是一些声明基本类型变量的例子:
byte byteVar = 100;
short shortVar = 1000;
int intVar = 10000;
long longVar = 100000L; // 注意末尾的L,表示这是一个long类型的字面量

float floatVar = 10.0F; // 注意末尾的f,表示这是一个float类型的字面量
double doubleVar = 10.0;

char charVar = 'A';
boolean booleanVar = true;


基本类型有一些特点:

  • 它们的大小是固定的,不会因为不同的机器而改变。
  • 它们不是对象,因此不具备对象的属性和方法。 因此他们间比较时需要直接使用 ==
  • 基本类型都有对应的包装类,包装类和基础类型间可以进行自动装箱和拆箱。例如:int的包装类是Integer,double的包装类是Double等。
Integer a = 1; //自动装箱,将a 转换为 包装类。
Integer b = 2;
int b = a;   //自动拆箱
if(b > a ){//自动拆箱
//...
}

Java 关键字 – for, while

for, while都是循环结构关键字,作用为支持重复执行相同代码,掌握了这两个关键字的使用,基本各种数据循环都可以实现。

示例: 按序输出26个字母

for(char c='a'; a<='z'; a++){
     System.out.println(a);
}
char c='a';
while (a<='z'){
   System.out.println(a);
}

for

for 语法结构有两种:条件for 及for-each 结构

//for 结构
for (初始化表达式; 条件表达式; 步进表达式) {
    // 循环体:当条件表达式为true时执行
}。

初始化表达式 一般为循环控制变量的初始化,只在循环开始时执行一次, 可为空。
条件表达式 循环控制表达式,可以为空,如果有则必须为布尔表达式,每次循环前都会执行,且只有表达为true 时,循环才会执行
步进表达式 循环体执行完后执行的表达式, 一般用户循环控制变量的修改。 可为空。

for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}
for (;;) {
    System.out.println("-");
    break;
}

注意: 这个三个表达式可以部分为空,也可以都为空的,都为空时,则循环的结束需在循环体中控制, 如使用break 或return 进行退出循环,等效while(true){//循环}

for-each 结构, 这是Java 5 引入了一种特殊类型的for循环,称为”增强for循环”或”for-each循环”,它简化了对数组或集合的遍历。增强for循环的语法如下:

for (数据类型 变量名 : 数组或实现了 Iterable 接口的任何集合类) {
    // 使用变量名进行操作
}

for-each 循环可以被视为Java语法糖。语法糖(Syntactic Sugar)是指在编程语言中添加的某种语法,这种语法让人们写代码时更加方便,但它并不提供新的功能,而是提供了一种更简洁易读的方法来表达已有的操作。也就是所有for-each 实现的代码都可以转换为for 循环结构实现,只是代码会复杂点。实际底层实现也是这么做的,如果遍历对象是实现了 Iterable 接口的任何集合类, 则使用了 Iterator 进行元素的遍历。如果你使用的是数组,它就会被编译成一个常规的 for 循环,使用索引来访问每个元素。

// 使用 for-each 循环
for (String item : listOfStrings) {
    System.out.println(item);
}
// 等价的使用 Iterator 的代码
for (Iterator<String> i = listOfStrings.iterator(); i.hasNext(); ) {
    String item = i.next();
    System.out.println(item);
}
// 如果是数组,则等价于常规的 for 循环
String[] arrayOfStrings = new String[] {"a", "b", "c"};
for (int i = 0; i < arrayOfStrings.length; i++) {
    System.out.println(arrayOfStrings[i]);
}

while

也有两种语法: while 及 do…while , 不过都是比较简单的。

while (condition) {
    // 循环体
    // 在这里编写需要重复执行的代码
}
do {
    // 循环体
    // 在这里编写需要重复执行的代码
}while(condition);

condition 是一个布尔表达式。在每次循环开始之前,都会评估这个条件。如果条件为 true,循环体内的代码块将被执行。完成循环体内的代码块后,条件将再次被评估,如果仍为 true,循环将继续执行。这个过程会一直重复,直到条件表达式的结果为 false

如果条件从一开始就是 false,那么循环体内的代码块一次也不会执行。

continue, break

这几个关键字出现在循环体,会影响循环体的执行。

continue (label): 执行到continue, 则结束本次循环,直接开始下次(label)循环。 label 为空则退出当前最近的循环。

break (label): 执行到break, 则结束退出(label)指定的循环, label 为空则退出当前最近的循环。

label 是可选的,通常循环嵌套时,用于退出多个循环时。

     first: for(int i =0; i< 10; i++){
          for (int j = 0; j < 10; j++){
              if(j== 5){
                  continue first;
              }
              if(j == 9){
                  break;
              }
              System.out.println("i="+i+",j="+j);
          }
      }

基于SpringBoot Actuator存活就绪检查

什么是存活就绪检查?

存活检查: 检查一个服务是否存活, 如果不存活,需要启动新的服务进行补充替换。对于JAVA 服务,如在Java 进程异常退出、 Java 进程假死等情况等不可自动恢复的情况,就任务是不存活的。

就绪检查: 检查一个服务是否准备好,对外提供服务。 主要应用在新应用启动后,不立刻提供对外服务,而需要通过就绪检查确定提供的服务的资源都准备好后才提供对外的服务。

为什么需要存活、就绪检查?

对于一个被线上使用的服务来说,降低服务的可用性的原因(不考虑编码层面问题)主要有:

  • 发布不平滑。 发布时不能平滑替换服务,导致部分请求报错,降低可用性。
  • 服务故障修复不及时。 一般是服务过载情况下, 服务缺失故障自动修复能力,或自动扩展能力不足,导致服务不可用。
  • 没有备份。 单机或单区运行,在服务器异常或区域性依赖异常时,导致服务不可用。

就绪检查主要会用在保障发布时保障服务可用时再提供对外服务使用,是平滑发布保障的关键一环。

存活检查主要用在服务过程中,服务发生不可恢复故障时,发布工具能够自动及时的进行补救。

如何实现存活就绪检查?

根据存活就绪检查目的, 实现方法一般会对应用依赖重要组件进行检查,汇总后提供检查结果输出。 可以看出来这是比较适合进行封装的动作,SpringBoot Actuator 就这样一个包,虽然存活就绪只是其功能之一。如果需要自己实现,SpringBoot Actuator 是一个很好的参考。

SpringBoot Actuator 做为存活就绪检查步骤

SpringBoot Actuator提供的健康检查端点 /actuator/health ,虽然也可以做为存活和就绪检查使用,通过对存活和就绪作用及原理的了解,知道其满足不了存活就绪分离检测。 不过在Spring Boot 2.3及以上版本,Actuator新增了分组功能,通过对健康端点的各组件进行分组,通过分组自定义组内包含的检测组件,实现不同作用的检测。如可以设置liveness和readiness 两个分组, 然后通过/actuator/health/liveness和/actuator/health/readiness来作为检测接口。

使用SpringBoot Actuator 基本上包含大部分组件的检查端点实现, 通过配置可以灵活的配置需要使用的端点。配置示例如下:

management:
  endpoints:
    web:
      exposure:
        include: "health,info,env"  #开放访问的接口
      base-path: /actuator     #自定义基础路径, 默认/actuator
  endpoint:
    health:
      enabled: true            #是否开启,默认true
      show-details: ALWAYS     #health 接口是否返回详情信息,方便排查一般返回
      group:
        readiness:               #就绪检查组,访问地址 /health/readiness
          include: "ping"   #就绪组检查的组件
        liveness:                #存活检查组,访问地址 /health/liveness
          include: "ping"        #存活组要检查的组件
  health:
    defaults.enabled: false      #关闭自动启用组件检查,改由手动启用
    ping.enabled: true           #defaults.enabled 为false 情况下, 手动指定开启的检查端点
    mysql.enabled: true          

如何确定哪些组件需要加入存活或就绪检测

一般项目不复杂,引入组件很少或没有重要影响系统运行的三方组件情况下,可以使用

Spring Boot Actuator提供的默认设置即可满足需求。但因为默认设置会默认加载所有引入组件包中带的Actuator 健康监测端点,而不管这个端点检测的组件是否使用,是否重要。为防止一些无效的包或不重要的组件检测故障导致存活或就绪检查失败,推荐自定义配置来定义设置线上项目的health 端点, 即把defaults.enabled 设置为false, 然后手工开启需要进行检测的组件。

具体项目中包含哪些可用端点呢, 可以通过设置defaults.enabled 设置为true,

开启actuator 健康检查,将health.defaults.enabled 设置为true的情况下,访问/actuator/health 就能查看到当前项目所有检查的端点。

如果项目没有需要检测的组件,或组件不适合作为就绪或存活检查项, 可以启用ping 组件做空白验证。对于有重要组件,但没有自带的检测端点,也可以自实现端点接口HealthIndicator。 示例:

public class MemHealthIndicator implements HealthIndicator {

    private final Logger LOGGER = LoggerFactory.getLogger(MemHealthIndicator.class);

    @Override
    public Health health() {
        MemoryMXBean memoryMbean = ManagementFactory.getMemoryMXBean();
        MemoryUsage usage = memoryMbean.getHeapMemoryUsage();
        Long max = usage.getMax();
        Long used = usage.getUsed();
        double useRate = used.doubleValue()/max.doubleValue();
        String useInfo = toString(usage);
        if(useRate > 0.9){
            LOGGER.info("jvm 内存使用超过90%,使用率{}",useInfo);
            return Health.down().withDetail("内存使用率",usage).build();
        }
        LOGGER.info("jvm 内存使用{}",useInfo);
        return Health.up().withDetail("内存使用率",usage).build();
    }

}

//其他配置类中
...
    @Bean
    @ConditionalOnEnabledHealthIndicator("mem") // 定义端点名称,配置中可以使用mem.enable:true 启用
    public HealthIndicator memHealthIndicator(){
        return new MemHealthIndicator();
    }
....

Java 关键字 — switch

Java 中的 switch 语句是一种多分支选择结构,它允许基于不同的情况执行不同的代码块。通常结合break, default, case 等关键字一起使用。

switch (expression) {
    case value1:
        // 代码块
        break; // 可选
    case value2:
        // 代码块
        break; // 可选
    // 可以有任意数量的case语句
    default: // 可选
        // 默认情况下的代码块
}

expression:这是一个必须的表达式,它的结果被用来与 case 语句中的值进行比较。这个表达式可以是 byte、short、char、int 类型,枚举(Java 5 开始支持),或者是 String 类型(Java 7 开始支持),
任意类型(Java 12).

case value:这是与 expression 结果进行匹配的值。如果匹配成功,紧随其后的代码块将被执行。
value 必须为一个常量表达式。  JAVA 12 开始支持类型推断。
JAVA 21 开始支持 when.

break:这是一个可选关键字,用来终止 switch 语句的执行。如果没有 break,程序将会继续执行下一个 case 中的代码,直到遇到 break 或者 switch 语句的结尾。

default:这也是一个可选部分,当没有任何 case 与 expression 的值匹配时,将执行 default 部分的代码。
示例:
final static class User{public String name;}

	private static final char m = 'm';
	private static final User user = new User();
	
	static void switchSen(Object v) {
		Character c = 1;
		User u = new User();
		switch(v) {
			case Integer i: System.out.println(i);
				break;
			//case c: System.out.println(1);
			//case 1: System.out.println(1);
			case User us: System.out.println(us);
			default: 
				System.out.println("default");
		}
		
		
		switch(c) {
			case 2: System.out.println(2);
			case m: System.out.println(m);
			default: 
				System.out.println("default");
		}
		
		switch(u) {
			case User i when u.name.equals("abc"): System.out.println(i);
	//		case user: System.out.println(2);
			default: 
				System.out.println("default");
		}
		
	}

switch 表达式
在 Java 12 及以后的版本中,switch 可以用作表达式,这意味着它可以返回一个值。switch 表达式使用 -> 来代替case 后的 :. 另外每个case 不需要使用break , 只返回因为表达式是有返回值的,因此其中的case 必须涵盖传入表达式的所有值。

switch (expression) {
    case value1 -> {
        // 代码块
        yield value; // 可选
    }
    case value2 -> value:
    // 可以有任意数量的case语句
    default -> default value // 可选
        // 默认情况下的代码块
}

case value:这是与 expression 结果进行匹配的值。如果匹配成功,紧随其后的代码块将被执行。
value 必须为一个常量表达式。 JAVA 12 开始支持类型推断。
JAVA 21 开始支持 when.

示例:

static String switchWhen(Object v) {
		//int when = 1; 
		//int yield = 3;//任然可以作为变量

		return switch(v) {
			case Integer i ->  i.toString();
			case String s when s.equalsIgnoreCase("yes") ->{
				yield s.toUpperCase();
			}
			case String s when s.equalsIgnoreCase("yeap") -> "yep";
			default ->  "EMPTY";
		};
	}
	
	static String switchNull(Object v) {
		return switch(v) {
			case Integer i ->  i.toString();
			case String s when s.equalsIgnoreCase("yes") ->{
				yield s.toUpperCase();
			}
			case String s -> "NO";
			case null,default ->  "EMPTY";
		};
	}
	
	static String switchString(CharSequence v) {
		return switch(v) {
			case String s -> "String";
			case CharSequence s -> "CS";
//			case String s when s.equalsIgnoreCase("yes") ->{
//				yield s.toUpperCase();
//			}
//			default ->  "EMPTY";  //前面两个case 已处理所有情况
		};
	}


为什么使用Switch
   从使用语法可知,switch 能实现的功能,if else 也是能实现的,但使用switch 有以下几大优势:


可读性: 当你需要基于同一个变量的不同值来执行不同的代码块时,switch语句比多个if-else语句更加清晰和易读。

效率: 对于包含许多case的情况,switch语句通常比if-else语句更高效,因为switch语句可以转化为跳转表,这意味着不需要按顺序检查每个条件。

可维护性: 当需要修改或者增加新的条件分支时,switch语句的结构使得这些变更更加集中和简单。

Java 关键字

Java关键字是指在Java编程语言中具有特定含义的保留单词。这些关键字代表了Java语言的基本构建块,它们用于定义数据类型、流程控制语句、访问权限等。由于这些单词被Java语言赋予了特殊的意义,不能用作标识符,例如类名、方法名或变量名等。 随着Java 发展及保证向后兼容性需求,新版本出现了可用于做标识符的局部关键字, 他们只在特定表达式或语法中做为关键字识别, 其他地方仍可作为标识符使用。

Java 总共包含53个关键字,详情如下表:

关键字类型关键字类型
abstract类、方法和变量修饰符native类、方法和变量修饰符
assert错误处理new变量引用
boolean数据类型package包定义
break程序控制结构private访问控制,私有
byte数据类型protected访问控制,保护
case程序控制结构public访问控制,公开
catch错误处理return程序控制结构
char数据类型short数据类型
class类、方法和变量修饰符static类、方法和变量修饰符
continue程序控制结构strictfp类、方法和变量修饰符
default程序控制结构super变量引用
do程序控制结构switch程序控制结构
double数据类型synchronized类、方法和变量修饰符
else程序控制结构this变量引用
enum类、方法和变量修饰符throw错误处理
extends类、方法和变量修饰符throws错误处理
final类、方法和变量修饰符transient类、方法和变量修饰符
finally错误处理try错误处理
float数据类型void变量引用
for程序控制结构volatile类、方法和变量修饰符
if程序控制结构while程序控制结构
implements类、方法和变量修饰符goto保留关键字
import包引入const保留关键字
int数据类型null特殊常量
interface类、方法和变量修饰符false特殊常量
instanceof程序控制结构true特殊常量
long数据类型

局部关键字:

关键字说明引入版本
var用于局部变量类型推断10
record 用于声明记录类12
sealed用于密封类和接口, 定义密封类或接口17
non-sealed用于密封类和接口,定义非密封类或接口17
permits用于密封类和接口,定义密封类或接口的可实现类范围17
yieldswitch 表达式值返回12
whenswitch 增强,case 扩展21

京ICP备12026520号-3