【Java】深入剖析Java输入输出的那些细节
前言
无论是新手入门的命令行输入输出,还是说OJ的读入和输出,离不开基本的IO操作。
但Java本身由于纯粹的面向对象,输入输出不方便,所以我们倒不妨探讨一番。
其实输入输出真实是所有学Java的入门者一定要先去学的,但用的越多越能深入地感受到输入输出或多或少的小问题。正所谓“养兵千日,用兵一时”,想要关键时刻一针见血,就必须在平时做好准备。
Are you ready? OK ~ 那今天我们就来聊聊,我们如何用好Java的输入输出。
看看Python
这叫输入:
n=input()
可以用eval()将输入类型转换成数值类型,用int()转换成整数类型……
如下:
n=eval(input())
这叫输出:
print(n)
看看C++
cin可以输入:
cin>>n;
输入还可以用scanf(),效率更高。
cout可以输出:
cout<<n;
输出还可以用printf(),效率更高。
Java输出篇
为什么先谈输出呢?
显然因为简单啊。
普通输出流有三种输出方式:
第一种是不换行输出:
int n = 1;
System.out.print(n);
第二种是换行输出:
System.out.println(n);
第三种是格式化输出:
System.out.printf("%d", n);
还有错误输出流,与上述内容类似:
第一种是不换行输出:
System.err.print(n);
第二种是换行输出:
System.err.println(n);
第三种是格式化输出:
System.err.printf("%d", n);
Java输出的一些问题
printf();
如果格式化不正确,就会爆java.util.IllegalFormatConversionException
异常。- 为什么Eclipse/IDEA这样的IDE在爆异常的时候都可能红字和普通字混合?
异常是err错误流,普通输出是out普通输出流,可能会在IDE里由于线程的问题而混合在一起。 - System.in/System.out/System.err是什么?
根据下面的源码(java.lang.System),可知分别是InputStream、PrintStream对象,err流和out流是同一个类的不同对象。public static final InputStream in;public static final PrintStream out;public static final PrintStream err;`
- 打印输出的时候会启动IO,所以不建议直接输出,可以用StringBuilder把答案“组织好”再统一输出。
- 循环里每次都cout的时候能不输出最后的空格,不需要额外的调整,但System.out.println()输出的时候没有这种考虑,必须自己处理最后一次的结果。我建议可以用
builder.append(i).append(" ");
和builder.toString().trim();
,最后消去末尾的一个空格,即可完成所需要的输出。 - 格式化打印指定位数小数是常见操作,可用printf()完成任务目标。比如,
System.out.printf("%.5f");
就是保留五位小数打印浮点数。 - ……(留待补充)
对于第五条,说明一下。我们先写一个测试类,打一下时间戳:
public class PrintTest {public static void main(String[] args) {int[] array = new int[100000];long time1 = System.currentTimeMillis();for (int i = 0; i < array.length-1; i++) {System.out.print(array[i] + " ");}System.out.println(array[array.length-1]);long time2 = System.currentTimeMillis();StringBuilder builder = new StringBuilder();for (int i = 0; i < array.length; i++) {builder.append(array[i]).append(" ");}System.out.println(builder.toString().trim());long time3 = System.currentTimeMillis();System.out.println("策略1的输出时间:" + (time2-time1));System.out.println("策略2的输出时间:" + (time3-time2));}
}
除去上面的两行输出,会打印:
策略1的输出时间:330
策略2的输出时间:10
显然,用StringBuilder而不是直接一次接一次的System.out.print(),是正解啦。
Java输入篇
记得在学校刚学的时候,第一节课老师就让大家写一下输入输出语句,输出还好,输入就不行了,很多同学不会写。其实我也是在学了很多语法以后才学会的输入啦,下面就来说一说吧。
其实对初学者的一个困难就是输出可以不必import,但输入则不然,需要import java.io.*,或者import java.util.Scanner,可能不那么容易直接理解。
一般比较“出名”的处理方式是java.util.Scanner,这倒确实。
Scanner类可以直接读取一下类型的对象:
- public String next() → 读取下一个字符串(默认分隔符为Space or Tab or Enter)
- public String next(String pattern) → 读取下一个字符串(匹配到的串符合指定的正则表达式)
- public String next(Pattern pattern) → 读取下一个字符串(匹配到的串符合指定的正则表达式)
- public BigDecimal nextBigDecimal() → 读取下一个高精小数(默认十进制)
- public BigInteger nextBigInteger() → 读取下一个高精整数(默认十进制)
- public BigInteger nextBigInteger(int radix) → 读取下一个高精整数(指定进制)
- public boolean nextBoolean() → 读取下一个布尔值
- public byte nextByte() → 读取下一个byte整型数值(超容会报错,默认十进制)
- public byte nextByte(int radix) → 读取下一个byte整型数值(超容会报错,指定进制)
- public double nextDouble() → 读取下一个双精度浮点数值(默认十进制)
- public float nextFloat() → 读取下一个单精度浮点数值(默认十进制)
- public int nextInt() → 读取下一个int整型数值(超容会报错,默认十进制)
- public int nextInt(int radix) → 读取下一个int整型数值(超容会报错,指定进制)
- public String nextLine() → 读取下一行内容以字符串类型返回(分隔符为Enter)
- public long nextLong() → 读取下一个long整型数值(超容会报错,默认十进制)
- public long nextLong(int radix) → 读取下一个long整型数值(超容会报错,指定进制)
- public short nextShort() → 读取下一个short整型数值(超容会报错,默认十进制)
- public short nextShort(int radix) → 读取下一个short整型数值(超容会报错,指定进制)
看吧,确实“全能”,不过我们在看到Scanner便捷的同时也应该清醒地认识到其性能的低下。
Scanner之所以能如此全能,依赖于Java支持的正则表达式,这点可以自行阅读文档或者源码了解,这里不加详细说明。
我们试想,比如一行这样的数据:
1 2 555 333333 99 243 ……
如果说每一次都用scanner.nextInt(),就会慢太多。
反反复复的IO操作,每次都要判断和处理,很影响效率的。
比如说在洛谷刷算法题的时候,我一般是用Java,但很多次都被卡死性能,不管怎么优化也不行,最后发现问题就在Scanner身上,那怎么处理呢?
答案是换BufferedReader,性能大幅提升。
看下面的代码:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int num = Integer.parseInt(reader.readLine());
int[] record = new int[num];
String[] nums = reader.readLine().split("\\s+");
for (int i = 0; i < num; i++) {record[i] = Integer.parseInt(nums[i]);
}
reader.close();
这样一段代码就可以先读一个数值,再读剩下一行里大量的数值。
看似还要开一个String[],但其实都说过了,再慢也慢不过IO,希望大家心里清楚最慢的就是IO了,减少IO是提升性能之道。
不过,在极其苛刻的情况下,Java是没办法完成的,严重TLE+MLE,哪怕你用了byte这样的也不行,所以就得换C++了。毕竟算法题没必要为Java设计性能指标,不达标也只能认了,Java比起C/C++太慢了。
Java输入的一些问题
- 性能实在不达标,看不对就换BufferedReader,再不行就换C++。
- 切记scanner.nextInt()之后没换行,此时如果读一行scanner.nextLine()可能只读到空字符串——"",导致后续崩盘。所以遇到单行单个数值+单行多数值的情况,就直接先用
Integer.parseInt(scanner.nextLine());
再用String[] array = scanner.nextLine().split("\s+");
,把String[]转成int[]即可(切记不可直接强转,二者毫无关系)。 - IO真的是最慢的,千万别多次IO。宁可处理麻烦点也别贪图省代码。
- 使用完输入流后记得关闭,这是一个好习惯。用scanner,就写
scanner.close();
,用reader,就写reader.close();
。 - 输入流关闭之后就不能再用了,这点要注意,在最后用完之后关闭就好。
- java.util.Scanner不需要处理异常,java.io.BufferedReader需要处理java.io.IOException,要么try…catch…finally,要么throws,不处理是不能通过编译的。当然啦,自动关闭资源的try语句也挺好的。
- ……
【Java】深入剖析Java输入输出的那些细节相关推荐
- [java]深入剖析Java性能监控调优视频教程
课程概述 基于JDK命令行工具的监控 基于JVisualVM的可视化监控 基于Btrace的监控调试 Tomcat性能监控与调优 Nginx性能监控与调优 JVM层GC调优 JVM字节码与Java代码 ...
- JAVA 代码交互率低的原因分析,深入剖析Java编程中的中文问题及建议最优解决方法...
说明:本文为作者原创,作者联系地址为: josserchai@yahoo.com .由于 Java 编程中的中文 问题是一个老生常谈的问题,在阅读了许多关于 Java 中文问题解决方法之后,结合作者的 ...
- 面经:阿里一面自我剖析---Java岗(40分钟)
这里说明一下我是投的阿里淘系技术部,至今已经面了阿里四面,四次都是电话面试,面试体验都很好,即使问到你不是很了解的方面了,面试官会给一些引导,甚至也会悉心给你讲解. 我是8月22号下午一面的,一面面试 ...
- [Java性能剖析]JVM Management API
JVM本身提供了一组管理的API,通过该API,我们可以获取得到JVM内部主要运行信息,包括内存各代的数据.JVM当前所有线程及其栈相关信息等等.各种JDK自带的剖析工具,包括jps.jstack.j ...
- 面经:阿里三、四面及HR面自我剖析---Java岗(80分钟、30分钟、15分钟)
一面面经链接:面经:阿里一面自我剖析-Java岗(40分钟) 二面面经链接:面经:阿里二面自我剖析-Java岗(50分钟) 三面是8月29号,即二面的第二天就三面了,三面就是主要问的项目了.四面是9月 ...
- try catch语句 java_深入剖析java的try…catch…finally语句
一.前言 前些天参加面试的时候有一道题: public classtest { public static voidmain(String[] args){try{return; }finally{ ...
- JVM - 剖析Java对象头Object Header之指针压缩
文章目录 Pre 指针压缩 论证压缩效果 UseCompressedOops & UseCompressedClassPointers [指针压缩]开启 VS 关闭 指针压缩的目的 为什么堆内 ...
- Java 常见的 30 个误区与细节
转载自 Java 常见的 30 个误区与细节 1.在Java中,没有goto语句.因为大量使用goto语句会降低程序的可读性和可维护性,所以Java语言取消了goto的使用.同时,为了避免程序员自行使 ...
- 剖析java中的String之__拼接
剖析java中的String之__拼接 分类: java 2011-08-24 17:46 31人阅读 评论(0) 收藏 举报 出处, http://blog.csdn.net/izard999/ar ...
- arraylist转int数组_深度剖析Java集合之ArrayList
一. ArrayList 初识 ArrayList是集合的一种实现,实现了接口List,List接口继承了Collection接口. ArrayList 是java 中最常用的集合类型,这是因为它使用 ...
最新文章
- 真能一快遮百丑?为什么要弃坑 FastJson
- classmethod和staticmethod
- Java判断工作日计算,计算随意2个日期内的工作日
- 怎样安装php52-71,CentOS如何安装PHP5和PHP7
- python3人工智能网盘_《Python3入门人工智能掌握机器学习+深度学习提升实战能力》百度云网盘资源分享下载[MP4/5.77GB]...
- 【软件工程】用户在软件项目中承担的工作
- System.Web.AspNetHostingPermission 类型的权限已失败
- jquery 遍历 each 每个匹配元素规定要运行的函数
- 后台权限管理系统设计(图文教程)
- 为什么腾讯微云显示服务器繁忙,谁知道腾讯微云是干什么?
- 沈阳移动打造“爱贝通”、“校讯通”业务助少年儿童健康成长
- java duration 设置值,Java Duration plus(Duration)用法及代码示例
- 一篇文章教你搞懂日志采集利器 Filebeat
- 【Redis】Failed listening on port 6379 (TCP), aborting.
- 618京东物流发大招,中小件完成了大陆地区的区县全面覆盖
- react中css样式表无效
- 星巴克中国首推全新精品咖啡品类“威士忌桶酿咖啡”
- 国密局发布16项密码行业标准 2022年5月1日起实施
- 永辉超市业绩下滑背后:新零售遇融合难题?
- 如何使公园无线AP全覆盖更有价值?