用 ChatGPT 写代码,效率杠杠的!

Posted Java技术栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用 ChatGPT 写代码,效率杠杠的!相关的知识,希望对你有一定的参考价值。

来源:https://www.cnblogs.com/scy251147/p/17242557.html

ChatGPT出来好久了,vscode上面由于集成了相关的插件,所以用起来很简单,经过本人深度使用后,发觉其能力的强大之处,在书写单元测试,书写可视化小工具,代码纠错,代码规范,编程辅助方面,极其可靠,而且能识别一些坑并绕过,下面来看看他能干的一些事情吧。

注意:由于英文的表述可以让ChatGPT的反馈更准确,所以这里的问题我均以英文来描述。

1、单测用例生成

待生成单测的测试类,此类就是一个静态工厂类,可以根据传入的数据类型和语言类型,创建出几个语言数据服务,包括ducc,mysql,配置,空语言数据服务:

public class SepI18nDataFactory 

    /**
     * 配置文件数据服务
     */
    public static ISepI18nDataService dataService;

    /**
     * 构建数据服务
     *
     * @param dataType
     * @return
     */
    public static ISepI18nDataService buildDataService(SepI18nDataType dataType, SepI18nLanguageType languageType) 
        //按照数据类型判断
        switch (dataType) 
            //从ducc中构建多语言服务
            case DUCC:
                return getInstance(languageType, x -> new SepI18nDuccDataService(x));
            //从mysql中构建多语言服务
            case MYSQL:
                return getInstance(languageType, x -> new SepI18nMysqlDataService(x));
            //从本地配置中构建多语言服务
            case CONFIG:
                return getInstance(languageType, x -> new SepI18nConfigDataService(x));
            //空数据服务,兜底逻辑
            default:
                return getInstance(languageType, x -> new SepI18nEmptyDataService(x));
        
    

    /**
     * 高并发下实例创建管控
     *
     * @param languageType
     * @param callback
     * @return
     */
    private static ISepI18nDataService getInstance(SepI18nLanguageType languageType, Function<SepI18nLanguageType, ISepI18nDataService> callback) 
        if (dataService == null) 
            synchronized (SepI18nDataFactory.class) 
                if (dataService == null) 
                    dataService = callback.apply(languageType);
                
            
        
        return dataService;
    

ChatGPT问题如下(要求:为类中的所有方法创建单测并包含所有的场景):

program unit tests for all methods for below class , you need test all scenarios, show me the code by using java language:

public class SepI18nDataFactory 

	/** * 配置文件数据服务 */
	public static SepI18nConfigDataService configDataService;

	/** * 数据库数据服务 */
	public static SepI18nMysqlDataService mysqlDataService;

	/** * ducc数据服务 */
	public static SepI18nDuccDataService duccDataService;

	/** * 空数据服务 - 兜底服务 */
	public static SepI18nEmptyDataService emptyDataService;

	/** * 构建数据服务
	 * @param dataType
	 * @return
	 */
	 public static ISepI18nDataService buildDataService(SepI18nDataType dataType, SepI18nLanguageType languageType) 
	 //区域设定 Locale locale = null;

	 //按照数据类型判断
	 switch (dataType) 
	 	//从ducc中构建多语言服务
	 	case DUCC:
	 	if (duccDataService == null) 
	 		duccDataService = new SepI18nDuccDataService(languageType);
	 	
	 	return duccDataService;
	 	//从mysql中构建多语言服务
	 	case MYSQL:
	 	if (mysqlDataService == null) 
	 		mysqlDataService = new SepI18nMysqlDataService(languageType);
	 	
	 	return mysqlDataService;
	 	//从本地配置中构建多语言服务
	 	case CONFIG:
	 	if (configDataService == null) 
	 		configDataService = new SepI18nConfigDataService(languageType);
	 	 return configDataService;
	 	//空数据服务,兜底逻辑
	 	default:
	 	if (emptyDataService == null) 
	 		emptyDataService = new SepI18nEmptyDataService(languageType);
	 	
	 	return emptyDataService;
	 
   

ChatGPT回答如下:

import static org.junit.Assert.assertEquals; import org.junit.Test;

public class SepI18nDataFactoryTest 

    @Test
    public void testBuildDataService_DUCC() 
        SepI18nDataType dataType = SepI18nDataType.DUCC;
        SepI18nLanguageType languageType = SepI18nLanguageType.EN;
        ISepI18nDataService dataService = SepI18nDataFactory.buildDataService(dataType, languageType);
        assertEquals(SepI18nDuccDataService.class, dataService.getClass());
        

    @Test
    public void testBuildDataService_MYSQL() 
        SepI18nDataType dataType = SepI18nDataType.MYSQL;
        SepI18nLanguageType languageType = SepI18nLanguageType.EN;
        ISepI18nDataService dataService = SepI18nDataFactory.buildDataService(dataType, languageType);
        assertEquals(SepI18nMysqlDataService.class, dataService.getClass());
    

    @Test
    public void testBuildDataService_CONFIG() 
        SepI18nDataType dataType = SepI18nDataType.CONFIG;
        SepI18nLanguageType languageType = SepI18nLanguageType.EN;
        ISepI18nDataService dataService = SepI18nDataFactory.buildDataService(dataType, languageType);
        assertEquals(SepI18nConfigDataService.class, dataService.getClass());
    

    @Test
    public void testBuildDataService_Default() 
        SepI18nDataType dataType = SepI18nDataType.OTHER;
        SepI18nLanguageType languageType = SepI18nLanguageType.EN;
        ISepI18nDataService dataService = SepI18nDataFactory.buildDataService(dataType, languageType);
        assertEquals(SepI18nEmptyDataService.class, dataService.getClass());

生成的单测可以完美运行且包含所有的场景,完美。

2、编写小工具

由于在工作中,我们免不了需要写一些小工具来辅助业务,所以看看是否可以把这种活儿交给ChatGPT来干一下。 这里我们准备让其编写基于javafx框架的form界面工具,然后实际运行这个小工具来检验其编写小工具的可行性。

ChatGPT问题如下(界面上,两个文本框,两个按钮,点击第一个按钮,会选择文件夹,然后点击第二个按钮会将文件夹下的enum类名显示到另一个文本框中):

a form with two textfields, two buttons, click one button to locate the directory path and fill it into a textfield, and click another button to start to find the enum .class file from the directory path and show the enum class name into textfield, using javafx structure and show me the java code

ChatGPT回答如下:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class EnumFinder extends Application 

private TextField directoryPathTextField;

private TextField enumClassNameTextField;

public static void main(String[] args) 
    launch(args);


@Override
public void start(Stage primaryStage) 
    directoryPathTextField = new TextField();
    Button directoryPathButton = new Button("Select Directory");
    directoryPathButton.setOnAction(e -> 
        DirectoryChooser directoryChooser = new DirectoryChooser();
        File selectedDirectory = directoryChooser.showDialog(primaryStage);
        if (selectedDirectory != null) 
            directoryPathTextField.setText(selectedDirectory.getAbsolutePath());
        
    );

    Button findEnumButton = new Button("Find Enum");
    findEnumButton.setOnAction(e -> 
        String directoryPath = directoryPathTextField.getText();
        try (Stream<Path> paths =Files.walk(Paths.get(directoryPath)))
            paths.filter(Files::isRegularFile).filter(p -> p.toString().endsWith(".class")).filter(p ->isEnumClass(p)).forEach(p -> enumClassNameTextField.setText(p.getFileName().toString().replace(".class","")));catch(IOException ex)
            ex.printStackTrace(););

    enumClassNameTextField =newTextField();
    enumClassNameTextField.setEditable(false);HBox hBox =newHBox(directoryPathTextField, directoryPathButton, findEnumButton, enumClassNameTextField);Scene scene =newScene(hBox);
    primaryStage.setScene(scene);
    primaryStage.show();privatebooleanisEnumClass(Path path)tryClass clazz =Class.forName(path.toString().replace(".class",""));return clazz.isEnum();catch(ClassNotFoundException e)
        e.printStackTrace();returnfalse;

有点呆住了,居然完全正确的生成了我要的工具且能正常运行(稍微调整下界面布局)。

3. 修复代码bug

Sample1:高并发bug

还是之前的代码,改了改,让其在高并发压力下,工作的不那么ok:

public class SepI18nDataFactory 

    /**
     * 配置文件数据服务
     */
    public static ISepI18nDataService dataService;

    /**
     * 构建数据服务
     *
     * @param dataType
     * @return
     */
    public static ISepI18nDataService buildDataService(SepI18nDataType dataType, SepI18nLanguageType languageType) 
        //按照数据类型判断
        switch (dataType) 
            //从ducc中构建多语言服务
            case DUCC:
                return getInstance(languageType, x -> new SepI18nDuccDataService(x));
            //从mysql中构建多语言服务
            case MYSQL:
                return getInstance(languageType, x -> new SepI18nMysqlDataService(x));
            //从本地配置中构建多语言服务
            case CONFIG:
                return getInstance(languageType, x -> new SepI18nConfigDataService(x));
            //空数据服务,兜底逻辑
            default:
                return getInstance(languageType, x -> new SepI18nEmptyDataService(x));
        
    

    /**
     * 高并发下实例创建管控
     *
     * @param languageType
     * @param callback
     * @return
     */
    private static ISepI18nDataService getInstance(SepI18nLanguageType languageType, Function<SepI18nLanguageType, ISepI18nDataService> callback) 
        if (dataService == null) 
              dataService = callback.apply(languageType);
        
        return dataService;
    

ChatGPT训练如下(指出代码在高并发下工作不太正常,让其修复):

below class is worked not ok under high flow pressure, please find the bug and fix for me :

public class SepI18nDataFactory 

	/** 配置文件数据服务 */
	public static ISepI18nDataService dataService;

	/** 构建数据服务
	* @param dataType
	* @return
	*/
	public static ISepI18nDataService buildDataService(SepI18nDataType dataType, SepI18nLanguageType languageType) 
	//按照数据类型判断
	switch (dataType) 
		//从ducc中构建多语言服务 case DUCC: return getInstance(languageType, x -> new SepI18nDuccDataService(x));
		//从mysql中构建多语言服务 case MYSQL: return getInstance(languageType, x -> new SepI18nMysqlDataService(x));
		//从本地配置中构建多语言服务 case CONFIG: return getInstance(languageType, x -> new SepI18nConfigDataService(x));
		//空数据服务,兜底逻辑 default: return getInstance(languageType, x -> new SepI18nEmptyDataService(x));
		
	

    /** 高并发下实例创建管控
     * @param languageType
     * @param callback
     * @return
     */
     private static ISepI18nDataService getInstance(SepI18nLanguageType languageType, Function callback) 
      if (dataService == null) 
     	 synchronized (SepI18nDataFactory.class) 
     		if (dataService == null) 
     			dataService = callback.apply(languageType);
     		
     	
     
     return dataService;
   

ChatGPT回答如下:

It looks like the bug is in the getInstance() method. The dataService variable is not being synchronized, which can cause issues with concurrent access. To fix this, you can add a synchronized block around the code that checks and sets the dataService variable. This will ensure that only one thread can access the variable at a time.

很明显,一针见血的指出了高并发下存在的问题。

Sample2: 自定义锁bug

随便写了个基于AQS锁框架的自定义锁,代码如下:

class SepSync extends AbstractQueuedSynchronizer 

    @Override
    protected boolean tryAcquire(int arg) 
        if (compareAndSetState(0, 1)) 
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        
        return false;
    

    @Override
    protected boolean tryRelease(int arg) 
        if (getState() == 0) 
            throw new IllegalMonitorStateException();
        
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    

    public void lock() 
        acquire(1);
    

    public void unlock() 
        release(1);
    

ChatGPT问题如下(大意是帮忙看下锁写的有没有问题):

below is the lock class, please find the bug and fix it for me :

class SepSync extends AbstractQueuedSynchronizer 

	@Override protected boolean tryAcquire(int arg) 
		if (compareAndSetState(0, 1)) 
			setExclusiveOwnerThread(Thread.currentThread());
			return true;
		

		return false;
	

	@Override
	protected boolean tryRelease(int arg) 
		if (getState() == 0) 
			throw new IllegalMonitorStateException();
		
		setExclusiveOwnerThread(null);
		setState(0);
		return true;
	

	public void lock() 
		acquire(1);
	

	public void unlock() 
		release(1);
	

ChatGPT回答如下:

The bug in the above code is that the tryRelease() method does not check if the current thread is the exclusive owner thread before releasing the lock. This can lead to a situation where the lock is released by a thread that does not own it.

To fix this bug, the tryRelease() method should be modified to check if the current thread is the exclusive owner thread before releasing the lock. The modified code should look like this:

@Override protected boolean tryRelease(int arg)
	if(Thread.currentThread() != getExclusiveOwnerThread())
		throw new IllegalMonitorStateException();
	
	setExclusiveOwnerThread(null);
	setState(0);
	return true;

大意就是,我的锁写的有点问题,其他线程可以释放不属于它的锁。(幸好偷偷去看了ReetrentLock实现,确实如此),到这里有些折服了。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

用MySQL替代Excel存储数据,效率提升杠杠滴


大家好,欢迎来到 Crossin的编程教室 !

正文开始之前先通知一个福利:

618当当优惠码

可在当当自营图书每满100-50的基础上叠加

满200减40:

VMNBW8 

自营图书专享(教材以及特例品除外)

用MySQL替代Excel存储数据,效率提升杠杠滴

当当小程序、APP均可使用

结算时选择【优惠码】输入 VMNBW8 即可

数量有限,先到先得

有效期:6.15~6.20 

(详细使用教程参见今日推送的第3条)



今天要给大家分享的是一个在数据分析时经常面临的问题:如何通过MySQL进行数据的读取。

应用场景:工作中经常遇到大量的数据需要整合、去重、按照特定格式导出等情况。如果用 Excel 操作,不仅费时费力,还容易出错,有没有更高效的解决方案呢?

本文以17个 txt 文本,3万多条数据为例,使用 Python 连接 MySQL 数据库,实现快速操作。

别人加班干的活,我的 Python 小助手几秒钟就搞定了!

本文主要包括以下三方面内容:

  • 数据写入
  • 数据去重
  • 数据导出

将数据写入 MySQL 数据库

下图所示文件是本文的数据源:

用MySQL替代Excel存储数据,效率提升杠杠滴

我们的设想是:编写一个小程序,扔在这个文件夹里,双击后就可以自动读取每个 txt 文档中的数据,并写入数据库。

代码如下:

import pymysql
import os
conn = pymysql.connect(host='localhost', user='root', password='123456', db='qq', charset='utf8')
cur = conn.cursor()
cur.execute("CREATE TABLE qq ( id int(5) NOT NULL auto_increment, qq varchar(20)NOT NULL, PRIMARY KEY (id));")
conn.commit()
path = os.getcwd()
files = os.listdir(path)
i = 0
for file in files:
f = open(file,'r',encoding = 'UTF-8')
next(f)
for line in f:
i += 1
#print(line)
sql = "insert into qq(qq) values(%s);"
cur.execute(sql,line)
print("插入第", i, "条数据!")
conn.commit()
f.close()
cur.close()
conn.close()

运行效果:

用MySQL替代Excel存储数据,效率提升杠杠滴

重点代码解释:

这段代码用到了 pymysql 和 os 两个库。

  • pymysql:用来操作 MySQL 数据库;
  • os:用来遍历所在文件夹下的所有文件。

现将主要代码解释如下:

1、遍历任意文件夹下所有文件名称

程序写好后,使用 pyinstaller 打包成 exe 程序,并放在要操作的文件夹下面。

通过 path = os.getcwd()命令,获取该 exe 文件所在目录。

通过 files = os.listdir(path)命令,获取 exe 文件所在目录下的所有文件名称,并存入 files 列表中。

这样我们就获得了所有的 txt 文件名称,你可以任意命名你的 txt 文件名,程序都能读出来。

2、将数据写入数据库

(1)连接数据库,并在数据库中创建新表

A. 连接到我的 qq 数据库

conn = pymysql.connect(host='localhost', user='root', password='123456', db='qq', charset='utf8')

B. 创建新表 qq

在 qq 数据库中创建新表,表名称为 qq ,包含 2 个字段:id 字段为主键、自动递增;qq 字段为字符型,用于存储数据。

cur.execute("CREATE TABLE qq ( id int(5) NOT NULL auto_increment, qq varchar(20)NOT NULL, PRIMARY KEY (id))")

(2)将数据写入数据库

这里使用了两层循环:

for file in files:
f = open(file,'r',encoding = 'UTF-8')
next(f)
for line in f:
i += 1
#print(line)
sql = "insert into qq(qq) values(%s);"
cur.execute(sql,line)
print("插入第", i, "条数据!")
conn.commit()
f.close()

第一层循环是用来依次打开上述 17 个 txt 文件。

第二层循环是依次读取每个 txt 文件的每一行,并将改行数据插入数据库表 qq 的 qq字段。

至此就完成了数据的导入,总共32073条数据。

数据清洗

这里以去除重复值为例,简单介绍一下数据清洗。

1、创建一个新表,用来存储清洗后的数据

可以在 cmd 窗口下登陆 MySQL,打开 qq 数据库,执行下列操作:

CREATE TABLE qq_dist ( id int(5) NOT NULL auto_increment, qq varchar(20)NOT NULL, PRIMARY KEY (id));

这样就创建了新表 qq_dist ,用来存储清洗后的数据,便于后期调用。

2、清洗数据

登陆 MySQL 后,执行下列操作:

insert into qq_dis(qq) select distinct qq from qq;

将从 qq 表中查找出的不重复的 qq 字段内容,插入到 qq_dist 表中的 qq 字段。

将数据按照特定格式导出

案例:将清洗后的数据的第101-200行导出到新的 txt 文本中。

代码如下:

import pymysql
conn = pymysql.connect(host='localhost', user='root', password='123456', db='wxid', charset='utf8')
print("写入中,请等待……")
cur = conn.cursor()
sql = "select wxid from wd_dis limit 100,100;"
cur.execute(sql)
conn.commit()
alldata = cur.fetchall()
f = open('data101-200.txt','a')
i = 0
for data in alldata:
i += 1
f.write(data[0])
f.flush()
f.close
cur.close()
conn.close()
print("写入完成,共写入{}条数据!".format(i))

重点代码解释:

1、 limit

MySQL 中 limit m,n 函数的含义是:从第 m+1 行开始读取 n 行。

所以,本案例中读取第101-200行,就是 limit 100,100

2、flush()

flush()函数一定要加上,它可以将缓冲区的数据写入文件中。否则就会出现生成的 txt 文档为空白的错误。

其他代码都比较简单,本文不再赘述。

如果文章对你有帮助,欢迎转发/点赞/收藏~

来源:智能演示


_往期文章推荐_





如需了解付费精品课程教学答疑服务
请在Crossin的编程教室内回复: 666

以上是关于用 ChatGPT 写代码,效率杠杠的!的主要内容,如果未能解决你的问题,请参考以下文章

用MySQL替代Excel存储数据,效率提升杠杠滴

IDEA 超全优化设置,效率杠杠的!

留学生如何利用ChatGPT提高学习效率?

效率杠杠的!读取大量MySQL数据,就用Mybatis 流式

怎么让chatGPT写作文-ChatGPT如何写作

用上ChatGPT的这几个功能,你的开发效率不高都难