规格说明(Specifications)

1.为什么需要规格说明?

(1)许多程序中的严重错误是由于代码之间接口的行为误解引起的。虽然每个程序员心中都有规格说明,但并非所有程序员都将其写下来。这导致团队中的不同程序员对同一个接口有不同的理解。

(2)编写明确的规格说明有助于确定错误的来源,并避免解决问题时的困惑。

(3)规格说明对方法的使用者有利,因为它们可以省去阅读代码的麻烦。规格说明对方法的实现者也有好处,因为它们赋予实现者改变实现而不需要通知使用者的自由。

 (1)行为等价(Behavioral Equivalence)

考虑以下两个方法:

static int findFirst(int[] arr, int val) {for (int i = 0; i < arr.length; i++) {if (arr[i] == val) return i;}return arr.length;
}static int findLast(int[] arr, int val) {for (int i = arr.length - 1; i >= 0; i--) {if (arr[i] == val) return i;}return -1;
}
规格说明的结构

方法的规范包含几个部分:

  • 前置条件(precondition):由关键字requires指示
  • 后置条件(postcondition):由关键字effects指示

前置条件是对客户端的要求,描述方法调用时的状态。

后置条件是对方法实现者的要求,描述方法完成时的状态。

在Java中,我们使用Javadoc注释来编写规范。

例如:

/*** 找到数组中指定值的位置。* @param arr 要搜索的数组,要求 val 在 arr 中恰好出现一次* @param val 要搜索的值* @return 数组中值为 val 的索引 i*/
static int find(int[] arr, int val) {// 方法实现
}

(2)Null引用(Null References)

在Java中,对象和数组的引用可以是null,这意味着引用没有指向任何对象。null值会导致运行时错误,因此在6.005课程中,不允许参数和返回值为null

避免null的建议:

  • 使用非null注解:例如@NonNull
  • 在方法规范中明确说明null的使用
static boolean addAll(@NonNull List<T> list1, @NonNull List<T> list2)

(3)变异方法的规范(Specifications for Mutating Methods)

描述会改变对象状态的方法的规范:

import java.util.List;/*** 将 list2 中的所有元素添加到 list1 的末尾。* * @param list1 要添加元素的列表* @param list2 要从中添加元素的列表* @param <T> 列表中元素的类型* @return 如果调用该方法后 list1 发生了变化,则返回 true* @throws IllegalArgumentException 如果 list1 和 list2 是同一个对象* * 前置条件(Requires):*  - list1 != list2* * 修改效果(Modifies):*  - list1* * 后置条件(Ensures):*  - list1 包含它最初包含的所有元素,顺序不变*  - list1 包含 list2 中的所有元素,顺序与 list2 中一致*  - 当且仅当 list2 不为空时,方法返回 true*/
public static <T> boolean addAll(List<T> list1, List<T> list2) {// 检查 list1 和 list2 是否是同一个对象if (list1 == list2) {throw new IllegalArgumentException("两个列表不能是同一个对象。");}// 记录 list1 的原始大小int originalSize = list1.size();// 将 list2 的所有元素添加到 list1 中boolean modified = list1.addAll(list2);// 返回 true 如果 list1 因调用而发生变化return modified;
}

2.异常处理(Exceptions)

(1)信令bug的异常(Signaling Bugs with Exceptions)

在Java编程中,常见的异常有ArrayIndexOutOfBoundsException(数组索引超出有效范围时抛出)和NullPointerException(尝试对null对象引用调用方法时抛出)。这些异常通常表示代码中存在错误,Java在抛出异常时显示的信息可以帮助您查找并修复这些错误。

public static void main(String[] args) {int[] array = {1, 2, 3};System.out.println(array[5]); // 抛出ArrayIndexOutOfBoundsException
}
(2)特殊结果的异常(Exceptions for Special Results)

处理特殊结果的一种常见方法是返回特殊值,例如在查找操作中返回-1null

但使用异常可以让代码更简洁,减少错误。

  • try 块中的代码抛出 NotFoundException 异常时,Java 运行时环境会搜索与该异常类型匹配的 catch 块。
  • catch (NotFoundException nfe) 表示捕获 NotFoundException 类型的异常,并将其赋值给变量 nfe
class BirthdayBook {public LocalDate lookup(String name) throws NotFoundException {// 假设找不到名字时抛出异常throw new NotFoundException();}
}public static void main(String[] args) {BirthdayBook birthdays = new BirthdayBook();try {LocalDate birthdate = birthdays.lookup("Alyssa");} catch (NotFoundException nfe) {System.out.println("未找到生日信息");}
}
 (3)已检查和未检查的异常(Checked and Unchecked Exceptions)
  • 已检查异常用于表示预期的、可以合理恢复的异常情况。编译器强制要求程序员在方法签名中声明这些异常,并且在调用该方法时处理这些异常。典型的已检查异常包括IOExceptionSQLException等。

    示例:文件读取操作 假设我们有一个读取文件内容的方法,该方法在文件不存在或无法读取时抛出IOException

  • import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;public class CheckedExceptionExample {// 声明可能抛出IOExceptionpublic static String readFile(String filePath) throws IOException {BufferedReader reader = new BufferedReader(new FileReader(filePath));StringBuilder content = new StringBuilder();String line;while ((line = reader.readLine()) != null) {content.append(line).append("\n");}reader.close();return content.toString();}public static void main(String[] args) {String filePath = "example.txt";try {String content = readFile(filePath);System.out.println(content);} catch (IOException e) {System.out.println("捕获到IOException: " + e.getMessage());}}
    }
    

  • 未检查异常(Unchecked Exception)

    未检查异常用于表示程序中的编程错误或不可恢复的错误。这些异常不需要在方法签名中声明,也不需要在调用时显式处理。典型的未检查异常包括NullPointerExceptionArrayIndexOutOfBoundsException等。

  • 示例:数组访问操作 假设我们有一个访问数组元素的方法,该方法在访问越界时会抛出ArrayIndexOutOfBoundsException

  • getElement方法没有声明它可能抛出ArrayIndexOutOfBoundsException,但调用者可以选择处理这个异常。

  • public class UncheckedExceptionExample {public static int getElement(int[] array, int index) {return array[index]; // 可能抛出ArrayIndexOutOfBoundsException}public static void main(String[] args) {int[] array = {1, 2, 3};try {int element = getElement(array, 5);System.out.println(element);} catch (ArrayIndexOutOfBoundsException e) {System.out.println("捕获到ArrayIndexOutOfBoundsException: " + e.getMessage());}}
    }
    
(4)异常设计注意事项(Exception Design Considerations)

(1) 不要滥用已检查异常

已检查异常要求调用者处理,有时会导致代码变得繁琐。如果预期异常很少发生,且调用者无法采取合理措施处理,可以考虑使用未检查异常。

public class Queue {private LinkedList<Integer> list = new LinkedList<>();public void enqueue(int item) {list.add(item);}public int dequeue() {if (list.isEmpty()) {throw new RuntimeException("队列为空");}return list.removeFirst();}
}

(2) 使用自定义异常

在某些情况下,标准异常类可能无法准确描述问题。此时可以创建自定义异常,以更好地表达特定的错误情况。

public class InsufficientFundsException extends Exception {public InsufficientFundsException(String message) {super(message);}
}

(3.)提供有意义的异常信息

在抛出异常时,应提供有意义的错误消息,以帮助调试和理解问题。错误消息应描述发生了什么错误以及可能的原因。

 

public class InvalidAgeException extends Exception {public InvalidAgeException(String message) {super(message);}
}public class User {private int age;public void setAge(int age) throws InvalidAgeException {if (age < 0 || age > 150) {throw new InvalidAgeException("年龄必须在0到150之间,输入的年龄为:" + age);}this.age = age;}
}
(5)滥用例外(Misuse of Exceptions)

使用异常来控制正常的程序流是一种不好的做法。这不仅会导致性能问题,还会使代码难以理解和维护。

// 错误示例:滥用异常控制循环
try {int[] array = {1, 2, 3};int i = 0;while (true) {System.out.println(array[i++]);}
} catch (ArrayIndexOutOfBoundsException e) {// 结束循环
}// 正确示例
int[] array = {1, 2, 3};
for (int i = 0; i < array.length; i++) {System.out.println(array[i]);
}

 

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

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

相关文章

Web安全:文件上传漏洞详解,文件上传漏洞原理、绕过方式和防御方案。

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

Java实现链表

链表 前言一、链表的概念及结构二、链表的分类三、链表的实现无头单向非循环链表实现无头双向链表实现具体代码 四、链表习题五、顺序表和链表的区别 前言 推荐一个网站给想要了解或者学习人工智能知识的读者&#xff0c;这个网站里内容讲解通俗易懂且风趣幽默&#xff0c;对我…

51单片机-实机演示(单多个数码管)

仿真链接&#xff1a; http://t.csdnimg.cn/QAPhx 目录 一.引脚位置 二.多个显示 三 扩展 一.引脚位置 注意P00 - >A ; 这个多个的在左边,右边的A到B是控制最右边那个单个的. 接下来上显示单个的代码 #include <reg52.h> #include <intrins.h> #define u…

大字体学生出勤记录系统网页HTML源码

源码介绍 上课需要一个个点名记录出勤情况&#xff0c;就借助AI制作了一个网页版学生出勤记录系统&#xff0c; 大字体显示学生姓名和照片&#xff0c;让坐在最后排学生也能看清楚&#xff0c;显示姓名同时会语音播报姓名&#xff0c; 操作很简单&#xff0c;先导入学生姓名…

嵌入式学习 (Day:27 IPC --- 进程间通信)

IPC 进程间通信 interprocess communicate &#xff08;即&#xff1a;进程间进行数据交换&#xff09; 三大类&#xff1a; 进程间通信的方式&#xff08;共8种&#xff09; 1、古老的通信方式&#xff08;Linux设计时就有的&#xff09; 无名管道 有名…

用源码建站可能涉及知产侵权,建站的注意!

近日普推知产老杨看到央视报道一家公司用了某建站源码涉及知产侵权&#xff0c;起诉了全国八千多家公司&#xff0c;某梦自从创始人因病转给某公司后&#xff0c;也在大量起诉用其建站代码公司侵权&#xff0c;他们也都是申请了相关的著作权。 有的中小企业在运营中会涉及建站…

c++ 将指针转换为 void* 后,转换为怎么判断原指针类型?

当将指针转换为void后&#xff0c;擦除了指针所指向对象的类型信息&#xff0c;因此无法通过void指针来判断原始指针的类型。我这里有一套编程入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习编程&#xff0c;不妨点个关注&#xff0c;给个…

【面试题】JavaScript基础高频面试(下)

10、Javascript 闭包是什么,闭包形成的原因和闭包的用途 &#xff1f; 闭包&#xff08;Closure&#xff09;是 JavaScript 中的一个非常重要的概念。简单地说&#xff0c;闭包就是一个函数能够访问另一个函数的作用域。这是因为在 JavaScript 中&#xff0c;函数是一等公民&a…

Oracle直接路径读解析

目录 一、直接路径读概念二、直接路径读在OLTP和OLAP环境中的不同点三、如何禁止直接路径读方法1&#xff1a;使用事件设置方法2&#xff1a;使用隐含参数 一、直接路径读概念 直接路径读&#xff08;Direct Path Read&#xff09;是Oracle数据库中的一种数据读取机制&#xf…

10编码(数据转化为信号)

目录 数据转化为信号 数字数据编码为数字信号&#xff1a; 数字数据调制为模拟信号&#xff1a; 模拟数据编码为数字信号&#xff1a; 模拟数据调制为模拟信号&#xff1a; 数据转化为信号 数据转化为数字信号要通过编码&#xff0c;转化为模拟信号通过调制 数据又分为数字…

PXI总线测试模块-6939 矢量信号发生器

频率范围&#xff1a;250kHz&#xff5e;6GHz 6939 矢量信号发生器 6939矢量信号发生器提供频率范围250kHz~6GHz的多制式信号&#xff0c;单边带相位噪声优于-120dBc/Hz10kHz&#xff08;载波1GHz&#xff09;、EVM优于1.0%&#xff0c;能够实现高纯连续波输出、模拟调制信号输…

Linux: network: TCP: zero window size/window full 示例

最近遇到一个问题,当前机器的CPU使用率非常高,然后导致其中一个程序处理socket的数据过慢,然后出现下面的zero的示例。 下面是在接收buff用光的时候,发出的 TCP zeroWindows的消息 这种问题就是内存,CPU,网速之间的性能取舍。具体解决的话,需要看具体的需要是什么样的?…

参数高效微调PEFT(一)快速入门BitFit、Prompt Tuning、Prefix Tuning

参数高效微调PEFT(一)快速入门BitFit、Prompt Tuning、Prefix Tuning 目前&#xff0c;模型最全的网站是HuggingFace&#xff0c;但是国内需要魔法流量才能访问。另外&#xff0c;现在大模型权重文件都较大&#xff0c;也会浪费不少流量&#xff0c;因此这里推荐使用魔搭社区下…

Spring+SpringBoot面试总结(近两万字)

SpringSpringBoot面试总结 一、Spring Bean1.1、bean的生命周期&#xff08;对象的创建使用销毁&#xff09;1.1.1、准备工作1.1.2、创建Bean对象1.1.3、注册销毁 1.2、 bean的作用域1.2.1、配置方式 1.3、 spring 自动装配 bean 有哪些方式&#xff08;存疑存疑&#xff09;1.…

2024年上半年软件设计师试题及答案(回忆版)--案例题

案例题 1.缺陷识别的数据流图 摄像机原始图像 缺陷识别,特征值,颜色、纹理,是否缺陷,缺陷类型 识别结果 数据导出,供检测识别系统模型积累、训练 系统管理,质量员配置系统参数 1.实体 2.存储 3.面向对象的分析与面向对象的设计2个阶段的模型区别 4.数据组成 2.球队、…

软件测试金字塔,对号入座,你在哪层?

自从学习了软件测试,脑袋也清晰了,目标也明确了,就是不知道学到哪里了.中间有很多的困难也有很多成就感,你目前在那个阶段呢? 初级测试工程师 技能要求:需求分析,使用等价类边界值等方法进行用例设计,执行功能测试,发现提交跟踪bug,使用禅道,会在测试中会操作数据库进行检查和…

数学建模--LaTeX的基本使用

目录 1.回顾 2.设置这个页眉和页脚 3.对于字体的相关设置 4.对于这个分级标题的设置 5.列表的使用 6.插入图片 1.回顾 &#xff08;1&#xff09;昨天我们了解到了这个latex的使用基本常识&#xff0c;以及这个宏包的概念&#xff0c;区域的划分&#xff0c;不同的代码代…

电磁仿真--CST综合建模练习1

1. 简介 本文展示一个CST自带的示例&#xff0c;在三维空间中使用带线计算传输线的S参数。基板顶部的带线通过小圆柱连接到底部的短带线&#xff0c;以便绕过可能存在的障碍。 结构生成 该结构完全通过参数输入进行建模&#xff0c;参考波长为10毫米&#xff0c;因此可以轻松…

JavaWeb开发 1.Web开发 介绍

我的生命是一万次的春和景明 —— 24.5.27 一、什么是Web Web&#xff1a; 全球广域网&#xff0c;也称为万维网(www World Wide Web)&#xff0c;能够通过浏览器访问的网站 Web网站的工作流程 学习流程

kafka的安装

windows下kafka的安装 【Kafka】Windows下安装Kafka&#xff08;图文记录详细步骤&#xff09;_windows安装kafka-CSDN博客 kafka生产消息 kafka消费消息