All posts by 龙生
max_allowed_packet设置问题
最近在运行的项目出现了一个线上事故,有人反映商城的东西下不了单了,到后台看了一下,果然报了一个错 Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1046 > 1024). You can change this value on the server by setting the max_allowed_packet' variable.; ]; Packet for query is too large (1046 > 1024). You can change this value on the server by setting the max_allowed_packet' variable.; nested exception is com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1046 > 1024). You can change this value on the server by setting the max_allowed_packet' variable. 其实上面的报错信息就给出了解决方案了,原来mysql根据配置文件会限制server接受的数据包大小。如果一次插入数据库中的数据太大的话就会失败,官方也有这方面的介绍 官方介绍 用命令行查看show VARIABLES like '%max_allowed_packet%';果然max_allowed_packet太小了 解决方法 1、修改配置文件(推荐) 在mysql中的my.ini文件中(在programdata隐藏文件中),修改max_allowed_packet的值 比如:max_allowed_packet=128M 然后重启mysql就可以 2、命令行中设置 set global max_allowed_packet = […]
View Details带你入门consul
consul consul用于微服务下的服务治理,主要特点有:服务发现、服务配置、健康检查、键值存储、安全服务通信、多数据中心等。 什么叫服务治理发现?起初我们的服务比较单一,各服务之间通过接口就能访问。后面服务越来越复杂出现了分布式,为了不引起单点问题,必然是多服务部署,如果还用原来的方式直接连接,那么在某个服务挂掉或者修改了信息,就会导致连接失败。如果连接端能够不去关心具体的服务配置,他只要连接到那个服务,后续的工作由其它服务保证,包括负载均衡、健康检查等,保证总有可用的连接那就行了,consul就是做这个的,当然,它的功能远不止这些,这里只是以服务发现为例。 与它同类的东西,还有Eureka、zooKeeper、etcd等也能做这些事,说不上谁好谁坏,看场景挑合适的吧,不过Eureka现在已经闭源了,这个还是建议不要去用这个了。 consul下载 consule的安装超级简单,去官方下载地址Download ,找到自已对应系统的压缩包,解压后里面就一个文件consul, 将这个文件放到你的PATH中,就能直接用了。 验证下安装成功没有, 看到下面的提示就行了。
1 2 3 |
$ consul version Consul v1.7.2 Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents) |
consul的CLI操作 consul提供了cli的命令操作,如启动代理、键值存储、注册/注销服务、加入集群等,这个consul提供的HTTP的API操作也是一样的,只是这里都是shell的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
$ consul Usage: consul [--version] [--help] <command> [<args>] Available commands are: acl Interact with Consul's ACLs agent Runs a Consul agent catalog Interact with the catalog config Interact with Consul's Centralized Configurations connect Interact with Consul Connect debug Records a debugging archive for operators event Fire a new event exec Executes a command on Consul nodes force-leave Forces a member of the cluster to enter the "left" state info Provides debugging information for operators. intention Interact with Connect service intentions join Tell Consul agent to join cluster keygen Generates a new encryption key keyring Manages gossip layer encryption keys kv Interact with the key-value store leave Gracefully leaves the Consul cluster and shuts down lock Execute a command holding a lock login Login to Consul using an auth method logout Destroy a Consul token created with login maint Controls node or service maintenance mode members Lists the members of a Consul cluster monitor Stream logs from a Consul agent operator Provides cluster-level tools for Consul operators reload Triggers the agent to reload configuration files rtt Estimates network round trip time between nodes services Interact with services snapshot Saves, restores and inspects snapshots of Consul server state tls Builtin helpers for creating CAs and certificates validate Validate config files/directories version Prints the Consul version watch Watch for changes in Consul |
Agent启动 consul是通过Agent来运行的,Agent又分为Server Agent和Client Agent两种类型,这两类型基本上是没区别的,Server Agent会将服务的消息存储起来,至少要启动一个Server Agent,为了防止单点,集群环境中推荐3-5个。 Client Agent主要用于注销服务、健康检查及转发Server Agent的查询等,它相当于一个代理,所以他必须在集群的每台主机上都要运行。 先看下Agent的常用配置
1 |
$ consul agent --help |
--server 定义运行server agent --data-dir 配置consul数据存储路径 --bootstrap-expect :期望的server节点数目,consul一直等到指定sever数目的时候才会引导整个集群 --bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0 --node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名 --ui: web的管理ui,查看服务和节点 --config-dir:配置文件目录,所有以.json结尾的文件都会被加载,可以是服务或consul自身的配置 --client:提供HTTP、DNS、RPC等服务,默认是127.0.0.1,不对外提供服务,如果需要则改成0.0.0.0 我本地没有虚拟机,也没用Docker操作,所以,如果要同时启动Server和Client的话,我就用的改端口的方式,当然生产环境肯定就没有这个了,它都是一台机器启动一个Agent, 这里只是测试用的。 启动一个Server Agent
1 |
$ consul agent --server=true --ui=true --data-dir=/tmp/consul --node=server1 --dev |
上面的 --server表示以server方式,--ui 会开启一个web ui管理界面, --dev 表示开发者模式,不需要ACL验证。不然那个web ui的打不开会报没有权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
==> Starting Consul agent... Version: 'v1.7.2' Node ID: 'f6272369-098a-1412-ed86-6e2076c1e5e4' Node name: 'server1' Datacenter: 'dc1' (Segment: '<all>') Server: true (Bootstrap: false) Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600) Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302) Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false ==> Log data will now stream in as it occurs: 2020-04-01T14:28:52.579+0800 [DEBUG] agent.tlsutil: Update: version=1 2020-04-01T14:28:52.580+0800 [DEBUG] agent.tlsutil: OutgoingRPCWrapper: version=1 2020-04-01T14:28:52.580+0800 [INFO] agent.server.raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:f6272369-098a-1412-ed86-6e2076c1e5e4 Address:127.0.0.1:8300}]" 2020-04-01T14:28:52.580+0800 [INFO] agent.server.raft: entering follower state: follower="Node at 127.0.0.1:8300 [Follower]" leader= 2020-04-01T14:28:52.581+0800 [INFO] agent.server.serf.wan: serf: EventMemberJoin: server1.dc1 127.0.0.1 2020-04-01T14:28:52.581+0800 [INFO] agent.server.serf.lan: serf: EventMemberJoin: server1 127.0.0.1 2020-04-01T14:28:52.581+0800 [INFO] agent.server: Adding LAN server: server="server1 (Addr: tcp/127.0.0.1:8300) (DC: dc1)" 2020-04-01T14:28:52.581+0800 [INFO] agent.server: Handled event for server in area: event=member-join server=server1.dc1 area=wan 2020-04-01T14:28:52.581+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8600 network=tcp 2020-04-01T14:28:52.582+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8600 network=udp 2020-04-01T14:28:52.582+0800 [INFO] agent: Started HTTP server: address=127.0.0.1:8500 network=tcp 2020-04-01T14:28:52.582+0800 [INFO] agent: Started gRPC server: address=127.0.0.1:8502 network=tcp 2020-04-01T14:28:52.582+0800 [INFO] agent: started state syncer ==> Consul agent running! |
启动Client Agent
1 |
$ consul agent --data-dir=/tmp/consul_client --join=127.0.0.1:8301 --serf-lan-port=8303 --serf-wan-port=8305 --dns-port=8601 --server-port=8304 --http-port=8503 --server=false --config-dir=./consul.d --enable-script-checks --node=client1 |
上面有一个--join表示加入到集群中,写server agent的地址就行。 config-dir的配置目录下面一个服务的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "service":{ "name":"web", "tags":[ "local" ], "port":80, "check":{ "name":"ping", "args":["/usr/bin/curl","-s", "http://localhost/"], "interval":"10s" } } } |
上面的命令运行后,会启动一个名字为“web"的服务,并提供健康检查。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
==> Starting Consul agent... Version: 'v1.7.2' Node ID: 'e1c8f283-f5c4-27e7-c29c-64666df1c52b' Node name: 'client1' Datacenter: 'dc1' (Segment: '') Server: false (Bootstrap: false) Client Addr: [127.0.0.1] (HTTP: 8503, HTTPS: -1, gRPC: -1, DNS: 8601) Cluster Addr: 192.168.0.103 (LAN: 8303, WAN: 8305) Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false ==> Log data will now stream in as it occurs: 2020-04-01T00:00:49.227+0800 [INFO] agent.client.serf.lan: serf: EventMemberJoin: client1 192.168.0.103 2020-04-01T00:00:49.231+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8601 network=udp 2020-04-01T00:00:49.232+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8601 network=tcp 2020-04-01T00:00:49.232+0800 [INFO] agent: Started HTTP server: address=127.0.0.1:8503 network=tcp ==> Joining cluster... 2020-04-01T00:00:49.232+0800 [INFO] agent: (LAN) joining: lan_addresses=[127.0.0.1:8301] 2020-04-01T00:00:49.233+0800 [WARN] agent.client.memberlist.lan: memberlist: Refuting a dead message (from: client1) 2020-04-01T00:00:49.233+0800 [INFO] agent.client.serf.lan: serf: EventMemberJoin: server1 127.0.0.1 2020-04-01T00:00:49.233+0800 [INFO] agent.client: adding server: server="server1 (Addr: tcp/127.0.0.1:8300) (DC: dc1)" 2020-04-01T00:00:49.233+0800 [INFO] agent: (LAN) joined: number_of_nodes=1 2020-04-01T00:00:49.233+0800 [INFO] agent: Join completed. Initial agents synced with: agent_count=1 2020-04-01T00:00:49.233+0800 [INFO] agent: started state syncer ==> Consul agent running! 2020-04-01T00:00:49.235+0800 [INFO] agent: Synced node info 2020-04-01T00:00:49.235+0800 [INFO] agent: Synced service: service=web 2020-04-01T00:00:53.316+0800 [INFO] agent: Synced check: check=service:web |
查看下,启动的Agent
1 2 3 4 |
$ ./consul members Node Address Status Type Build Protocol DC Segment server1 127.0.0.1:8301 alive server 1.7.2 2 dc1 <all> client1 127.0.0.1:8303 alive client 1.7.2 2 dc1 <default> |
web管理界面 可以查看服务的定义和节点,访问[web管理界面](http://127.0.0.1:8500/ui) HTTP API consul除了提供DNS外,还提供Http的操作,如注册服务、查看节点、查看服务信息等,一般都是通过API来操作的。 如我上面定义的 "web"服务,通过下面的API查询,就能得到具体的IP地址和端口,这样就能直接连到那台服务了。 其它更详情API操作,可以自已去参照官方的文档 API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
$ curl http://127.0.0.1:8500/v1/catalog/service/web [ { "ID": "e1c8f283-f5c4-27e7-c29c-64666df1c52b", "Node": "client1", "Address": "127.0.0.1", "Datacenter": "dc1", "TaggedAddresses": { "lan": "127.0.0.1", "lan_ipv4": "127.0.0.1", "wan": "127.0.0.1", "wan_ipv4": "127.0.0.1" }, "NodeMeta": { "consul-network-segment": "" }, "ServiceKind": "", "ServiceID": "web", "ServiceName": "web", "ServiceTags": [ "local" ], "ServiceAddress": "", "ServiceWeights": { "Passing": 1, "Warning": 1 }, "ServiceMeta": {}, "ServicePort": 80, "ServiceEnableTagOverride": false, "ServiceProxy": { "MeshGateway": {}, "Expose": {} }, "ServiceConnect": {}, "CreateIndex": 15, "ModifyIndex": 15 } ] |
from:https://zhuanlan.zhihu.com/p/122340918
View DetailsMySQL show processlist说明
show processlist和show full processlist processlist命令的输出结果显示了有哪些线程在运行,不仅可以查看当前所有的连接数,还可以查看当前的连接状态帮助识别出有问题的查询语句等。 如果是root帐号,能看到所有用户的当前连接。如果是其他普通帐号,则只能看到自己占用的连接。showprocesslist只能列出当前100条。如果想全部列出,可以使用SHOW FULL PROCESSLIST命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
mysql> show processlist; +----+------+--------------------+------+---------+-------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+--------------------+------+---------+-------+-------+------------------+ | 1 | root | localhost | NULL | Sleep | 12 | | NULL | | 2 | root | 192.168.100.1:7437 | test | Sleep | 8035 | | NULL | | 3 | root | 192.168.100.1:7438 | NULL | Sleep | 24348 | | NULL | | 5 | root | 192.168.100.1:7443 | NULL | Sleep | 24317 | | NULL | | 7 | root | 192.168.100.1:7450 | test | Sleep | 24272 | | NULL | | 9 | root | 192.168.100.1:5152 | test | Query | 0 | init | show processlist | +----+------+--------------------+------+---------+-------+-------+------------------+ 6 rows in set mysql> show full processlist; +----+------+--------------------+------+---------+-------+-------+-----------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+--------------------+------+---------+-------+-------+-----------------------+ | 1 | root | localhost | NULL | Sleep | 19 | | NULL | | 2 | root | 192.168.100.1:7437 | test | Sleep | 8042 | | NULL | | 3 | root | 192.168.100.1:7438 | NULL | Sleep | 24355 | | NULL | | 5 | root | 192.168.100.1:7443 | NULL | Sleep | 24324 | | NULL | | 7 | root | 192.168.100.1:7450 | test | Sleep | 24279 | | NULL | | 9 | root | 192.168.100.1:5152 | test | Query | 0 | init | show full processlist | +----+------+--------------------+------+---------+-------+-------+-----------------------+ 6 rows in set |
各个列的含义: ①.id列,用户登录mysql时,系统分配的"connection_id",可以使用函数connection_id()查看 ②.user列,显示当前用户。如果不是root,这个命令就只显示用户权限范围的sql语句 ③.host列,显示这个语句是从哪个ip的哪个端口上发的,可以用来跟踪出现问题语句的用户 ④.db列,显示这个进程目前连接的是哪个数据库 ⑤.command列,显示当前连接的执行的命令,一般取值为休眠(sleep),查询(query),连接(connect)等 ⑥.time列,显示这个状态持续的时间,单位是秒 ⑦.state列,显示使用当前连接的sql语句的状态,很重要的列。state描述的是语句执行中的某一个状态。一个sql语句,以查询为例,可能需要经过copying to tmp table、sorting result、sending data等状态才可以完成 ⑧.info列,显示这个sql语句,是判断问题语句的一个重要依据 在主从复制环境中,show processlist或show full processlist对于判断状态很有帮助,例如下面的state列: from:https://www.cnblogs.com/flzs/p/11044689.html
View Detailsmysql select into的用法
MySQL不支持Select Into语句直接备份表结构和数据,一些种方法可以代替,如下:
1 2 3 4 |
#MYSQL不支持: Select * Into new_table_name from old_table_name; 这是sql server中的用法 #替代方法: Create table new_table_name (Select * from old_table_name); |
from:https://blog.csdn.net/zwldx/article/details/82227533
View Detailsgit 如何取消add操作
可以直接使用命令 git reset HEAD 这个是整体回到上次一次操作 绿字变红字(撤销add) 如果是某个文件回滚到上一次操作: git reset HEAD 文件名 红字变无 (撤销没add修改) git checkout — 文件 from:https://www.cnblogs.com/jpfss/p/11888157.html
View DetailsMySql时间戳函数
参考链接:https://www.cnblogs.com/jhy-ocean/p/5560857.html MySql时间戳涉及的函数 date_format(date, format) 函数,MySQL日期格式化函数date_format() unix_timestamp() 函数 str_to_date(str, format) 函数 from_unixtime(unix_timestamp, format) 函数,MySQL时间戳格式化函数from_unixtime 时间转字符串
1 2 3 |
select date_format(now(), '%Y-%m-%d'); #结果:2016-01-05 |
时间转时间戳
1 2 3 |
select unix_timestamp(now()); #结果:1452001082 |
字符串转时间
1 2 3 |
select str_to_date('2016-01-02', '%Y-%m-%d %H'); #结果:2016-01-02 00:00:00 |
字符串转时间戳
1 2 3 |
select unix_timestamp('2016-01-02'); #结果:1451664000 |
时间戳转时间
1 2 3 |
select from_unixtime(1451997924); #结果:2016-01-05 20:45:24 |
时间戳转字符串
1 2 3 |
select from_unixtime(1451997924,'%Y-%d'); 结果:2016-01-05 20:45:24 |
附表 MySQL日期格式化(format)取值范围。 值 含义 秒 %S、%s 两位数字形式的秒( 00,01, …, 59) 分 %I、%i 两位数字形式的分( 00,01, …, 59) 小时 %H 24小时制,两位数形式小时(00,01, …,23) %h 12小时制,两位数形式小时(00,01, …,12) %k 24小时制,数形式小时(0,1, …,23) %l 12小时制,数形式小时(0,1, …,12) %T 24小时制,时间形式(HH:mm:ss) %r 12小时制,时间形式(hh:mm:ss AM 或 PM) %p AM上午或PM下午 周 %W 一周中每一天的名称(Sunday,Monday, …,Saturday) %a 一周中每一天名称的缩写(Sun,Mon, …,Sat) %w 以数字形式标识周(0=Sunday,1=Monday, …,6=Saturday) %U 数字表示周数,星期天为周中第一天 %u 数字表示周数,星期一为周中第一天 天 %d 两位数字表示月中天数(01,02, …,31) %e 数字表示月中天数(1,2, …,31) %D 英文后缀表示月中天数(1st,2nd,3rd […]
View Details装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。 我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。 介绍 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。 何时使用:在不想增加很多子类的情况下扩展类。 如何解决:将具体功能职责划分,同时继承装饰者模式。 关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。 应用实例: 1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。 2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。 缺点:多层装饰比较复杂。 使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。 注意事项:可代替继承。 实现 我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。 RedShapeDecorator 是实现了 ShapeDecorator 的实体类。 DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。 步骤 1 创建一个接口: Shape.java
1 2 3 |
public interface Shape { void draw(); } |
步骤 2 创建实现接口的实体类。 Rectangle.java
1 2 3 4 5 6 7 |
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Shape: Rectangle"); } } |
Circle.java
1 2 3 4 5 6 7 |
public class Circle implements Shape { @Override public void draw() { System.out.println("Shape: Circle"); } } |
步骤 3 创建实现了 Shape 接口的抽象装饰类。 ShapeDecorator.java
1 2 3 4 5 6 7 8 9 10 |
public abstract class ShapeDecorator implements Shape { protected Shape decoratedShape;public ShapeDecorator(Shape decoratedShape){ this.decoratedShape = decoratedShape; } public void draw(){ decoratedShape.draw(); } } |
步骤 4 创建扩展了 ShapeDecorator 类的实体装饰类。 RedShapeDecorator.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class RedShapeDecorator extends ShapeDecorator { public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); } @Override public void draw() { decoratedShape.draw(); setRedBorder(decoratedShape); } private void setRedBorder(Shape decoratedShape){ System.out.println("Border Color: Red"); } } |
步骤 5 使用 RedShapeDecorator 来装饰 Shape 对象。 […]
View DetailsGuava 快速入门(一)
Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。 Guava 是Java的工具集,提供了一些常用的便利的操作工具类,减少因为 空指针、异步操作等引起的问题BUG,提高开发效率。 本文主要介绍了Guava常用的工具方法,快速入门Guava。 1、基本工具(Base utils) 1. Optional null 值出现在代码中,有如下缺点: 语义模糊,引起歧义。例如,Map.get(key)返回Null时,可能表示map中的值是null,亦或map中没有key对应的值。 在应用层面可能造成混乱,出现令人意外的错误。 为了尽量避免程序中的null值,guava提供了Optional对数据进行封装。如果值为空则立即抛出异常,并且提供了Absent和Present两个子类分别表示值缺失和值存在的情形,来增强null的语义。 常用方法如下: isPresent():如果Optional包含非null的引用(引用存在),返回true get() :如果Optional为NULL将触发异常
1 2 3 4 5 6 7 8 |
public static void test(){ Optional<Integer> possible = Optional.fromNullable(5); //创建允许null值的Optional if(possible.isPresent()){//包含的引用非null的(引用存在),返回true System.out.println(possible.get()); }else{ System.out.println("possible is null"); } } |
or(defaultvalue) :包含的引用缺失(null),返回默认的值,否则返回本身 orNull():包含的引用缺失,返回null asSet():如果引用存在,返回只有单一元素的集合;若为NULl返回空集合 2. 先决条件 Preconditions Preconditions 提供了判断条件是否合法的静态方法,如果不符合要求会抛出异常。类似断言。 方法声明(不包括额外参数) 描述 检查失败时抛出的异常 checkArgument(boolean) 检查boolean是否为true,用来检查传递给方法的参数 IllegalArgumentException checkNotNull(T) 检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNull NullPointerException checkState(boolean) 用来检查对象的某些状态。 IllegalStateException checkElementIndex(int index, int size) 检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<size IndexOutOfBoundsException checkPositionIndex(int index, int size) 检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=size IndexOutOfBoundsException checkPositionIndexes(int start, int end, int size) 检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效 IndexOutOfBoundsException 每个判断方法都有三个多态方法: 没有额外参数:抛出的异常中没有错误消息; 有一个Object对象作为额外参数:抛出的异常使用Object.toString() 作为错误消息; 有一个String对象作为额外参数,并且有一组任意数量的附加Object对象:这个变种处理异常消息的方式有点类似printf,但考虑GWT的兼容性和效率,只支持%s指示符。例如:
1 2 3 |
checkArgument(i >= 0); checkArgument(i >= 0, "Argument was expected nonnegative"); checkArgument(i < j, "Expected i < j, but %s > %s", i, j); |
3. […]
View Details想学Google Guava看这篇就够了
Guava是谷歌提供的一个核心Java类库,其中包括新的集合类型、不可变集合、图库,以及用于并发、I/O、Hash、缓存、字符串等的 实用工具。它在谷歌中的大多数Java项目中被广泛使用,也被许多其他公司广泛使用,熟练掌握这些工具类能帮助我们快速的处理日常开发中的一些问题,比如,不可变集合、集合的转换、字符串处理、本地缓存等 最近一段时间,我把Guava中常用到的工具类学了一遍,感觉有些工具类还是挺有用的,至少它帮你封装了很多功能,让你在处理一些逻辑的时候,不用太关注细节,把Guava的工具类直接拿来用就好了。下面我就介绍一下Guava中最常用的一些工具: 1、Guava不可变集合 不可变集合就是集合创建之后元素是不可改变的,主要用途如下: 不可变对象提供给别人使用时是安全的,因为不可变,所有人都无法进行修改,只能读 支持多个线程调用,不存在竞争的问题,天然支持多线程 不可变集合节省内存空间,因为不可变,集合空间在创建时就已经确定好了,不用考虑扩容等问题,内存利用率高 不可变集合可用于常量 Guava针对常用的集合类型List、Set、Map等都提供了不可变类型的集合 详细使用方法,可查看另一篇博客《Guava系列之不可变集合》 2、Guava新的集合类型 Guava提供了几种新的集合类型,补充了JDK中的集合类型 比如我们要统计List中某个元素出现的次数,如果使用JDK中的list就需要使用循环遍历进行统计,但使用了Guava的Multiset就可以直接统计出来元素出现的次数 再比如,我们要通过Map中的key查找value,通过value来查找值,也就是需要一个双向Map,如果使用JDK中的Map,我们需要维护两个Map,一个从key映射到value,另外一个从value映射到key,而且不管是新增还是修改Map中的元素,都要保持两个Map同步修改,维护成本太高了,使用Guava的BiMap可以通过一个Map轻松解决这个问题 更多新集合类型请查看《Guava系列之新的集合类型》 3、Guava超实用的集合工具类 JDK中集合的操作已经提供了很多工具类,比如基本的集合交集、并集、差集这些常用的操作,Guava中提供的工具类是对JDK的补充,在Guava中提供了静态的创建集合的方法,还有集合的很多操作,比如笛卡尔集、list反转、排列组合、Set转Map、Map的各种过滤等 新集合工具类的详细使用,请查看《Guava系列之超实用的集合工具类》 4、Guava本地缓存Cache Guava中的缓存是本地缓存的实现,与ConcurrentMap相似,但不完全一样。最基本的区别就是,ConcurrentMap会一直保存添加进去的元素,除非你主动remove掉。而Guava Cache为了限制内存的使用,通常都会设置自动回收 Guava Cache的使用场景: 以空间换取时间,就是你愿意用内存的消耗来换取读取性能的提升 你已经预测到某些数据会被频繁的查询 缓存中存放的数据不会超过内存空间 Guava Cache的详细使用方法,可查看《Guava系列之Cache》 5、Guava强大的String工具类 String是我们平时开发工作当中使用最频繁的类型, Guava提供了字符串的连接、分隔等操作,特别是字符串的匹配,那是相当强大,比如提取出字符串中的字母、数字、特殊字符等,可以从指定字符串中提取、删除、替换等操作 举个例子,提取“er 3j6o 3k ,)$ wt@ wr4576je ow3453535345irjew jwfel ” 字符串的字母,直接可以调用现成的方法 再比如,你需要将上述字符串中的数字全部移除或替换成其他字符,都有现成的方法,使用起来非常方便,只要你使用好了这些工具类, 可以大大提升你对字符串的处理效率 具体详细用法,请查看《Guava系列之强大的String工具类》 6、Guava限流RateLimiter 在互联网高并发场景下,限流是用来保证系统稳定性的一种手段,当系统遭遇瞬时流量激增时,可能会由于系统资源耗尽导致宕机。而限流可以把一小部分流量拒绝掉,保证大部分流量可以正常访问,从而保证系统只接收承受范围以内的请求,多余的请求给拒绝掉 我们常用的限流算法有:漏桶算法、令牌桶算法 Guava中的限流使用的是令牌桶算法,RateLimiter提供了两种限流实现 平滑突发限流(SmoothBursty) 平滑预热限流(SmoothWarmingUp) Guava RateLimiter的详细用法,请查看《Guava系列之限流RateLimiter》 7、Guava发布/订阅EventBus EventBus是Guava中实现的用于发布/订阅模式的事件处理组件,它是设计模式中观察者模式的优雅实现 EventBus是消息总线,它会根据消息的类型发送到指定的消息订阅者,当有消息没有订阅者接收时,会将消息发送给DeadEvent 关于EventBus的详细用法,请查看《Guava系列之EventBus》 以上是对最近学习Guava类库的一个总结,它包括了我们平常开发中最常用的一些组件工具类,熟练掌握这些工具类的使用方法,必然会让你的工作如虎添翼~ from:https://www.pianshen.com/article/57281487560/
View DetailsGoogle guava工具类的介绍和使用
概述 工具类 就是封装平常用的方法,不需要你重复造轮子,节省开发人员时间,提高工作效率。谷歌作为大公司,当然会从日常的工作中提取中很多高效率的方法出来。所以就诞生了guava。 guava的优点: 高效设计良好的API,被Google的开发者设计,实现和使用 遵循高效的java语法实践 使代码更刻度,简洁,简单 节约时间,资源,提高生产力 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如: 集合 [collections] 缓存 [caching] 原生类型支持 [primitives support] 并发库 [concurrency libraries] 通用注解 [common annotations] 字符串处理 [string processing] I/O 等等。 使用 引入gradle依赖(引入Jar包)
1 |
compile 'com.google.guava:guava:26.0-jre' |
1.集合的创建
1 2 3 4 5 6 7 8 9 |
// 普通Collection的创建 List<String> list = Lists.newArrayList(); Set<String> set = Sets.newHashSet(); Map<String, String> map = Maps.newHashMap(); // 不变Collection的创建 ImmutableList<String> iList = ImmutableList.of("a", "b", "c"); ImmutableSet<String> iSet = ImmutableSet.of("e1", "e2"); ImmutableMap<String, String> iMap = ImmutableMap.of("k1", "v1", "k2", "v2"); |
创建不可变集合 先理解什么是immutable(不可变)对象 在多线程操作下,是线程安全的 所有不可变集合会比可变集合更有效的利用资源 中途不可改变
1 |
ImmutableList<String> immutableList = ImmutableList.of("1","2","3","4"); |
这声明了一个不可变的List集合,List中有数据1,2,3,4。类中的 操作集合的方法(譬如add, set, sort, replace等)都被声明过期,并且抛出异常。 而没用guava之前是需要声明并且加各种包裹集合才能实现这个功能
1 2 3 4 5 |
// add 方法 @Deprecated @Override public final void add(int index, E element) { throw new UnsupportedOperationException(); } |
当我们需要一个map中包含key为String类型,value为List类型的时候,以前我们是这样写的
1 2 3 4 5 6 |
Map<String,List<Integer>> map = new HashMap<String,List<Integer>>(); List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); map.put("aa", list); System.out.println(map.get("aa"));//[1, 2] |
而现在
1 2 3 4 |
Multimap<String,Integer> map = ArrayListMultimap.create(); map.put("aa", 1); map.put("aa", 2); System.out.println(map.get("aa")); //[1, 2] |
其他的黑科技集合
1 2 3 4 5 6 7 8 9 10 11 12 13 |
MultiSet: 无序+可重复 count()方法获取单词的次数 增强了可读性+操作简单 创建方式: Multiset<String> set = HashMultiset.create(); Multimap: key-value key可以重复 创建方式: Multimap<String, String> teachers = ArrayListMultimap.create(); BiMap: 双向Map(Bidirectional Map) 键与值都不能重复 创建方式: BiMap<String, String> biMap = HashBiMap.create(); Table: 双键的Map Map--> Table-->rowKey+columnKey+value //和sql中的联合主键有点像 创建方式: Table<String, String, Integer> tables = HashBasedTable.create(); ...等等(guava中还有很多java里面没有给出的集合类型) |
2.将集合转换为特定规则的字符串 以前我们将list转换为特定规则的字符串是这样写的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//use java List<String> list = new ArrayList<String>(); list.add("aa"); list.add("bb"); list.add("cc"); String str = ""; for(int i=0; i<list.size(); i++){ str = str + "-" +list.get(i); } //str 为-aa-bb-cc //use guava List<String> list = new ArrayList<String>(); list.add("aa"); list.add("bb"); list.add("cc"); String result = Joiner.on("-").join(list); //result为 aa-bb-cc |
把map集合转换为特定规则的字符串
1 2 3 4 5 |
Map<String, Integer> map = Maps.newHashMap(); map.put("xiaoming", 12); map.put("xiaohong",13); String result = Joiner.on(",").withKeyValueSeparator("=").join(map); // result为 xiaoming=12,xiaohong=13 |
3.将String转换为特定的集合
1 2 3 4 5 6 7 8 9 10 11 12 |
//use java List<String> list = new ArrayList<String>(); String a = "1-2-3-4-5-6"; String[] strs = a.split("-"); for(int i=0; i<strs.length; i++){ list.add(strs[i]); } //use guava String str = "1-2-3-4-5-6"; List<String> list = Splitter.on("-").splitToList(str); //list为 [1, 2, 3, 4, 5, 6] |
如果
1 |
str="1-2-3-4- 5- 6 "; |
guava还可以使用 omitEmptyStrings().trimResults() 去除空串与空格
1 2 3 |
String str = "1-2-3-4- 5- 6 "; List<String> list = Splitter.on("-").omitEmptyStrings().trimResults().splitToList(str); System.out.println(list); |
将String转换为map
1 2 |
String str = "xiaoming=11,xiaohong=23"; Map<String,String> map = Splitter.on(",").withKeyValueSeparator("=").split(str); |
4.guava还支持多个字符切割,或者特定的正则分隔
1 2 |
String input = "aa.dd,,ff,,."; List<String> result = Splitter.onPattern("[.|,]").omitEmptyStrings().splitToList(input); |
关于字符串的操作 都是在Splitter这个类上进行的
1 2 3 4 5 6 7 8 9 10 |
// 判断匹配结果 boolean result = CharMatcher.inRange('a', 'z').or(CharMatcher.inRange('A', 'Z')).matches('K'); //true // 保留数字文本 CharMatcher.digit() 已过时 retain 保留 //String s1 = CharMatcher.digit().retainFrom("abc 123 efg"); //123 String s1 = CharMatcher.inRange('0', '9').retainFrom("abc 123 efg"); // 123 // 删除数字文本 remove 删除 // String s2 = CharMatcher.digit().removeFrom("abc 123 efg"); //abc efg String s2 = CharMatcher.inRange('0', '9').removeFrom("abc 123 efg"); // abc efg |
[…]
View Details