前言

无论是新手入门的命令行输入输出,还是说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输出的一些问题

  1. printf();如果格式化不正确,就会爆java.util.IllegalFormatConversionException异常。
  2. 为什么Eclipse/IDEA这样的IDE在爆异常的时候都可能红字和普通字混合?
    异常是err错误流,普通输出是out普通输出流,可能会在IDE里由于线程的问题而混合在一起。
  3. 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;`
    
  4. 打印输出的时候会启动IO,所以不建议直接输出,可以用StringBuilder把答案“组织好”再统一输出。
  5. 循环里每次都cout的时候能不输出最后的空格,不需要额外的调整,但System.out.println()输出的时候没有这种考虑,必须自己处理最后一次的结果。我建议可以用builder.append(i).append(" ");builder.toString().trim();,最后消去末尾的一个空格,即可完成所需要的输出。
  6. 格式化打印指定位数小数是常见操作,可用printf()完成任务目标。比如,System.out.printf("%.5f");就是保留五位小数打印浮点数。
  7. ……(留待补充)

对于第五条,说明一下。我们先写一个测试类,打一下时间戳:

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输入的一些问题

  1. 性能实在不达标,看不对就换BufferedReader,再不行就换C++。
  2. 切记scanner.nextInt()之后没换行,此时如果读一行scanner.nextLine()可能只读到空字符串——"",导致后续崩盘。所以遇到单行单个数值+单行多数值的情况,就直接先用Integer.parseInt(scanner.nextLine());再用String[] array = scanner.nextLine().split("\s+");,把String[]转成int[]即可(切记不可直接强转,二者毫无关系)。
  3. IO真的是最慢的,千万别多次IO。宁可处理麻烦点也别贪图省代码。
  4. 使用完输入流后记得关闭,这是一个好习惯。用scanner,就写scanner.close(); ,用reader,就写reader.close();
  5. 输入流关闭之后就不能再用了,这点要注意,在最后用完之后关闭就好。
  6. java.util.Scanner不需要处理异常,java.io.BufferedReader需要处理java.io.IOException,要么try…catch…finally,要么throws,不处理是不能通过编译的。当然啦,自动关闭资源的try语句也挺好的。
  7. ……

【Java】深入剖析Java输入输出的那些细节相关推荐

  1. [java]深入剖析Java性能监控调优视频教程

    课程概述 基于JDK命令行工具的监控 基于JVisualVM的可视化监控 基于Btrace的监控调试 Tomcat性能监控与调优 Nginx性能监控与调优 JVM层GC调优 JVM字节码与Java代码 ...

  2. JAVA 代码交互率低的原因分析,深入剖析Java编程中的中文问题及建议最优解决方法...

    说明:本文为作者原创,作者联系地址为: josserchai@yahoo.com .由于 Java 编程中的中文 问题是一个老生常谈的问题,在阅读了许多关于 Java 中文问题解决方法之后,结合作者的 ...

  3. 面经:阿里一面自我剖析---Java岗(40分钟)

    这里说明一下我是投的阿里淘系技术部,至今已经面了阿里四面,四次都是电话面试,面试体验都很好,即使问到你不是很了解的方面了,面试官会给一些引导,甚至也会悉心给你讲解. 我是8月22号下午一面的,一面面试 ...

  4. [Java性能剖析]JVM Management API

    JVM本身提供了一组管理的API,通过该API,我们可以获取得到JVM内部主要运行信息,包括内存各代的数据.JVM当前所有线程及其栈相关信息等等.各种JDK自带的剖析工具,包括jps.jstack.j ...

  5. 面经:阿里三、四面及HR面自我剖析---Java岗(80分钟、30分钟、15分钟)

    一面面经链接:面经:阿里一面自我剖析-Java岗(40分钟) 二面面经链接:面经:阿里二面自我剖析-Java岗(50分钟) 三面是8月29号,即二面的第二天就三面了,三面就是主要问的项目了.四面是9月 ...

  6. try catch语句 java_深入剖析java的try…catch…finally语句

    一.前言 前些天参加面试的时候有一道题: public classtest { public static voidmain(String[] args){try{return; }finally{ ...

  7. JVM - 剖析Java对象头Object Header之指针压缩

    文章目录 Pre 指针压缩 论证压缩效果 UseCompressedOops & UseCompressedClassPointers [指针压缩]开启 VS 关闭 指针压缩的目的 为什么堆内 ...

  8. Java 常见的 30 个误区与细节

    转载自 Java 常见的 30 个误区与细节 1.在Java中,没有goto语句.因为大量使用goto语句会降低程序的可读性和可维护性,所以Java语言取消了goto的使用.同时,为了避免程序员自行使 ...

  9. 剖析java中的String之__拼接

    剖析java中的String之__拼接 分类: java 2011-08-24 17:46 31人阅读 评论(0) 收藏 举报 出处, http://blog.csdn.net/izard999/ar ...

  10. arraylist转int数组_深度剖析Java集合之ArrayList

    一. ArrayList 初识 ArrayList是集合的一种实现,实现了接口List,List接口继承了Collection接口. ArrayList 是java 中最常用的集合类型,这是因为它使用 ...

最新文章

  1. 真能一快遮百丑?为什么要弃坑 FastJson
  2. classmethod和staticmethod
  3. Java判断工作日计算,计算随意2个日期内的工作日
  4. 怎样安装php52-71,CentOS如何安装PHP5和PHP7
  5. python3人工智能网盘_《Python3入门人工智能掌握机器学习+深度学习提升实战能力》百度云网盘资源分享下载[MP4/5.77GB]...
  6. 【软件工程】用户在软件项目中承担的工作
  7. System.Web.AspNetHostingPermission 类型的权限已失败
  8. jquery 遍历 each 每个匹配元素规定要运行的函数
  9. 后台权限管理系统设计(图文教程)
  10. 为什么腾讯微云显示服务器繁忙,谁知道腾讯微云是干什么?
  11. 沈阳移动打造“爱贝通”、“校讯通”业务助少年儿童健康成长
  12. java duration 设置值,Java Duration plus(Duration)用法及代码示例
  13. 一篇文章教你搞懂日志采集利器 Filebeat
  14. 【Redis】Failed listening on port 6379 (TCP), aborting.
  15. 618京东物流发大招,中小件完成了大陆地区的区县全面覆盖
  16. react中css样式表无效
  17. 星巴克中国首推全新精品咖啡品类“威士忌桶酿咖啡”
  18. 国密局发布16项密码行业标准 2022年5月1日起实施
  19. 永辉超市业绩下滑背后:新零售遇融合难题?
  20. 如何使公园无线AP全覆盖更有价值?

热门文章

  1. 程序10 VC编写批量重命名工具
  2. Java Lambda表达
  3. 用Backbone.js创建一个联系人管理系统(四)
  4. WinForm中使用AnyCAD三维控件 の 初始化
  5. Java volatile关键字
  6. F5刷新表单页不能清空缓存
  7. 使用java实现rfc3161,openssl验证用自签名证书签名的RFC3161时间戳
  8. mysql optimizer组件_MySQL Optimizer
  9. celery 可视化_Django中Celery的实现介绍(一)
  10. 二元函数图像生成器_GAN生成图像综述