获取网络时间

获取网络时间 public class GetNetworkTime { public static void main(String[] args) { String webUrl2 = "http://www.baidu.com";//百度 String webUrl3 = "http://www.taobao.com";//淘宝 String webUrl4 = "http://www.ntsc.ac.cn";//中国科学院国家授时中心 String webUrl5 = "http://www.360.cn";//360 System.out.println(getWebsiteDatetime(webUrl2) + " [百度]"); System.out.println(getWebsiteDatetime(webUrl3) + " [淘宝]"); System.out.println(getWebsiteDatetime(webUrl4) + " [中国科学院国家授时中心]"); System.out.println(getWebsiteDatetime(webUrl5) + " [360安全卫士]"); } /** * 获取指定网站的日期时间 * * @param webUrl * @return * @author SHANHY * @date 2015年11月27日 */ private static String getWebsiteDatetime(String webUrl){ try { URL url = new URL(webUrl);// 取得资源对象 URLConnection uc = url.openConnection();// 生成连接对象 uc.connect();// 发出连接 long ld = uc.getDate();// 读取网站日期时间 Date date = new Date(ld);// 转换为标准时间对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);// 输出北京时间 return sdf.format(date); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } } https://blog.csdn.net/catoop/article/details/50076879

2019-10-09 · 1 min · 119 words · -

netty Reactor 模式

netty Reactor模式 Reactor模式的角色构成(Reactor模式一共有5中角色构成): Handle (句柄或描述符,在Windows下称为句柄,在Linux下称为描述符):本质上表示一种资源(比如说文件描述符,或是针对网络编程中的socket描述符),是由操作系统提供的;该资源用于表示一个个的事件,事件既可以来自于外部,也可以来自于内部;外部事件比如说客户端的连接请求,客户端发送过来的数据等;内部事件比如说操作系统产生的定时事件等。它本质上就是一个文件描述符,Handle是事件产生的发源地。 Synchronous Event Demultiplexer (同步事件分离器):它本身是一个系统调用,用于等待事件的发生(事件可能是一个,也可能是多个)。调用方在调用它的时候会被阻塞,一直阻塞到同步事件分离器上有事件产生为止。对于Linux来说,同步事件分离器指的就是常用的I/O多路复用机制,比如说select、poll、epoll等。在Java NIO领域中,同步事件分离器对应的组件就是Selector;对应的阻塞方法就是select方法。 Event Handler (事件处理器):本身由多个回调方法构成,这些回调方法构成了与应用相关的对于某个事件的反馈机制。在Java NIO领域中并没有提供事件处理器机制让我们调用或去进行回调,是由我们自己编写代码完成的。Netty相比于Java NIO来说,在事件处理器这个角色上进行了一个升级,它为我们开发者提供了大量的回调方法,供我们在特定事件产生时实现相应的回调方法进行业务逻辑的处理,即,ChannelHandler。ChannelHandler中的方法对应的都是一个个事件的回调。 Concrete Event Handler (具体事件处理器):是事件处理器的实现。它本身实现了事件处理器所提供的各种回调方法,从而实现了特定于业务的逻辑。它本质上就是我们所编写的一个个的处理器实现。 Initiation Dispatcher (初始分发器):实际上就是Reactor角色。它本身定义了一些规范,这些规范用于控制事件的调度方式,同时又提供了应用进行事件处理器的注册、删除等设施。它本身是整个事件处理器的核心所在,Initiation Dispatcher会通过 Synchronous Event Demultiplexer 来等待事件的发生。一旦事件发生,Initiation Dispatcher 首先会分离出每一个事件,然后调用事件处理器,最后调用相关的回调方法来处理这些事件。Netty中ChannelHandler 里的一个个回调方法都是由 bossGroup 或 workGroup 中的某个EventLoop来调用的。 Reactor模式流程 ① 初始化Initiation Dispatcher,然后将若干个Concrete Event Handler注册到Initiation Dispatcher中。当应用向Initiation Dispatcher注册Concrete Event Handler时,会在注册的同时指定感兴趣的事件,即,应用会标识出该事件处理器希望Initiation Dispatcher在某些事件发生时向其发出通知,事件通过Handle来标识,而Concrete Event Handler又持有该Handle。这样,事件 ————> Handle ————> Concrete Event Handler 就关联起来了。 ② Initiation Dispatcher 会要求每个事件处理器向其传递内部的Handle。该Handle向操作系统标识了事件处理器。 ③ 当所有的Concrete Event Handler都注册完毕后,应用会调用handle_events方法来启动Initiation Dispatcher的事件循环。这是,Initiation Dispatcher会将每个注册的Concrete Event Handler的Handle合并起来,并使用Synchronous Event Demultiplexer(同步事件分离器)同步阻塞的等待事件的发生。比如说,TCP协议层会使用select同步事件分离器操作来等待客户端发送的数据到达连接的socket handler上。 比如,在Java中通过Selector的select()方法来实现这个同步阻塞等待事件发生的操作。在Linux操作系统下,select()的实现中 a)会将已经注册到Initiation Dispatcher的事件调用epollCtl(epfd, opcode, fd, events)注册到linux系统中,这里fd表示Handle,events表示我们所感兴趣的Handle的事件;b)通过调用epollWait方法同步阻塞的等待已经注册的事件的发生。不同事件源上的事件可能同时发生,一旦有事件被触发了,epollWait方法就会返回;c)最后通过发生的事件找到相关联的SelectorKeyImpl对象,并设置其发生的事件为就绪状态,然后将SelectorKeyImpl放入selectedSet中。这样一来我们就可以通过Selector.selectedKeys()方法得到事件就绪的SelectorKeyImpl集合了。 ④ 当与某个事件源对应的Handle变为ready状态时(比如说,TCP socket变为等待读状态时),Synchronous Event Demultiplexer就会通知Initiation Dispatcher。 ⑤ Initiation Dispatcher会触发事件处理器的回调方法,从而响应这个处于ready状态的Handle。当事件发生时,Initiation Dispatcher会将被事件源激活的Handle作为『key』来寻找并分发恰当的事件处理器回调方法。 ⑥ Initiation Dispatcher会回调事件处理器的handle_event(type)回调方法来执行特定于应用的功能(开发者自己所编写的功能),从而相应这个事件。所发生的事件类型可以作为该方法参数并被该方法内部使用来执行额外的特定于服务的分离与分发。 ...

2019-10-03 · 1 min · 186 words · -

golang MP4文件服务器

golang MP4 文件服务器 https://studygolang.com/articles/11204 package main import ( "github.com/gorilla/handlers" "log" "net/http" "os" "time" ) func ServeHTTP(w http.ResponseWriter, r *http.Request) { video, err := os.Open("/tmp/foo.mp4") if err != nil { log.Fatal(err) } defer video.Close() http.ServeContent(w, r, "foo.mp4", time.Now(), video) } func main() { http.HandleFunc("/", ServeHTTP) _ = http.ListenAndServe(":8089", handlers.LoggingHandler(os.Stdout, http.DefaultServeMux)) }

2019-09-27 · 1 min · 50 words · -

termite

termite vim ~/.config/termite/config font = Source Code Pro 10 Termite是一种基于VTE的最小终端仿真器,它是一个模态应用程序,类似于Vim,具有插入模式和选择模式,其中键绑定具有不同的功能,Termite基于VTE库,这是一个你喜欢每天与之互动的终端,特别是当它与i3窗口管理器结合时,其主要功能包括: 灵活性。 众多主题。 有许多关键绑定可供考虑用于捷径。 与其他应用程序集成,例如Oh-my-zsh。 历史搜索。 支持bash和zsh shell。 提供了AppImages。 最小的设计用户界面。 keyboard-centric VTE-based terminal https://wiki.archlinux.org/index.php/Termite https://github.com/thestinger/termite https://ywnz.com/linuxml/4305.html

2019-09-26 · 1 min · 25 words · -

go new make

go new make https://sanyuesha.com/2017/07/26/go-make-and-new/ new 和 make 都可以用来分配空间,初始化类型,但是它们确有不同。 new(T) 返回的是 T 的指针 new(T) 为一个 T 类型新值分配空间并将此空间初始化为 T 的零值,返回的是新值的地址,也就是 T 类型的指针 *T,该指针指向 T 的新分配的零值。 p1 := new(int) fmt.Printf("p1 -> %#v \n ", p1) //(*int)(0xc42000e250) fmt.Printf("p1 point to -> %#v \n ", *p1) //0 var p2 _int i := 0 p2 = &i fmt.Printf("p2 -> %#v \n ", p2) //(_int)(0xc42000e278) fmt.Printf("p2 point to -> %#v \n ", *p2) //0 上面的代码是等价的, new(int) 将分配的空间初始化为 int 的零值, 也就是 0, 并返回 int 的指针, 这和直接声明指针并初始化的效果是相同的. ...

2019-09-21 · 3 min · 582 words · -

Go stacks

Go stacks Viper: 配置管理 Bun ORM: ORM 框架 Resty: HTTP 客户端

2019-09-17 · 1 min · 11 words · -

将cmd中命令输出保存为TXT文本文件

将cmd中命令输出保存为TXT文本文件 https://www.cnblogs.com/hongten/archive/2013/03/27/hongten_windows_cms.html 将cmd中命令输出保存为TXT文本文件 在网上看到一篇名为: “[转载]如何将cmd中命令输出保存为TXT文本文件” 例如: 将Ping命令的加长包输出到D盘的ping.txt文本文件。 在D:目录下创建文本文件ping.txt (这步可以省略,偶尔提示无法创建文件时需要) 在提示符下输入ping <www.idoo.org.ru> -t > D:ping.txt 这时候发现D盘下面的ping.txt里面已经记录了所有的信息 备注: 只用">“是覆盖现有的结果,每一个命令结果会覆盖现有的txt文件,如果要保存很多命令结果的话,就需要建立不同文件名的txt文件。 那么有没有在一个更好的办法只用一个txt文件呢?答案是肯定的,要在同一个txt文件里面追加cmd命令结果,就要用”»“替换”>" 就可以了.

2019-09-17 · 1 min · 19 words · -

Making ipset,iptables persistent

Making ipset,iptables persistent ipset save > /etc/ipset.conf systemctl enable ipset.service iptables-save -f /etc/iptables/iptables.rules systemctl enable iptables.service https://wiki.archlinux.org/index.php/Ipset https://wiki.archlinux.org/index.php/Iptables

2019-09-09 · 1 min · 18 words · -

圈复杂度(Cyclomatic Complexity)

圈复杂度(Cyclomatic Complexity) 圈复杂度(Cyclomatic Complexity)是一种代码复杂度的衡量标准。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立线性路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和维护。程序的可能错误和高的圈复杂度有着很大关系。 下面这个实例中,单元测试的覆盖率可以达到100%,但是很容易发现这其中已经漏掉了一个NPE的测试用例。case1方法的圈复杂度为2,因此至少需要2个用例才能完全覆盖到其所有的可能情况。 //程序原代码,圈复杂度为 2 public String case1(int num) { String string = null; if (num == 1) { string = “String”; } return string.substring(0); } //上面代码的单元测试代码 public void testCase1(){ String test1 = case1(1); } 圈复杂度主要与分支语句 (if、else、,switch 等) 的个数成正相关。当一段代码中含有较多的分支语句,其逻辑复杂程度就会增加。 圈复杂度的计算方法,可以参考这篇文章: http://blog.csdn.net/lg707415323/article/details/7790660 可以直接降低圈复杂度的 9 种重构技术 (针对结构化编程) Composing Methods(重新组织你的函数) Extract Method(提炼函数) Substitute Algorithm(替换你的算法) Simplifying Conditional Expressions(简化条件表达式) Decompose Conditional(分解表达式) Consolidate Conditional Expression(合并表达式) Consolidate Duplicate Conditional Fragments (合并重复的条件) Remove Control Flag(移除控制标记) Making Method Calls Simpler(简化函数调用) Separate Query from Modifier(将查询函数和修改函数分离) <2>PARAMETERIZE Method(令函数携带参数) ...

2019-09-09 · 1 min · 91 words · -

数据库事务, 锁

数据库事务, 锁 数据库锁 因为数据库要解决并发控制问题。在同一时刻,可能会有多个客户端对同一张表进行操作,比如有的在读取该行数据,其他的尝试去删除它。为了保证数据的一致性,数据库就要对这种并发操作进行控制,因此就有了锁的概念。 锁的分类 从对数据库操作的类型分 读锁(共享锁):针对同一块数据,多个读操作可以同时进行而不会互相影响。由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写。 写锁(排它锁):当当前写操作没有完成之前,它会阻断其他写锁和读锁。由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁。 从锁定的数据范围分 表锁:锁定某个表。 行锁 :锁定某行。 为了尽可能 提高数据库的并发度,每次锁定的数据范围越小越好。理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很耗费资源的事情。因此数据库系统需要在高并发响应和系统性能两方面进行平衡,这样就产生了“锁粒度”的概念。 锁粒度 表锁:管理锁的开销最小,同时允许的并发量也最小的锁机制。MyIsam存储引擎使用的锁机制。当要写入数据时,把整个表都锁上,此时其他读、写动作一律等待。在MySql中,除了MyIsam存储引擎使用这种锁策略外,MySql本身也使用表锁来执行某些特定动作,比如alter table. 行锁:可以支持最大并发的锁策略。InnoDB和Falcon两张存储引擎都采用这种策略。 MySql是一种开放的架构,你可以实现自己的存储引擎,并实现自己的锁粒度策略,不像Oracle,你没有机会改变锁策略,Oracle采用的是行锁。从大到小,mysql服务器仅支持表级锁,行锁需要存储引擎完成。粒度越精细,并发性越好。即行锁的并发性最好,但需要存储引擎的支持。 数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。 事务和锁机制是什么关系? 开启事务就自动加锁了吗? 1、事务与锁是不同的。事务具有ACID(原子性、一致性、隔离性和持久性),锁是用于解决隔离性的一种机制。 2、事务的隔离级别通过锁的机制来实现。另外锁有不同的粒度,同时事务也是有不同的隔离级别的。 3、开启事务就自动加锁。 ql规范定义的事务的隔离级别: 1.READ UNCOMMITTED(读取未提交内容) 所有事务可以看到未提交事务的执行结果,本隔离级别很少用到实际应用中,读取未提交的数据,又称为“脏读”。 2.READ COMMITTED(读取提交内容) 大多数数据库的默认隔离级别是此级别,但不是MySQL默认的。一个事务在开始的时候只能看见已提交事务所做的改变。一个事务从开始到提交前所做的任何改变都是不可见的,除非提交。这种隔离级别也称为不可重复读。 3.REPEATABLE READ(可重复读) 此隔离级别是为了解决不可重复读隔离级别导致的问题即一个事务多个实例并发读取数据时会看到不同的结果。可重复读描述的是一个事务在处理数据时,多次查询此数据得到的结果是一样的。MySQL的InnoDB存储引擎通过多版本并发控制(Multi_Version Concurrency Control, MVCC)机制来解决该问题。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时, 另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。(幻读描述的是MVCC不能阻止插入新的数据,导致多次查询时数据记录不一致。) 4.SERIALIZABLE(可串行化) 可串行化是最高的隔离级别,它通过强制事务排序,使之不可重读,解决了幻读的问题。此隔离级别会在每个读的数据行上加共享锁,使用这种隔离级别会产生大量的超时现象,一般实际开发中不会用到。该类型在A客户端操作test.test1表时会锁定该数据,如果B客户端想要操作test.test1就需要等待A客户端释放。 这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如: 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。 幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。 mysql加锁机制: 根据类型可分为共享锁(SHARED LOCK)和排他锁(EXCLUSIVE LOCK)或者叫读锁(READ LOCK)和写锁(WRITE LOCK)。 根据粒度划分又分表锁和行锁。表锁由数据库服务器实现,行锁由存储引擎实现。 mysql提供了3种事务型存储引擎,InnDB、NDB Cluster和Falcon。 一个事务执行的任何过程中都可以获得锁,但是只有事务提交或回滚的时候才释放这些锁。这些都是隐式锁定,也可以显式锁定,InnoDB支持显式锁定,例如: SELECT …. LOCK IN SHARE MODE (加共享锁) SELECT …..FOR UPDATE(加排他锁) ...

2019-09-09 · 1 min · 102 words · -

0day

0day 0day,中文意思"0日/零日"或"零日漏洞"或"零时差攻击", 零日这个词历史很悠久,最早出现是在战争中,将一些大规模可毁灭世界的事物 (一般是武器) 称之为零日危机 (类似的还有末日时钟), 在世界毁灭之后,重新建立新文明的第一天,即称之为第0天。 后来引入到黑客文化,将一些大规模、致命性、高威胁性、能够造成巨大破坏的漏洞也称为零日漏洞 (并不是所有漏洞都叫0day), 缩写即为: 0day。 版权声明: 本文为CSDN博主「EDDJH_31」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接: https://blog.csdn.net/EDDJH_31/article/details/67637890

2019-09-09 · 1 min · 19 words · -

CPU steal time

CPU steal time Steal Time(st),用来衡量被虚拟机监视器(Hypervisor)偷去给其它虚拟机使用的 CPU 时间所占的比例。 https://blog.csdn.net/jessysong/article/details/73571878 Netflix 很关注 CPU 的 Steal Time。他们的策略是: 如果是当前虚拟机的 Steal Time 超过了你们设置的阈值,他们会关闭这台虚拟机并且在另外一台物理机上面重启。 如果你想要部署虚拟环境 (例如: Amazon EC2) , steal time 就是你想要关注的性能指标之一。 如果这个指标的数值很高,那么说明机器状态非常糟糕。什么是 steal time?什么会引发高 steal time?多少才是警戒值 (你需要做什么) ? CPU Steal Time 的定义 From ibm: Steal time is the percentage of time a virtual CPU waits for a real CPU while the hypervisor is servicing another virtual processor. 你的虚拟机 (VM) 会与虚拟环境的宿主机上的多个虚拟机实例共享物理资源。其中之一共享的就是CPU时间切片。如果你的VM的物理机虚拟比是1/4, 那么它的CPU使用率不会限制于25%的CPU时间切片-它能够使用超过它设置的虚拟比。 (有别于内存的使用,内存大小是严格控制的) 。 哪里可以看到CPU Steal Time? 你可以使用Linux 的 TOP 命令来看到实时的一些性能指标。CPU相关的其中一行内容如下: ...

2019-09-03 · 1 min · 188 words · -

svn diff

svn diff 转载于: http://blog.sina.com.cn/s/blog_4e5668630100ag2u.html http://www.upsdn.net/html/2004-12/65.html $ svn diff -r 2:3 rules.txt (1)Index: rules.txt (2)=================================================================== (3)- rules.txt (revision 2) (4)+++ rules.txt (revision 3) (5)@@ -1,4 +1,4 @@ (6)Be kind to others (7)-Freedom = Chocolate Ice Cream (8)+Freedom = Responsibility (9)Everything in moderation (10)Chew with your mouth open 第一行,显示文件 第二行,分隔符 第三行,老版本用"-“表示 第四行,新版本用”+“表示 第五行,(5)@@ -1,4 +1,4 @@ -表示老版本,+++表示新版本,@@ (老版本) 起始行,行数 (新版本) 起始行,行数 应改为,老版本从第1行开始显示,共显示4行,即显示1~3行; 新版本一样 第六行,两个版本都有 第七行,只有老版本有 第八行,只有新版本有 第九行,两个版本都有 第十行,两个版本都有 unified diff format统一差异格式 一种标准的文件比较格式, 不同的行之前标上’+‘或者’-‘表示不同的文件, 新文件用’+‘表示, 旧文件用’-‘表示 ...

2019-09-02 · 1 min · 113 words · -

MySQL update in

MySQL update in EXPLAIN UPDATE table0 w SET w.field0 ='foo' WHERE (w.key0,w.key1,w.) IN ( SELECT a.* FROM ( SELECT w1.key0,w1.key1,w1.key2 FROM table0 w1 WHERE w1.field0 IS NULL AND w1.key2=0 LIMIT 10) AS a ); EXPLAIN UPDATE table0 w0 JOIN (SELECT *FROM table0 w1 WHERE w1.field0 IS NULL AND w1.key0=0 LIMIT 10) w2 ON w0.key0=w2.key0 AND w0.key1=w2.key1 AND w0.key2=w2.key2 SET w0.field0='foo'

2019-08-29 · 1 min · 60 words · -

MySQL update 嵌套 select

MySQL update 嵌套 select 当你希望更新一批值,且值是通过select条件查询出来时,下面这个错误应该不陌生 You can’t specify target table ‘x’ for update in FROM clause。 错误示范 1: A B 有关联同一个key_id , 根据 B表符合条件 -> 更新A表val值。 UPDATE A a SET a.val = 2 WHERE a.id IN ( SELECT a.id FROM A LEFT JOIN B ON b.key_id = a.key_id WHERE b.satisfy = 1) 解决思路 1: 使用 INNER JOIN (最简洁) UPDATE A a INNER JOIN B b ON b.key_id = a.key_id SET a.val = 2 WHERE b.satisfy = 1 ...

2019-08-28 · 1 min · 112 words · -

Screeps

Screeps https://screeps-cn.github.io/introduction.html https://github.com/rustyscreeps/screeps-game-api https://twodam.net/Tutorial-for-Screeps-0 https://github.com/aphistic/screeps-deployer https://github.com/rustyscreeps/screeps-starter-rust https://github.com/hinshun/screepsapi

2019-08-27 · 1 min · 7 words · -

toml

toml https://toml.io/cn/ # comments java https://github.com/mwanji/toml4j goland https://github.com/pelletier/go-toml/tree/v2

2019-08-24 · 1 min · 8 words · -

slf4j 打印java异常堆栈信息

slf4j 打印java异常堆栈信息 SLF4J 1.6.0以前的版本,如果打印异常堆栈信息,必须用 log.error(String msg, Throwable t) log.info等对应方法. 如果msg含有变量,一般用String.format方法格式化msg. 如果用 error(String format, Object… arguments) 等其它方法,异常堆栈信息会丢失. 幸好,SLF4J 1.6.0以后的版本对这个不友好的异常信息log改进了. error(String format, Object… arguments)这个方法也会打印异常堆栈信息,只不过规定throwable对象必须为 最后一个参数.如果不遵守这个规定,异常堆栈信息不会log出来. 官方FAQ: http://www.slf4j.org/faq.html Can I log an exception without an accompanying message? In short, no. If e is an Exception, and you would like to log an exception at the ERROR level, you must add an accompanying message. For example, logger.error(“some accompanying message”, e); You might legitimately argue that not all exceptions have a meaningful message to accompany them. Moreover, a good exception should already contain a self explanatory description. The accompanying message may therefore be considered redundant. ...

2019-08-23 · 3 min · 492 words · -

回文,palindrome

回文,palindrome 回文,英文palindrome,指一个顺着读和反过来读都一样的字符串,比如 madam

2019-08-19 · 1 min · 3 words · -

Java Double 浮点数 比较大小 & 相等比较

‘Java Double 浮点数 比较大小 & 相等比较’ public class DoubleUtils { private static final double DEFAULT_DELTA = 0.000001; //默认比较精度 //比较2个double值是否相等 (默认精度) public static boolean considerEqual(double v1, double v2) { return considerEqual(v1, v2, DEFAULT_DELTA); } //比较2个double值是否相等 (指定精度) public static boolean considerEqual(double v1, double v2, double delta) { return Double.compare(v1, v2) == 0 || considerZero(v1 - v2, delta); } //判断指定double是否为0 (默认精度) public static boolean considerZero(double value) { return considerZero(value, DEFAULT_DELTA); } //判断指定double是否为0 (指定精度) public static boolean considerZero(double value, double delta) { return Math.abs(value) <= delta; } /** * @param v1 v1 * @param v2 v2 * @return result * v1>v2, result = 1 * v1=v2, result =0 * v1<v2, result =-1 */ public static int compare(double v1, double v2) { if (v1 - v2 > DEFAULT_DELTA) { return 1; } else if (considerEqual(v1, v2)) { return 0; } else { return -1; } } } https://blog.csdn.net/z69183787/article/details/81318486

2019-08-19 · 1 min · 143 words · -