语法糖——JAVA

目录

一、for-each

二、枚举

三、不定项参数

四、静态导入

五、自动装箱与拆箱

六、多异常并列

七、数值赋值优化

八、接口方法

九、try-with-resource

十、resource-bundle文件加载

十一、var类型

十二、switch


语法糖定义:为了让事务更加容易读和理解的程序语言被成为语法糖。

一、for-each

for语句:

for(Iterator<Double> i = nums.iterator(); i.hasNext(); )
		{
			result += i.next();
		}	

for-each语句:

for(double item : nums)
		{
			result += item;
		}

优点:

  • 从jdk5开始引入
  • 语言简洁、可以避免出现越界错误

相对于for语句的缺点:

  • for语句可以删除元素,for-each不可以删除和替换
  • for-each遍历时,不知道当前索引的位置
  • for-each只能正向遍历,不能反向遍历
  • for-each不能同时遍历多个集合

for和for-each性能比较接近,是同一个数量级的。

二、枚举

枚举:使变量取值只在一个有限的集合内。常用于性别,星期几,颜色等等

枚举的定义 :enum声明枚举类,枚举类都是Enum子类。

enum Size {
	SMALL,MEDIUM,LARGE,EXTRA_LARGE;
}

枚举的实例化:枚举类中有多少个值就有多少个实例对象,不能直接new来实例。

枚举中的属性/构造函数/方法:枚举中还可以添加属性/构造函数/方法,但是枚举中的构造函数只能是default或者private属性,内部调用。

public class FruitTest {
	public static void main(String[] args) {
		Fruit a1 = Fruit.APPLE;
		System.out.println("Price is " + a1.getPrice());
	}
}

enum Fruit
{
	APPLE(10), ORANGE(8);//将apple构造成10元
	private int price;
	
	Fruit(int price) {
		this.price = price;
	}
	
	public int getPrice() {
		return this.price;
	}
}
输出:Price is 10

Enum类中的方法:

public class DayTest {

	public static void main(String[] args) {
		Day d1 = Day.MONDAY;
		Day d2 = Enum.valueOf(Day.class, "MONDAY");
		System.out.println(d1 == d2);    //true
		
		Day d3 = Enum.valueOf(Day.class, "TUESDAY");
		System.out.println(d1.compareTo(d3)); //MONDAY<TUESDAY
		
		//遍历所有的枚举值
		for(Day item : Day.values())
		{
			System.out.println(item.toString() + "," + item.ordinal());
		}		
	}
}

enum Day
{
	MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
输出:
true
-1
MONDAY,0
TUESDAY,1
WEDNESDAY,2
THURSDAY,3
FRIDAY,4
SATURDAY,5
SUNDAY,6

三、不定项参数

表示可变参数,可以用于不确定同类型参数有几个的情况下。定义为在类型后面加...如:int.../double...(其实可以把不定项参数看成数组)

注意:一个方法只能有一个不定项参数,且必须位于参数列表的最后。

重载优先级:固定参数的方法比可变参数优先级高,调用语句,同时与两个带可变参数的方法匹配则会报错。

package sugar.variablearguments;

public class VariableArgumentTest {

	public static void main(String[] args) {
		print();
		print("aaa");
		print("aaa", "bbb");
		print("aaa", "bbb", "ccc");

	}
	
	public static void print(String... args) {
        System.out.println(args.length);
        for (String arg : args) {
            System.out.println(arg);
        }
    }
	
	//当只有一个参数时,本方法优先级更高
	public static void print(String s)
	{
		 System.out.println("I am another method");
	}
	
	//错误:一个方法不可以有多个可变参数
//	public static void print(String... args, int... irgs) 
//	{
//        
//  }
	
	//错误:一个调用语句不能同时有2个带可变参数的方法适配
//	public static void print(String s1, String... args)
//	{
//		
//	}

}
输出:
0
I am another method
2
aaa
bbb
3
aaa
bbb
ccc

四、静态导入

import static导入一个类的静态方法静态变量(jdk5以上)

相当于直接把方法导入不再需要以格式“类名.方法”调用,直接以格式:“方法”调用

注意:

  • 静态导入时最好不要使用通配符*,最好具体到静态变量和方法。防止重复。
  • 静态方法名具有明确特征,如有重名需要补充类名。
import static java.lang.Double.*;
import static java.lang.Math.*;
import static java.lang.Integer.*;
import static java.text.NumberFormat.*;

import java.text.NumberFormat;

public class BadImportStaticTest {

	public static void main(String[] args) {
		double s = PI * pow(parseDouble(args[0]),2);
		NumberFormat nf = getInstance();
		nf.setMaximumFractionDigits(parseInt(args[1]));
		System.out.println("圆面积是:" + nf.format(s));
		//System.out.println("最大值:" + MAX_VALUE); //因为java.lang.Double.*;java.lang.Integer.*;都含有MAX_VALUE静态变量,所以error
		System.out.println("最大值:" + Integer.MAX_VALUE);
	}
}



import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
import static java.lang.System.*;
import static java.lang.System.out;

public class ImportStaticTest {
	public static void importMath()	{
		int a=3, b=4, c=0;
		c = (int) sqrt(pow(a,2)+pow(b,2));//静态导入后
		c = (int) Math.sqrt(Math.pow(a,2)+Math.pow(b,2));//普通导入
		out.println("c is " + c);//静态导入
		System.out.println("c is " + c);//普通导入		
	}
}

五、自动装箱与拆箱

目的:简化基本类型和对象之间的简化。

注意事项:

  • 自动装箱拆箱时编译器的工作。
  • ==判等时:基本类型判断内容是否相同,对象则判断指针是否指向统一内存区域
  • 基本类型不能赋值为null,对象可以为null。
  • 基础数据类型与封装类进行数据运算时,会自动给封装类进行拆箱,对基础数据类型进行运算。
  • 谨慎使用多个非同类的数值类对象进行运算。

举例:

如果没有自动装箱拆箱:

ArrayList<Integer> list =new ArrayList<>();
list.add(Integer.valueof(2));
int a = list.get(1).intValue();

有自动装箱拆箱后:

ArrayList<Integer> list =new ArrayList<>();
list.add(2);
int a = list.get(1);

 同时最好也注意一下常量池的概念:之前写过相关博客可见:https://blog.csdn.net/weixin_43698704/article/details/103946059

public class A {
	public static void main(String[] args) {
		Integer n1 =128;
		Integer n2 =128;
		System.out.println(n1==n2);
	}
	
}
//输出false 涉及常量池
public class A {
	public static void main(String[] args) {
		int n1 =128;
		int n2 =128;
		System.out.println(n1==n2);
	}
	
}
//输出true 所以敲代码最好用Int而不是integer

 拆箱装箱示例:

public class NumberTest {

	public static void main(String[] args) {
		Integer a1 = 1000;
		int a2 = 1000;
		Integer a3 = 2000;
		Long a4 = 2000L;
		long a5 = 2000L;
		
		System.out.println(a1 == a2);  //拆箱再进行数值比较
		System.out.println(a3 == (a1 + a2));  //拆箱再进行数值比较
		System.out.println(a4 == (a1 + a2));  //拆箱再进行数值比较
		System.out.println(a5 == (a1 + a2));  //拆箱再进行数值比较
		
		
		System.out.println(a3.equals(a1+a2)); //equals要求同类,且内容相同
		System.out.println(a4.equals(a1+a2)); //equals要求同类,且内容相同
		System.out.println(a4.equals((long) (a1+a2))); //equals要求同类,且值相同
		
		//System.out.println(a3 == a4); //不同类型不能比较,判断两个对象内存是否是同一个
	}

}
输出:
true
true
true
true
true
false
true

六、多异常并列

多个异常并列放入一个catch中(jdk7以上)

注意:管道两侧异常类不可以有直接或间接继承关系。

try
		{
			test();
		}
		catch(IOException | SQLException ex)
		{
			//JDK7开始,支持一个catch写多个异常
			//异常处理
		}

七、数值赋值优化

(jdk7以上)

1.整数类型可以用二进制数赋值。

可用于:byte/short/int/long类型

2.在数字直接可以使用下划线_增加数字的可读性和纠错功能。

可用于short/int/long/float/double;

下划线只能出现在数字之间,前后必须有数字;

允许出现在2/8/10/16进制的数字中使用。


public class NumberTest {
	public static void main(String[] args) {
		
		long a1 = 9999999999L;
		long a2 = 9_999_999_999L;
		
		int a3 = 0b0111_1011_0001; //二进制, 0b开头
		int a4 = 0_214;           //八进制, 0开头
		int a5 = 123___45;         //可以多个下划线
		int a6 = 0x7_B_1;          //十六进制
		float a7 = 3.56_78f;       //float
		double a8 = 1.3_45__67;    //double
		
		int b1 = 0b_123_4;  //_必须在数字之间
		int b2 = 0123_4_;   //_不能在末尾
		int b3 = _123;      //_不能在开头
		int b4 = 0_x_123;   //不能拆开0x
		int b5 = 0x_51;     //_必须在数字之间
		long b6 = 1000_L;   //_必须在数字之间
		float b7 = 1.34f_;  //_不能在末尾
		
		
	}
}

八、接口方法

之前也写过类似接口与抽象类的区别的博客可查看https://blog.csdn.net/weixin_43698704/article/details/103994472

最初接口内不可以让方法实现和公开,直到jdk8推出接口的默认方法/静态方法(都可以实现)。

默认方法:

Object方法有equal();toString();hashCode()(返回哈希码值);

规则五中如一个类引用的两个接口都含同名同参数的默认方法,需要在子类重写。可以用格式来重写:

public void move() {
		NewAnimal.super.move();	//其中一个接口(父类)的move()方法	
	}	

默认方法实现:

public interface NewAnimal {
	public default void move()
	{
		System.out.println("I can move.");
	}
}

静态方法:

定义:在方法前面加一个static

静态方法属于本接口,不属于子类或者子接口

子类(子接口)中没有继承静态方法,只能通过格式:“接口名.方法”来调用

public interface StaticAnimal {

	public static void move()
	{
		System.out.println("I can move");
	}
}
public interface StaticLandAnimal extends StaticAnimal {
	//也继承不到StaticAnimal的move方法
}
public class StaticSwan implements StaticAnimal {
	
	public static void main(String[] args) {
		StaticAnimal.move();
		//StaticLandAnimal.move(); //error,报错
		//new StaticSwan().move(); //error,报错
	}
}

私有方法:

(需要jdk9以上)

public interface PrivateAnimal {

	public default void run()
	{
		move();//默认方法可以调用静态/非静态的私有方法
		move2();
		System.out.println("I can run");
	}
	public default void fly()
	{
		move();//默认方法可以调用静态/非静态的私有方法
		System.out.println("I can fly");
	}
	private void move()
	{
		//非静态的私有方法
		System.out.println("I can move");
		System.out.println("I am growing");
	}
	
	public static void run2()
	{
		move2();//静态方法可以调用静态的私有方法
		System.out.println("I can run");
	}
	public static void fly2()
	{
		move2();//静态方法可以调用静态的私有方法
		System.out.println("I can fly");
	}
	private static void move2()
	{
		//静态的私有方法
		System.out.println("I can move");
		System.out.println("I am growing");
	}
	
	
	
	
}

九、try-with-resource

程序如果打开外部资源,那么在使用结束以后需要正确关闭。

之前用的是try-catch-finally进行保证

public static void readFile1() {
		FileInputStream fis = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		try {
			fis = new FileInputStream("c:/temp/abc.txt"); // 节点类
			isr = new InputStreamReader(fis, "UTF-8"); // 转化类
			//isr = new InputStreamReader(fis);
			br = new BufferedReader(isr); // 装饰类
			// br = new BufferedReader(new InputStreamReader(new
			// FileInputStream("c:/temp/abc.txt")))
			String line;
			while ((line = br.readLine()) != null) // 每次读取一行
			{
				System.out.println(line);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				br.close(); // 关闭最后一个类,会将所有的底层流都关闭
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}

jdk7提供try-with-resource,比上者更加方便。(资源对象需要实现了AutoCloseable接口,才可以用这个方法,fileInputStream中已经实现)

public class MyTryWithResourceTest {

	public static void main(String[] args) {
		
		//将会自动调用conn的close方法
		try(MyConnection conn = new MyConnection())
		{
			conn.sendData();
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}

	}

}

class MyConnection implements AutoCloseable {
	 public void sendData() throws Exception {
		 System.out.println("Send Data....");
	 }
	 
	 public void close() throws Exception {
		 System.out.println("Close....");
	 }
}
输出:
Send Data....
Close....

注意的是jdk7中需要在try()中定义资源,若在外面定义看,则需要一个本地变量。如:

jdk9不再要求定义临时变量,可以直接使用外部的资源变量。

public static void readFile2() {
		String line;
		//try-resource 语句,自动关闭资源
		try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("c:/temp/abc.txt")))) {
			while ((line = in.readLine()) != null) {
				System.out.println(line);
			}
		}
		catch(Exception ex)  
		{
			ex.printStackTrace();
		}
	}

十、resource-bundle文件加载

jdk8及之前国际化编程中文件里面的编码都需要利用native2ascii工具进行转义,jdk9之后就不用了。



/**
 * 测试ResourceBundle加载方式
 * @author Tom
 * 以JDK9及以上运行,程序正常,以JDK8运行,出现乱码,无法解析UTF-8文件
 */
public class NameTest {

	public static void main(String[] args) {
		Locale myLocale = Locale.getDefault();
		
		System.out.println(myLocale); //zh_CN 

		// 根据指定语言_国家环境加载资源文件
		ResourceBundle bundle = ResourceBundle.getBundle("msg", myLocale);

		// 从资源文件中取得的消息
		System.out.println(bundle.getString("name"));  


	}

}
输出:
zh_CN
吴琼

msg_zh_CN.properties,用UTF-8编码即可

#Update name name
#Wed Jul 31 15:26:28 CST 2019
name=吴琼

十一、var类型

jdk10推出了var,局部变量推断。

优点:

注意:本质上还是强类型语言,编译器负责推断类型,并写入字节码文件,因此推断后不能更改。

十二、switch

jdk12之前:

public static int judgeMonthDay(String month)
	{
		int result = 0;
		
		switch(month)
		{
		case "Jan": case "Mar": case "May": case "July": 
		case "Aug": case "Oct": case "Dec": 
			result = 31;
			break;
		case "Apr": case "June": case "Sep": case "Nov": 
			result = 30;
			break;
		case "Feb":
			result = 28;
			break;
		default: 
			result = -1;
		}
		
		return result;
	}

jdk12及以后:

public static int judgeMonthDay12(String month)
	{
		//this method works based on Java 12.
		//modify project properties/Java Compiler/Enable preview features
		int result = 0;
		
		//new switch, don't need break clauses
		//-> 之后 : expression/block/throw   
		switch(month)
		{
			case "Jan","Mar","May","July","Aug","Oct","Dec" -> result = 31;			
			case "Apr","June","Sep","Nov" -> result = 30;
			case "Feb" -> result = 28;
			default -> result = -1;
		}
		
		return result;
	}

 可以直接有返回


	public static void testSwitchReturn()
	{
		int num = 1;
		int days = switch (num) {
		    case 1,3,5,7,8,10,12 -> 31;
		    case 4,6,9,11 -> 30;
		    default -> {
		        int result = 28;
		        break result;  //代码块中break返回结果
		    }
		};
		
		System.out.println(days);
	}

参考中国大学mooc《java核心技术》

发布了55 篇原创文章 · 获赞 17 · 访问量 4994

猜你喜欢

转载自blog.csdn.net/weixin_43698704/article/details/104183361