在今天使用Java
代码做一个集合的任务的时候,没在for
循环中手动打印日志信息,导致在任务执行后根本不知道执行到了哪一步。
这点让我挺困扰的,于是在github
上寻找有没有什么进度条的显示方式,我还真找到了。
看了一下代码,挺简单的,就将思路直接copy
过来,实现了一个自己的控制台进度条。
vdurmont/etaprinter: Java console progress bar (github.com)
抽象类ProcessBarUtil.java
,里面有着基本的信息
package com.banmoon.utils.processbar;
import java.util.Iterator;
import java.util.function.Consumer;
/**
* @author banmoon
* @date 2024/03/08 15:52:13
*/
public abstract class ProcessBarUtil<T> implements Iterable<T> {
/**
* 遍历的数据
*/
private final Iterable<T> data;
/**
* 结束数量
*/
private final Integer startNum;
/**
* 当前的进度
*/
private Integer current;
/**
* 结束数量
*/
private final Integer endNum;
/**
* 进度条当前位置
*/
private Integer processCurrentNum = 0;
/**
* 进度条总数
*/
private final Integer processTotalNum = 100;
public ProcessBarUtil(Iterable<T> data, Integer startNum, Integer current, Integer endNum) {
this.data = data;
this.startNum = startNum;
this.current = current;
this.endNum = endNum;
}
/**
* 添加进度
*
* @param num 本次进度数量
*/
public void add(Integer num) {
this.current += num;
this.processCurrentNum = (int) (100.0 * current / endNum);
updateProcessBar(processCurrentNum, processTotalNum);
}
/**
* 更新进度条
*
* @param current 当前进度
*/
public void update(Integer current) {
this.current = current;
this.processCurrentNum = (int) (100.0 * current / endNum);
updateProcessBar(processCurrentNum, processTotalNum);
}
protected abstract void updateProcessBar(Integer processCurrentNum, Integer processTotalNum);
@Override
public Iterator<T> iterator() {
return data.iterator();
}
@Override
public void forEach(Consumer<? super T> action) {
data.forEach(t -> {
action.accept(t);
add(1);
});
}
}
以及它的第一个实现类ConsoleProcessBarUtil.java
,使用控制台输出进度条
package com.banmoon.utils.processbar;
import cn.hutool.core.collection.IterUtil;
import java.io.IOException;
import java.io.OutputStream;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* 控制台打印输出进度条
*
* @author banmoon
* @date 2024/03/08 16:05:26
*/
public class ConsoleProcessBarUtil<T> extends ProcessBarUtil<T> {
private final OutputStream outputStream;
/**
* 未完成的
*/
private static final char incomplete = '░';
/**
* 完成的
*/
private static final char complete = '█';
private ConsoleProcessBarUtil(Iterable<T> data, Integer startNum, Integer current, Integer endNum) {
super(data, startNum, current, endNum);
outputStream = System.out;
}
public static <T> ProcessBarUtil<T> init(Iterable<T> data) {
return new ConsoleProcessBarUtil<>(data, 0, 0, IterUtil.size(data));
}
public static ProcessBarUtil<?> init(Integer startNum, Integer endNum) {
return new ConsoleProcessBarUtil<>(null, startNum, startNum, endNum);
}
@Override
protected void updateProcessBar(Integer processCurrentNum, Integer processTotalNum) {
String processBar = generateProcessBar(processCurrentNum, processTotalNum);
try {
outputStream.write("\r".getBytes());
outputStream.write(processBar.getBytes());
} catch (IOException e) {
throw new RuntimeException("an error occurred while printing the progress bar");
}
}
private String generateProcessBar(Integer processCurrentNum, Integer processTotalNum) {
StringBuilder sb = new StringBuilder("[");
Stream.generate(() -> complete)
.limit(processCurrentNum)
.forEach(sb::append);
IntStream.range(processCurrentNum, processTotalNum)
.mapToObj(i -> incomplete)
.forEach(sb::append);
sb.append("] ");
if (processCurrentNum >= processTotalNum) {
sb.append("complete\n");
} else {
sb.append(processCurrentNum).append("%");
}
return sb.toString();
}
}
package com.banmoon.utils.stream;
import cn.hutool.core.util.RandomUtil;
import com.banmoon.utils.processbar.ConsoleProcessBarUtil;
import com.banmoon.utils.processbar.ProcessBarUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ProcessBarUtilTest {
@Test
public void iterableTest() {
List<Integer> list = IntStream.range(0, 100).boxed().collect(Collectors.toList());
ConsoleProcessBarUtil
.init(list)
.forEach(str -> {
try {
// 模拟业务执行
TimeUnit.MILLISECONDS.sleep(RandomUtil.randomInt(50, 200));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
Assert.assertEquals(list.size(), 100);
}
@Test
public void forTest() {
int current = 50;
int total = 200;
ProcessBarUtil<?> processBarUtil = ConsoleProcessBarUtil.init(current, total);
while (current < total) {
try {
// 模拟业务执行
TimeUnit.MILLISECONDS.sleep(RandomUtil.randomInt(50, 200));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
current++;
processBarUtil.update(current);
}
Assert.assertEquals(current, total);
}
}
运行后查看效果,成功
后续会完善加上,执行的耗时,预计多少时间完成等信息。
以及看看除了控制台,还有没有其他实现。
我是半月,你我一同共勉!!!