Effective Java 案例分享(八)

39、使用注解而不是通过命名规则分类

如果需要对定义class,property,或者method进行分类管理,推荐的做法是使用注解对其添加类别,而不是通过命名规则分类。这里以JUnit为例:
在JUnit 3中,如果要写测试的方法,该方法必须以test开头,否则不会跑该测试用例。这种方式存在以下问题:

  1. 以test开头容易出现拼写错误,例如“test“写成了“tset”;
  2. 无法确认该方法只是专门跑测试用例的方法,可能是某些原因需要方法以test开头;
  3. 没有办法灵活配置测试用例,例如抛出异常则认为测试通过,但是不用写try-catch代码;

为了解决这个问题,在JUnit 4引入了注解@Test,需要测试的方法使用注解标记即可,例如下面的代码,m2不会执行

// Program containing marker annotations
public class Sample {
@Test
public static void m1() { } // Test should pass
public static void m2() { } // no test.
@Test 
public static void m3() {// Test should failthrow new RuntimeException("Boom");
}

如果期望测试方法抛出指定异常为通过,可以使用ExceptionTest:

// Program containing annotations with a parameter
public class Sample2 {@ExceptionTest(ArithmeticException.class)public static void m1() { // Test should passint i = 0;i = i / i;}@ExceptionTest(ArithmeticException.class)public static void m2() { // Should fail (wrong exception)int[] a = new int[0];int i = a[1];}@ExceptionTest(ArithmeticException.class)public static void m3() { } // Should fail (no exception)
}

40、坚持使用OVERRIDE注解

如果方法是从父类或者接口继承的方法,一定要使用OVERRIDE标记。使用OVERRIDE好处有以下几点:

  1. 方法分类,方便知道哪些方法是外部要求实现的,哪些是内部要求实现的;
  2. 方法检查,OVERRIDE标记的方法会自动检查方法是否满足要求,例如方法名,参数类型,返回值,避免拼写错误;
  3. 便于维护,无论是父类还是子类修改了OVERRIDE的方法都会有编译报错,提示开发者及时纠正方法变化带来的问题;

41、使用标记接口定义类型

标记接口内部无需要实现的方法,仅仅是通过添加该接口做类型的区分。例如Android SDK自带的Serializable接口,本身没有实现的方法,但是通过此接口标记该Class可以被序列化。除此之后我们也可以自定义标记接口,为Class打上标记。
标记接口的目的是为Class分类,快速识别Class具有哪些特征,实现了哪些功能。如果要为属性和方法添加标记,需要使用注解。

42、lambda和匿名类相比,优先使用lambda

lambda表达式是Java带来的新语法特性,它最大的优点是语法简洁:

// Anonymous class instance as a function object - obsolete!
Collections.sort(words, new Comparator<String>() {public int compare(String s1, String s2) {return Integer.compare(s1.length(), s2.length());}
});// Lambda expression as function object (replaces anonymous class)
Collections.sort(words,(s1, s2) -> Integer.compare(s1.length(), s2.length()));

lambda表达式虽然语法简洁,但是有一些不足:

  1. lambda语法没有明确参数的类型和返回值类型,造成代码的可读性变差;
  2. lambda表达式this引用的是调用方的对象,而不是匿名类的对象;

所以在以下两种情况下,还是要使用匿名类:

  1. 方法实现比较复杂,一般来说超过3行推荐使用匿名内部类;
  2. 需要使用匿名类的对象,例如this关键字,需要使用匿名内部类;

43、方法引用和lambda相比,推荐使用方法引用

在可以方法引用的情况下会比lambda表达更加简洁:

// lambda表达式
map.merge(key, 1, (count, incr) -> count + incr);
// 方法引用
map.merge(key, 1, Integer::sum);

lambda表达式中的第三个参数是把两个int相加,在这种情况下正好可以使用Integer的sum方法替换,代码更加简洁。除此之外,比较常见的情况还有执行Runnable接口:

// lambda表达式
service.execute(() -> action());
// 方法引用
service.execute(GoshThisClassNameIsHumongous::action)

以下是一张常用的方法引用和lambda表达式替换的情况:
在这里插入图片描述
总结:优先使用方法引用,其他情况使用lambda表达式。

44、多使用功能性interface

功能性interface指的是没有特定含义的接口,仅仅是完成某种功能的通用性interface,他的名称跟具体实现的需求无关,实现方法的名称也是无含义的。例如比较常用的Consumer:

List<String> list = new ArrayList<>();
list.forEach(new Consumer<String>() {@Overridepublic void accept(String str) {}
});

Consumer就是一个功能性接口,他的作用就是把功能的实现和对象分离。除此之外还有其他功能性接口:
在这里插入图片描述
Android提供了很多的功能性接口,如果这些不满足开发者的需求也可以自定义,自定义的interface建议使用@FunctionalInterface注解。

45、谨慎的使用Stream

在Java 8中提供了流式api:Stream。
Stream的特点:

  1. Stream管道是懒汉式的,直到调用了结束方法才会开始计算;
  2. Stream的语法是流式语法(类似Builder),使用方便;

Stream使用案例:

// Overuse of streams - don't do this!
public class Anagrams {public static void main(String[] args) throws IOException {Path dictionary = Paths.get(args[0]);int minGroupSize = Integer.parseInt(args[1]);try (Stream<String> words = Files.lines(dictionary)) {words.collect(groupingBy(word -> word.chars().sorted().collect(StringBuilder::new,(sb, c) -> sb.append((char)StringBuilder::append).toString())).values().stream().filter(group -> group.size() >= minGroupSize).map(group -> group.size() + ": " + group).forEach(System.out::println);}}
}

从上面的案例可以看出过度使用Stream过导致代码的可读性变差,所以在使用中应当注意以下几点:

  1. 科学的命名lambda表达式中的参数名称,提高代码可读性;
  2. 使用有益的方法提高代码的可读性;
  3. 在认为有必要的时候使用Stream,而不是滥用;

在Stream中有事情是要注意的:

  1. 普通的代码块,可以使用本地变量,但是使用lambda变量必须是final的;
  2. 普通的代码块可以使用return,break,continue等关键字改变外部的方法逻辑,但是lambda表达不可以;

在以下情况推荐使用Stream:

  1. 简单的元素转换;
  2. 过滤元素;
  3. 对每一个元素只做简单的操作,例如修改,拼接,计算等等;
  4. 对元素添加到其他集合,例如分组;
  5. 对集合搜索出符合某条件的元素;

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

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

相关文章

linux环境安装mysql数据库

一&#xff1a;查看是否自带mariadb数据库 命令&#xff1a;rpm -qa | grep mariadb 如果自带数据库则卸载掉重新安装 命令&#xff1a;yum remove mariadb-connector-c-3.1.11-2.el8_3.x86_64 二&#xff1a;将压缩文件上传到/user/local/mysql文件夹 或者直接下载 命令&a…

基于ssm+mysql+html道路养护管理系统

基于ssmmysqlhtml道路养护管理系统 一、系统介绍二、功能展示1.道路信息管理2.损害类型信息管理3.损害类型信息管理4.评定等级信息管理5.日常巡查信息管理6.定期检查信息管理 四、获取源码 一、系统介绍 系统主要功能&#xff1a;道路信息管理、损害类型信息管理、评定等级信息…

【网络原理】 (1) (应用层 传输层 UDP协议 TCP协议 TCP协议段格式 TCP内部工作机制 确认应答 超时重传 连接管理)

文章目录 应用层传输层UDP协议TCP协议TCP协议段格式TCP内部工作机制确认应答超时重传 网络原理部分我们主要学习TCP/IP协议栈这里的关键协议(TCP 和 IP),按照四层分别介绍.(物理层,我们不涉及). 应用层 我们需要学会自定义一个应用层协议. 自定义协议的原因? 当前的软件(应用…

【JAVASE】顺序和选择结构

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 顺序和选择 1. 顺序结构2. 分支结构2.1 …

Ubuntu18.04 下配置Clion

配置Clion 安装gcc、g、make Ubuntu中用到的编译工具是gcc©&#xff0c;g&#xff08;C&#xff09;&#xff0c;make(连接)。因此只需安装对应的工具包即可。Ubuntu下使用命令安装这些包&#xff1a; &#xff08;1&#xff09;安装gcc sudo apt install gcc&am…

解决Cannot resolve plugin org.apache.maven.plugins:xxxxxxxx

解决Cannot resolve plugin org.apache.maven.plugins:xxxxxxxx 方法一、检查配置设置 下图中三个方框圈出来的地方设置为自己的下载的maven地址&#xff0c;配置文件地址&#xff0c;仓库地址。刷新maven。 我个人试过没用&#xff0c;不过网上有的朋友用这个方法解决了。 …

Day 69-70:矩阵分解

代码&#xff1a; package dl;import java.io.*; import java.util.Random;/** Matrix factorization for recommender systems.*/public class MatrixFactorization {/*** Used to generate random numbers.*/Random rand new Random();/*** Number of users.*/int numUsers…

FANUC机器人实现2个RO输出信号互锁关联(互补)的具体方法

FANUC机器人实现2个RO输出信号互锁关联(互补)的具体方法 一般情况下,为了方便用户控制工装夹具上的电磁阀等控制工具,FANUC机器人出厂时给我们提供了8个RO输出信号,如下图所示,这8个RO信号可以各自单独使用。 那么,如果为了安全控制,需要将2个RO信号成对的进行安全互锁…

linux服务器安装redis

一、安装下载 下载安装参考文章 下载安装包地址&#xff1a;https://download.redis.io/releases/ 亲测有效&#xff0c;但是启动的步骤有一些问题 安装完成&#xff01;&#xff01;&#xff01; 二、启动 有三种启动方式 默认启动指定配置启动开机自启 说明&#xff1a…

下载JMeter的历史版本——个人推荐5.2.1版本

官网地址&#xff1a;https://archive.apache.org/dist/jmeter/binaries/

JVM-提问纯享版

一、内存区域 介绍下 Java 内存区域&#xff08;运行时数据区&#xff09;内存分配方式内存分配并发问题对象的访问定位的两种方式&#xff08;句柄和直接指针两种方式&#xff09; 二、垃圾回收 如何判断对象是否死亡&#xff08;两种方法&#xff09;。简单的介绍一下强引…

POI 导出 树形结构

参考文章&#xff1a;(327条消息) Excel树状数据绘制导出_excel导出树形结构_Deja-vu xxl的博客-CSDN博客https://blog.csdn.net/weixin_45873182/article/details/120132409?spm1001.2014.3001.5502 Overridepublic void exportPlus(String yearMonth, HttpServletRequest re…

【C语言】从零开始学习数组

&#x1f341; 博客主页:江池俊的博客 &#x1f4ab;收录专栏&#xff1a;C语言——探索高效编程的基石 &#x1f4bb; 其他专栏&#xff1a;数据结构探索 &#x1f4a1;代码仓库&#xff1a;江池俊的代码仓库 &#x1f3aa; 社区&#xff1a;C/C之家社区 &#x1f341; 如果觉…

【C++ 进阶】学习导论:C/C++ 进阶学习路线、大纲与目标

目录 一、C 学习路线 二、C 课程大纲与学习目标 &#xff08;1&#xff09;第一阶段&#xff1a;C 语言基础 &#xff08;2&#xff09;第二阶段&#xff1a;C 高级编程 &#xff08;3&#xff09;第三阶段&#xff1a;C 核心编程与桌面应用开发 &#xff08;4&#xf…

网络安全领域关键信息泄露事件引发关注

近日&#xff0c;一家知名网络安全公司发布了一份报告揭露了一起重大信息泄露事件。据称&#xff0c;该事件涉及大量敏感用户数据的泄露引发了全球网络安全领域的广泛关注。 根据报道&#xff0c;该事件发生在全球范围内涉及多个国家和组织。专家指出&#xff0c;此次泄露事件…

深入学习 Redis - 深挖经典数据类型之 zset

目录 前言 一、zset 类型 1.1、操作命令 zadd / zrange&#xff08;添加 / 查询&#xff09; zcard&#xff08;个数&#xff09; zcount&#xff08;区间元素个数&#xff09; zrevrange&#xff08;逆序展示&#xff09; zrangebyscore&#xff08;按分数找元素&#…

【UE5 多人联机教程】06-显示玩家名称

效果 可以看到玩家输入各自的名称&#xff0c;会显示到自己控制的角色头上。但是目前有一个BUG就是&#xff0c;当客户端加入游戏时会多创建一个服务端的角色。 步骤 1. 打开“BP_ThirdPersonCharacter”&#xff0c;添加一个控件组件&#xff0c;用于显示玩家名称 作为网格体…

内存函数讲解

&#x1f495;"痛苦难以避免&#xff0c;而磨难可以选择。"-->村上春树&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;数据在内存中的存储 内存函数就是管理内存数据的函数&#xff0c;包含于头文件<string.h>中 1.memcpy函数-->内存…

Jenkins插件管理切换国内源地址

一、替换国内插件下载地址 选择系统管理–>插件管理–> Available Plugins 并等待页面完全加载完成、这样做是为了把jenkins官方的插件列表下载到本地、接着修改地址文件、替换为国内插件地址 进入插件文件目录 cd /var/lib/jenkins/updatesdefault.json 为插件源地址…

tinymce实现将word中内容(文字图片等)直接粘贴至编辑器中——利用插件tinymce-powerpaste-plugin

TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有&#xff1a;UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。 TinyMCE的优势&#xff1a; 开源可商用&#xff0c;基于LGPL2.1 插件丰富&#xff0c;自带插件基本涵盖日常…