知道Python语言的Google Fire项目么,我将它移植到了Java上

2023-11-28 02:08

本文主要是介绍知道Python语言的Google Fire项目么,我将它移植到了Java上,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

640?wx_fmt=png

最近尝试了Python语言的开源命令行便捷工具库Google Fire,它是用来加速用户编写命令行程序的一个小工具库,该工具使用非常方便,节省了编写命令行程序繁琐的参数解析代码的时间。

巧用Google Fire简化Python命令行程序

但是我发现Java语言还缺少这样一个工具库,于是花了2天时间,将Google Fire移植到了Java语言上,命名为Startup。有了Startup,Java同学也可以从此不用解析繁琐的命令行参数了。

Startup项目的Github代码地址 https://github.com/pyloque/startup

安装依赖

<dependency><groupId>com.github.pyloque</groupId><artifactId>startup</artifactId><version>0.0.1</version>
</dependency>

让Jedis秒变命令行

import java.io.IOException;import codehole.startup.Startup;
import redis.clients.jedis.Jedis;public class Demo {public static void main(String[] args) {Startup.shell(new Jedis());}}

使用maven将程序打包成jar包文件demo.jar,接下来就可以体验命令行版本的Jedis了。

$ java -jar demo.jar
> @set codehole superhero
OK
> @get codehole
superhero
> @keys *
[codehole]
> @del codehole
1
> @sadd books str[]:java,golang,python
1
> @sadd books str[]:java,golang,python
3
> @smembers books
[python, golang, java]
> @scard books
3

我们还可以使用单行命令模式,将shell方法改成fire即可,有了fire函数,繁琐的命令行参数解析过程就可以彻底拜拜了。

Startup.fire(new Jedis(), args);  // 需要传递args参数

接下来,我们尝试一下单行命令的效果

$ java -jar demo.jar @set codehole superhero
OK
$ java -jar demo.jar @get codehole
superhero
$ java -jar demo.jar @keys "*"
[codehole]
$ java -jar demo.jar @del codehole
1
$ java -jar demo.jar @sadd books str[]:java,golang,python
3
$ java -jar demo.jar @smembers books
[python, golang, java]
$ java -jar demo.jar @scard books
3

Redis的set命令在Jedis里存在多个重载函数,很难记清楚具体有哪些参数。不过没关系,Startup提供了类自省功能,可以列出指定匹配模式的函数调用形式。

$ java -jar demo.jar ! @set
class: redis.clients.jedis.Jedismethod: set(String arg0, String arg1, String arg2)method: set(String arg0, String arg1, String arg2, String arg3, int arg4)method: set(String arg0, String arg1)method: set(String arg0, String arg1, String arg2, String arg3, long arg4)
class: redis.clients.jedis.BinaryJedismethod: set(byte[] arg0, byte[] arg1, byte[] arg2)method: set(byte[] arg0, byte[] arg1, byte[] arg2, byte[] arg3, int arg4)method: set(byte[] arg0, byte[] arg1, byte[] arg2, byte[] arg3, long arg4)method: set(byte[] arg0, byte[] arg1)

自省操作符是!,它连带祖先类一会自省了。当set方法有如此多时,如何调用具体哪个set方法呢?Startup使用参数数量和参数类型来匹配函数,如果有多个函数满足匹配条件,就使用第一个函数。比如现在要调用byte[]类型的set函数,我们可以这样写

> java -jar demo.jar @set byte[]:1,2,3 byte[]:10,20
OK
> java -jar demo.jar @get byte[]:1,2,3
[B@ae45eb6

因为输出是一个byte[]数组,所以显示的是它的toString()调用的结果。如果用户不满意输出效果,可以通过自定义IConsole.print方法来优化输出。

Startup.fire(Object target, String[] args, IConsole console);

细节规则

  1. 方法调用使用@前缀,如@set

  2. 字段访问使用$前缀,如$host

  3. 方法调用如果遇到同样参数数量的方法不止一个,那么在传递参数时就必须携带参数类型前缀信息,便于startup确定具体应该调用哪个方法。如@set str:codehole str:superhero,表示调用两个参数都是String类型的set方法。如果不给予参数类型提示,那么自动使用第一个找到的方法,这可能不是你想要的。

  4. startup的target参数可以是普通对象,也可以是类。比如Startup.fire(Jedis.class, args),那么后续的参数作用对象就是Jedis.class。

  5. 如果target是类,那么可以使用操作符+号对类进行实例化,后面跟着构造器的参数列表。比如Jedis有构造器Jedis(String host, int port),那么就可以这样实例化+ str:localhost int:6379

  6. 如果target是类,并且有默认构造器的话,那么如果要访问实例方法或者实例字段的话,就会对这个类进行自动实例化。如果没有默认构造器,这时候就会抛出异常。

  7. 如果某个方法返回值为void,Startup会进行特殊处理,返回调用对象自身。

  8. 自省操作符!可以使用! @显示所有方法,可以使用! $显示所有字段,如果不带参数,等价于! *列出所有的字段和方法。像Jedis类里面实例方法特别多,如果全部列出来会让人崩溃,这时可以用第三个参数maxlen,表示最多显示多少行。比如! @ 100最多显示100行方法。还可以通过模式匹配*号来查找方法,比如! @*set*匹配所有包行set字符串的方法列表。

  9. 输入exit和q可以退出命令行shell。

实例演示

下面我们使用链式调用的例子来演示Startup的强大威力。首先我们编写一个Counter类,可以对该类里面的整形字段value进行incr和decr操作。然后使用Startup对它进行shell化。同时我们定一个coeff静态变量,用于放大自增自减的效果。

import codehole.startup.Startup;public class Demo {static class Counter {int value;static int coeff = 1;public Counter() {this(10);}public Counter(int value) {this.value = value;}public static int coeff() {return coeff;}public static void coeff(int c) {coeff = c;}public Counter incr() {return incr(1);}public Counter incr(int v) {this.value += v * coeff;return this;}public Counter decr() {return incr(1);}public Counter decr(int v) {this.value -= v * coeff;return this;}public int value() {return value;}public String toString() {return String.format("Counter(value=%d)", value);}}public static void main(String[] args) {Startup.shell(Counter.class); // 注意,这里的目标是类}}

我们运行一下,体验一下Startup的神奇魅力。

自省

$ java -jar demo.jar
# 列出所有方法
> ! @
class: codehole.startup.demo.Demo.Countermethod: value()method: decr()method: decr(int arg0)method: static coeff(int arg0)method: static coeff()method: incr(int arg0)method: incr()
# 列出所有字段
> ! $
class: codehole.startup.demo.Demo.Counterfield: int valuefield: static int coeff
# 列出所有的incr方法
> ! @incr
class: codehole.startup.demo.Demo.Countermethod: incr(int arg0)method: incr()
# 列出所有的decr方法
> ! @decr
class: codehole.startup.demo.Demo.Countermethod: decr()method: decr(int arg0)
# 列出后缀为cr的方法
> ! @*cr
class: codehole.startup.demo.Demo.Countermethod: decr()method: decr(int arg0)method: incr(int arg0)method: incr()

构造器

# 默认构造器
> +
Counter(value=10)
# 调用构造器Counter(int)
> + 5
Counter(value=5)
# 构造完继续获取实例字段
> + $value
10
> + 5 $value
5
# 构造完继续调用实例方法
> + @value
10
> + 5 @value
5
# 对类[访问实例字段或调用实例方法]会自动构造该类的默认实例,再回调方法或者访问实例字段
> $value
10
> @value
10

静态字段和方法

# 对类调用静态方法和对实例调用静态方法效果是一样的
> @coeff
1
> + @coeff
1
# 对类访问静态字段和对实例访问静态字段效果是一样的
> $coeff
1
> + $coeff
1
# 返回类型为void的方法会自动调整返回结果为调用对象
> @coeff 2
class codehole.startup.demo.Demo$Counter
> + @coeff 2
Counter(value=10)
> @coeff 2 $coeff
2

链式调用

> @incr @incr @incr 5 @incr 5 $value
22
> @incr 5 @decr 5 @incr 5 @decr 5 $value
10
> + @incr @incr @incr 5 @incr 5 $value
22
> + @incr 5 @decr 5 @incr 5 @decr 5 $value
10

总结

Java版本的Startup和Google Fire使用上还是有一些不一样,这个是语言的机制差别所致。但是使用上是大同小异,基本上Google Fire能做到的事,Startup都能做了,只是在使用形式上略有不同。

Startup继承了Fire的优良传统,小巧轻便没有任何依赖项,使用一行代码就把命令行的繁琐解析过程给彻底消灭了。同时还提供了Fire所欠缺的自省功能和交互式shell,用户使用Startup进行调试工作时会无比轻松。

高级文章,关注微信订阅号「码洞」

这篇关于知道Python语言的Google Fire项目么,我将它移植到了Java上的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/428893

相关文章

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程