Java中不太常见的语法-总结

简介

读源码时,或者看同事写的代码,经常看到一些不太常见的语法,这里做一个总结

不太常见的语法

成员变量的默认值

案例:

public class Person2 {private String name = "张三";private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Person2{" +"name='" + name + '\'' +", age=" + age +'}';}
}

实例化Person2,会发现,name已经被赋默认值了:

Person2 person2 = new Person2();
System.out.println("person2 = " + person2);   // person2 = Person2{name='张三', age=null}

普通的业务代码中不推荐这么写,建议把赋值语句写在构造方法中,语义更明确。

原始类型数据不能和null进行运算

案例:

int i = null;

这一行代码会报错,基础数据类型不是一个对象,不支持赋null值。

我在开发中遇到的一个实际案例,当时没有注意到这一点,这里我使用一段简单的代码来模拟一下:

public class Test3 {@Testpublic void test1() {Integer i = null;if (Color.RED.getId() == i) {  // 这行代码会报空指针异常,可以使用Objects.equals来避免System.out.println("aaa");} else {System.out.println("bbb");}}enum Color {RED(1, "红色"),BLACO(2, "黑色"),YELLOE(3, "黄色");private final int id;private final String name;Color(int id, String name) {this.id = id;this.name = name;}public int getId() {return id;}public String getName() {return name;}}
}

分析一下原因,因为基础数据类型不支持和null进行运算,而案例中Integer类型的变量实际上是一个null值,所以会报空指针异常,我当时遇到这个问题,怎么都想不到原因,结果发现,同事定义的枚举值中,居然使用了int类型,所以最好使用包装类来作为成员变量的类型,这个案例中,如果id的类型是Integer,这么比较不会有问题。

do while语句

do while循环,第一次时一定会进入循环,在某些情况下使用它更合适,例如,有一种场景,需要循环读取外部数据并处理,直到读完,第一次的时候肯定要读取外部数据,所以这种情况下使用do while会比较合适。

案例:

数据准备: 模拟读取外部数据,分页读取

private static final List<User> list = Lists.newArrayList(new User(1L, "aaa", "aaa@qq.com", 20),new User(2L, "bbb", "bbb@qq.com", 20),new User(3L, "ccc", "ccc@qq.com", 20));private PageBO<User> readList(int pageNo, int pageSize) {PageBO<User> bo = new PageBO<>();bo.setPageNo((long) pageNo);bo.setPageSize(pageSize);bo.setTotalCount((long) list.size());int offset = (pageNo - 1) * pageSize;int limit = Math.min(offset + pageSize, list.size());if (offset < list.size()) {List<User> resultList = new ArrayList<>(list.subList(offset, limit));bo.setRecordList(deepCopyByIO(resultList));}return bo;
}// 使用IO流实现深拷贝
@SuppressWarnings("unchecked")
public static <T> T deepCopyByIO(T object) {if (object == null) {return null;}// ByteArrayOutputStream、ByteArrayInputStream,是内存流,即使不关闭也不会造成资源泄露,例如文件句柄未// 释放等问题,即使如此,随时关闭流依然是一个好习惯,而且关闭输出流会保证缓冲区的数据被正确的写出try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {objectOutputStream.writeObject(object);try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {return (T) objectInputStream.readObject();}} catch (Exception e) {e.printStackTrace(); // 打印异常信息return null;}
}@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBO<T> {/*** 总条数*/private Long totalCount;/*** 当前页码*/private Long pageNo;/*** 页面大小*/private Integer pageSize;/*** 本页数据*/private List<T> recordList;
}@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {private static final long serialVersionUID = 8683452581122892181L;private Long id;private String name;private String email;private Integer age;
}

案例1: 使用while语句来实现循环读取外部数据

@Test
public void test1() {int pageNo = 1;final int PAGE_SIZE = 1;PageBO<User> pageBO = readList(pageNo, PAGE_SIZE);while (CollectionUtils.isNotEmpty(pageBO.getRecordList())) {// 处理数据System.out.println("处理数据 = " + pageBO.getRecordList());// 循环读取pageNo++;pageBO = readList(pageNo, PAGE_SIZE);}
}

案例2: 将上面的while循环变成do while循环

@Test
public void doWhileTest() {int pageNo = 1;final int PAGE_SIZE = 1;PageBO<User> pageBO; // while 条件表达式中的变量,必须在do while之外才可以被看到do {pageBO = readList(pageNo, PAGE_SIZE);System.out.println("处理数据 = " + pageBO.getRecordList());pageNo++; // 循环读取} while (CollectionUtils.isNotEmpty(pageBO.getRecordList()));
}

案例3:案例2中有一个问题,最后一次一定会读到空数据,所以while不可以直接转换为do while,代码要做一点改变

@Test
public void doWhileTest2() {int pageNo = 1;final int PAGE_SIZE = 1;PageBO<User> pageBO;do {pageBO = readList(pageNo, PAGE_SIZE);if (CollectionUtils.isEmpty(pageBO.getRecordList())) {break;}System.out.println("处理数据 = " + pageBO.getRecordList());pageNo++; // 循环读取} while (true);
}

案例4:一个简单的案例

public static void main(String[] args) {java.util.Scanner scanner = new java.util.Scanner(System.in);int userInput;do {System.out.print("请输入一个1到10之间的数字: ");userInput = scanner.nextInt();} while (userInput < 1 || userInput > 10);System.out.println("你输入了: " + userInput);
}

总结:do while语句适合处理第一次一定会进入循环的情况,但是使用普通的while也可以,只是do wihle在语义上更加合适,不过要注意的是,判断是否需要继续循环的条件,和while的不太一样,它们不可以共用。

平时do while使用的不是很多,更多的使用的是while,遇到类似的情况,可以使用更合适的do while。

问题:a = b的返回值是什么?

答案:返回b

案例:

int a = 10;
int b = 11;
int c = a = b;
System.out.println("c = " + c); // 11

这是在阅读源码时看到的一段代码:

queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);

注意看方法中的参数3,q.next = waiters,最终是把什么值传递给了方法?答案是waiters,但同时,q.next的值也被更新为waiters了

双括号初始化

一种快捷的初始化集合或其他对象的方式

案例:

List<String> list = new ArrayList<String>() {{add("AA");add("BB");}
};

list被初始化为一个 ArrayList 的匿名子类。大括号中的代码块是一个实例初始化块,它在匿名子类创建时执行。

需要注意的是,虽然双括号初始化语法在某些情况下很方便,但它也创建了一个匿名的子类,会产生一些额外的内存开销,因为每个实例都是一个单独的类。此外,这种语法在某些上下文中可能会导致问题,比如在序列化时。

这种初始化方式会创建一个匿名内部类,相较于普通的初始化方式性能较低,不建议使用,而且序列化等方面,可能会有意想不到的坑

迭代器的使用

关于迭代器的几个问题:

  • 自己编写的类,怎样可以被for关键字遍历? 实现Iterable接口,这个接口要求返回Iterator实例,通常需要为自己编写的类实现一个独有的Iterator。
  • 迭代器的初始状态:迭代器被创建后,指针指向列表的第一个元素,hasNext的第一次判断,是判断列表的第一个元素存不存在,next方法,返回当前指向的元素并且指针后移。这里不是绝对的,取决于迭代器的实现逻辑,但是通常是这么实现的。

案例:模拟ArrayList,写一个基于数组的集合

public class ArrList<E> implements List<E>, Iterable<E>, Serializable, Cloneable {private static final long serialVersionUID = 1234L;private static final int DEFAULT_CAPACITY = 8;private Object[] arr;private int size;private int capacity;public ArrList() {capacity = DEFAULT_CAPACITY;size = 0;arr = new Object[capacity];}// 省略代码,这里只关系迭代器的实现@Overridepublic Iterator<E> iterator() {return new Itr();}private void checkIdx(int i) {if (i < 0 || i >= size) {throw new RuntimeException("下标越界:" + i);}}private class Itr implements Iterator<E> {private int idx;private int lastRet = -1;  // 上次访问@Overridepublic boolean hasNext() {return idx < size;}@Overridepublic E next() {checkIdx(idx);lastRet = idx;return get(idx++);}// remove方法,只有在调用next方法之后才可以调用remove方法,它用于移除当前元素,// 因为此时指针已经后移,所以特定使用一个变量来记录指针的上一个位置。@Overridepublic void remove() {checkIdx(idx);ArrList.this.remove(lastRet);  idx = lastRet;lastRet = -1;}}
}

重点查看迭代器的实现逻辑,迭代器初始化时,指向列表中的第一个元素,调用next方法,返回当前元素并且指针后移。

之前只是学习过迭代器的正确使用姿势,自己尝试写一个迭代器时,才注意到它内部的逻辑,所以这里做个简单总结

总结

这里记录了一些不太常见的语法,跟个人经验有关,比如我就不怎么使用do while循环来解决问题,但是有些情况下它确实更合适,还有迭代器的使用,不太清楚它的内部逻辑,剩下的就是某些不太常见的语法,或者容易被忽视的问题点。

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

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

相关文章

Easytier异地组网与移动光猫GS220-s

Easytier异地组网与Nginx反向代理_--relay-network-whitelis easytier-CSDN博客 上一篇文章介绍了Easytier实现异地组网&#xff0c;基于Windows应用&#xff0c;本篇将探讨如何将Easytier写入光猫GS220-s中&#xff0c;实现更方便的家庭组网。 一、Telnet移动光猫GS220-s 1…

卫星信号和无线信号的设备厂商

以下是一些与卫星信号相关的公司&#xff1a;中国卫通集团股份有限公司&#xff1a;中国航天科技集团有限公司从事卫星运营服务业的核心专业子公司&#xff0c;是中国唯一拥有通信卫星资源且自主可控的卫星通信运营企业。运营管理着多颗在轨民商用通信广播卫星&#xff0c;覆盖…

HyperPlonk 的硬件友好性

1. 引言 在工业界广泛使用的 Plonk SNARK 协议高度依赖 NTT 来完成计算。HyperPlonk 是 Plonk 的一个变种&#xff0c;它试图通过用 Sumcheck 替代 NTT&#xff08;以及其它改进&#xff09;来提升并行性。Ingonyama团队认为&#xff1a; Sumcheck 在 HyperPlonk 中所谓的并行…

Visual Studio内置环境变量有哪些

在 Visual Studio 中&#xff0c;内置变量&#xff08;也称为宏&#xff09;可以用于在项目配置中指定特定的路径、环境变量或其他值。这些变量可以在项目的属性页面中使用&#xff0c;也可以在代码中使用。以下是一些常用的内置变量及其用途&#xff1a; 常用内置变量 $(Solut…

大模型入门学习微调实战:基于PyTorch和Hugging Face电影评价情感分析模型微调全流程(附完整代码)手把手教你做

深入浅出&#xff1a;如何训练一个属于你的大模型&#xff1f; “一个强大的大模型&#xff0c;究竟是如何训练出来的&#xff1f;” 本文将基于行业共识&#xff0c;为您详细拆解大模型的完整训练流程&#xff0c;并提供一个基于开源模型和数据集的实战代码示例&#xff0c;…

零、2025 年软件设计师考试大纲

一、考试说明 1.考试目标 通过本考试的合格人员能根据软件开发项目管理和软件工程的要求&#xff0c;按照系统总体设计规格说明书进行软件设计&#xff0c;编写程序设计规格说明书等相应的文档&#xff0c;组织和指导程序员编写、调试程序&#xff0c;并对软件进行优化和集成…

uniapp npm安装形式 全局分享和按钮分享设置

全局分享方法新建一个shareUtil.ts方法import { storageConfig } from /config/storageConfig; export default {data() {return {miniShareOptions: {title: 标题,path: /pages/tabbar/index?inviteCode,summary: 描述,imageUrl: /userPages/static/img/invitation_h_bg.png,…

【数据结构】树和二叉树——树和森林

目录树和二叉树树和森林树的存储结构双亲表示法孩子表示法孩子兄弟表示法森林与二叉树的转换树和森林的遍历树的先根遍历树的后根遍历树的层次遍历森林的先序遍历森林的中序遍历树的应用求树的深度输出树中所有从根到叶子的路径的算法建树的存储结构的算法哈夫曼树与哈夫曼编码…

【小宁学习日记5 PCB】电路定理

目录 一、先搞懂&#xff1a;原理图的 “构成密码” &#xff08;1&#xff09;连接线&#xff1a;别被 “直线” 骗了&#xff01; &#xff08;2&#xff09;结点&#xff1a;红色小圆点才是 “真・连接” &#xff08;3&#xff09;网络标签&#xff1a;“无形的连线” …

ans1语法的一个例子nt5inf.cat

第二部分&#xff1a;语法第一部分&#xff1a;头部语法第一部分A&#xff1a;0x30 类型位0x10SEQUENCE and SEQUENCE OF10语法第一部分B&#xff1a;83 长度3个字节&#xff0c;如果为1个字节&#xff0c;第一部分B则没有。语法第一部分C&#xff1a;长度 0x09 …

三电平逆变器SVPWM控制(无解耦功能)与谐波分析

三电平逆变器的空间矢量脉宽调制(SVPWM)控制方法&#xff0c;重点分析在不使用解耦控制的情况下实现5%谐波含量的技术方案。我们将使用MATLAB/Simulink进行建模和仿真分析。 一、三电平逆变器基本原理 三电平逆变器相比传统两电平逆变器具有以下优势&#xff1a; 输出电压波形质…

模拟实现C++中的string类型:从底层理解字符串操作

string前言核心成员变量设计构造函数与析构函数默认构造函数从C风格字符串构造填充构造拷贝构造函数迭代器范围构造析构函数基本操作实现迭代器支持容量管理元素访问字符串修改操作拼接操作插入与删除字符串查找操作运算符重载总结每文推荐前言 在C中&#xff0c;std::string是…

pdf转ofd之移花接木

文章目录1.pdf转ofd的方法1.1 spire.pdf.free1.2 ofdrw2.移花接木3.总结1.pdf转ofd的方法 1.1 spire.pdf.free 这个是一个半开源的类库&#xff0c;免费版本的在转换的时候会有一个10的限制&#xff0c;所以不推荐使用&#xff0c;具体教程网上都有&#xff0c;这里只是分享有…

用【Coze】实现文案提取+创作

在AI技术飞速发展的当下&#xff0c;打造专属智能应用成为不少人的向往。今天&#xff0c;就带大家走进字节跳动的扣子Coze平台&#xff0c;看看如何借助它搭建智能体&#xff0c;还会介绍AI工作流&#xff0c;以及详细的Coze搭建步骤&#xff0c;开启你的AI创作之旅&#xff5…

buuctf——web刷题第5页

第五页 目录 [EIS 2019]EzPOP [WMCTF2020]Make PHP Great Again 2.0 [BSidesCF 2020]Hurdles [安洵杯 2019]iamthinking [GWCTF 2019]mypassword [HFCTF2020]BabyUpload [NewStarCTF 2023 公开赛道]include 0。0 [SWPU2019]Web4 [PASECA2019]honey_shop [Black Watc…

果蔬采摘机器人:自动驾驶融合视觉识别,精准定位,高效作业

在智慧农业的快速发展中&#xff0c;果蔬采摘机器人以其自动驾驶技术与视觉识别技术的完美融合&#xff0c;正逐步成为农业生产中的重要力量。这些机器人不仅实现了对果蔬的精准定位&#xff0c;还显著提高了采摘效率&#xff0c;展现了强大的技术优势。一、自动驾驶技术的引领…

2025年职业发展关键证书分析:提升专业能力的路径选择

在当今职场环境中&#xff0c;专业能力的提升已成为职业发展的重要方面。各类专业证书作为系统学习与能力验证的方式&#xff0c;受到越来越多职场人士的关注。本文基于当前行业发展趋势&#xff0c;分析8个在不同领域具有代表性的专业资格认证&#xff0c;为职场人士提供参考信…

【Qt】QCryptographicHash 设置密钥(Key)

QCryptographicHash 本身不能设置密钥&#xff08;Key&#xff09;。 它是一个用于计算非密钥型加密哈希的函数&#xff0c;其设计目的和 HMAC 或加密算法完全不同。 下面我详细解释为什么&#xff0c;以及如何正确地实现你可能想要的功能。 1. QCryptographicHash 的核心功能&…

2025板材十大品牌客观评估报告—客观分析(三方验证权威数据)

随着消费者环保意识提升&#xff0c;板材作为家装基础材料的性能指标受到广泛关注。中国林产工业协会数据显示&#xff0c;2025年国内环保板材市场规模约860亿元&#xff0c;但行业标准执行不一&#xff0c;消费者面临信息不对称问题。本报告严格依据可验证的第三方数据&#x…

诊断通信管理(Diagnostic Communication Management)详解

—— 基于《Specification of Diagnostics AUTOSAR AP R24-11》(SWS_Diagnostics.pdf) 诊断通信管理(Diagnostic Communication Management)是 AUTOSAR 自适应平台诊断管理(Diagnostic Management,DM)的核心功能模块之一,位于应用层,承担 “诊断客户端与诊断服务器实…