Java中Scanner与System.in的正确使用及资源管理

Java中Scanner与System.in的正确使用及资源管理

本文深入探讨了java中`scanner`类与`system.in`的正确交互方式,指出不应关闭包装`system.in`的`scanner`实例,并解释了其背后的资源管理原理。同时,文章强调了`try-with-resources`语句在管理其他可关闭资源时的重要性,并纠正了通过递归调用`main`方法来重复程序逻辑的常见误区,提供了正确的迭代实现方法。

理解Scanner与System.in的资源管理

在Java编程中,Scanner类常用于从各种输入源读取数据,其中最常见的是标准输入流System.in。开发者普遍被告知要在使用完资源后将其关闭,以防止资源泄露。然而,对于new Scanner(System.in)创建的Scanner实例,这一规则却不适用,甚至会导致程序错误。

System.in是一个由Java虚拟机(JVM)管理的全局标准输入流,它代表着操作系统层面的输入通道。应用程序并不“拥有”System.in,因此也没有责任或权利去关闭它。Scanner类在设计上是一个“过滤器资源”,它包装了底层的实际资源(如System.in、文件输入流等)。当一个Scanner实例被关闭时,它会尝试关闭其所包装的底层资源。如果关闭了System.in,将导致整个JVM进程的标准输入流被关闭,后续任何尝试从System.in读取数据的操作都将失败,抛出NoSuchElementException。

因此,核心原则是:谁创建,谁负责关闭。 由于我们没有创建System.in,所以我们不应该关闭包装它的Scanner。IDE或静态代码分析工具有时会过度热心地提示关闭所有Scanner,但这在这种特定情况下是错误的指导。

正确的资源管理:try-with-resources

尽管Scanner(System.in)不应被关闭,但对于其他由我们自己创建并拥有,且需要明确关闭的资源(例如文件输入/输出流、网络连接等),正确关闭它们是至关重要的。Java 7及更高版本引入了try-with-resources语句,这是一种优雅且健壮的资源管理机制,可以确保资源在使用完毕后自动关闭,即使在发生异常的情况下也能正常工作。

立即学习“Java免费学习笔记(深入)”;

try-with-resources语句适用于实现了java.lang.AutoCloseable接口的任何对象。Scanner类也实现了此接口。

示例:使用try-with-resources管理文件输入

import java.io.File;import java.io.FileNotFoundException;import java.util.Scanner;public class FileReaderExample {    public static void main(String[] args) {        // 假设我们有一个名为 "data.txt" 的文件        File file = new File("data.txt");         // 使用 try-with-resources 确保 Scanner 自动关闭        try (Scanner fileScanner = new Scanner(file)) {            while (fileScanner.hasNextLine()) {                System.out.println(fileScanner.nextLine());            }        } catch (FileNotFoundException e) {            System.err.println("文件未找到: " + e.getMessage());        } catch (Exception e) {            System.err.println("读取文件时发生错误: " + e.getMessage());        }    }}

在上述示例中,fileScanner在try块执行完毕后(无论是正常结束还是因异常退出)都会自动调用其close()方法,无需手动在finally块中处理。

避免递归调用main方法

在程序中,通过递归调用main(null)来重复执行某个逻辑或模拟程序重启是一种错误且危险的做法。main方法是程序的入口点,每次调用它都会在调用上创建一个新的栈帧。无限递归调用main会导致StackOverflowError,使程序崩溃。

正确的做法是使用循环结构(如while或do-while循环)来重复执行应用程序的核心逻辑,直到满足退出条件。

错误示例 (应避免):

public static void ms_calc () {    // ... 部分逻辑 ...    scanbpm.close(); // 错误:System.in 不应关闭    main(null);      // 错误:递归调用 main 方法}

正确示例:使用循环结构重构程序流程

import java.util.InputMismatchException;import java.util.Scanner;public class BpmConverter {    public static void main(String[] args) {        // 创建一个 Scanner 实例用于 System.in,且不关闭        Scanner consoleScanner = new Scanner(System.in);        boolean continueRunning = true;        while (continueRunning) {            msCalculate(consoleScanner);            System.out.println("n是否继续计算?(输入 'yes' 或 'no')");            String choice = consoleScanner.nextLine().trim().toLowerCase();            if (!"yes".equals(choice)) {                continueRunning = false;            }        }        System.out.println("程序结束。");        // 注意:这里仍然不关闭 consoleScanner,因为它包装了 System.in    }    public static void msCalculate(Scanner scanner) {        System.out.println("请输入BPM值:");        int bpm = getUserInt(scanner, 1, 2300);        // BPM 到毫秒的计算逻辑        double mS1 = Math.round((bpm * 100.0) / 6) * 4;        double mS2 = Math.round((bpm * 100.0) / 6) * 2;        int mS1R = (int) mS1;        int mS2R = (int) mS2;        System.out.println("____________________________________");        System.out.println();        System.out.println("全音符 : " + mS1R + " ms");        System.out.println();        System.out.println("二分音符 : " + mS2R + " ms");        for (int x = 1; x < 9; x = x * 2) {            double mS = Math.round((60000.00 / x) / bpm);            int y = x * 4;            int mSR = (int) mS;            System.out.println();            System.out.println("1/" + y + " : " + mSR + " ms");        }        System.out.println("____________________________________");    }    public static int getUserInt(Scanner scanner, int min, int max) {        int userInput = min - 1;        boolean isValidInput = false;        while (!isValidInput || userInput  max) {            try {                userInput = scanner.nextInt();                if (userInput >= min && userInput <= max) {                    isValidInput = true;                } else {                    System.out.println("输入超出范围,请重新输入 (" + min + "-" + max + "):");                }            } catch (InputMismatchException e) {                System.out.println("输入无效,请输入一个整数:");            } finally {                // 消耗掉当前行的剩余输入,包括换行符                scanner.nextLine();            }        }        System.out.println("您的输入: " + userInput);        return userInput;    }}

在这个重构后的代码中:

Scanner实例在main方法中创建一次,并作为参数传递给需要它的方法。主程序逻辑通过while循环重复执行,用户可以选择是否继续。getUserInt方法中的finally { scanner.nextLine(); }是为了处理nextInt()不消耗换行符的问题,确保下一次读取(无论是nextInt()还是nextLine())都能从新行开始。consoleScanner在整个程序生命周期中保持打开状态,因为它包装了System.in。

Java编码规范

遵循Java的编码规范对于代码的可读性和团队协作至关重要。其中一个重要的规范是命名约定:

方法名和局部变量名: 采用camelCase(小驼峰命名法),例如msCalculate、userInput。类名: 采用PascalCase(大驼峰命名法),例如BpmConverter。常量: 采用ALL_CAPS_WITH_UNDERSCORES(全大写加下划线),例如MAX_BPM。

遵循这些约定可以使您的代码更容易被其他Java开发者理解和维护。

总结

正确处理Scanner与System.in的关系是Java初学者常遇到的一个陷阱。记住以下几点:

不要关闭new Scanner(System.in)创建的Scanner实例。 System.in不归你的应用程序所有。对于其他你创建并拥有的资源,使用try-with-resources语句来确保它们自动且安全地关闭。避免递归调用main方法来重复程序逻辑;应使用while或do-while循环。遵循Java编码规范,以提高代码的可读性和专业性。

通过理解这些核心概念和最佳实践,可以编写出更健壮、更易于维护的Java应用程序。

以上就是Java中Scanner与System.in的正确使用及资源管理的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/8249.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
vscode怎么自定义代码片段_片段创建方法说明
上一篇 2025年11月6日 13:28:32
下一篇 2025年11月6日 13:30:34

相关推荐

  • 生成Java中全范围正Double随机数的正确方法

    本文旨在指导开发者如何在Java中生成覆盖整个正Double范围的随机数,并解释了使用ThreadLocalRandom.nextDouble(Double.MIN_VALUE, Double.MAX_VALUE)可能产生偏差的原因。我们将提供一种基于位操作的替代方案,确保生成的随机数在Double…

    2026年9月24日
    100
  • VSCode如何配置.NET开发环境 VSCode搭建.NET项目的完整流程

    首先安装.net sdk并验证版本;2. 安装vscode及microsoft官方c#扩展,确保智能感知和调试功能正常;3. 通过dotnet new命令创建项目,并使用code .在vscode中打开项目;4. 添加构建和调试资产以生成tasks.json和launch.json文件;5. 安装n…

    2026年9月24日
    000
  • PixVerse V5入围Artificial Analysis第一梯队,上线首日全球超百万用户更新并体验

    PixVerse V5入围Artificial Analysis第一梯队,上线首日全球超百万用户更新并体验PixVerse V5入围Artificial Analysis第一梯队,上线首日全球超百万用户更新并体验PixVerse V5入围Artificial Analysis第一梯队,上线首日全球超百万用户更新并体验PixVerse V5入围Artificial Analysis第一梯队,上线首日全球超百万用户更新并体验

    8月27日晚,根据权威独立测评平台 artificial analysis 最新测试结果,爱诗科技发布的pixverse v5 新一代自研视频生成大模型,在图生视频(image to video)项目中排名全球 top2,在文生视频(text to video)项目中位列 top3,保持在全球第一梯…

    2026年9月24日 用户投稿
    100
  • hive安装配置实验

    一、安装前的准备工作 1. 配置并安装hadoop,请参考链接http://blog.csdn.net/wzy0623/article/details/50681554。 2. 下载以下安装包:mysql-5.7.10-linux-glibc2.5-x86_64.tar.gz、apache-hive…

    2026年9月24日
    600
  • 动态表单输入中多答案数据处理教程

    本教程旨在解决Web开发中,如何高效处理包含动态数量答案的表单提交数据,特别是当需要更新现有问题及其关联答案时。文章将详细阐述前端表单的命名策略以及后端PHP如何解析这些动态输入,以准确获取答案内容及其对应的数据库ID,从而实现数据的精准更新,并提供最佳实践建议。 理解动态答案更新的挑战 在构建问答…

    2026年9月24日
    000
  • 大学论文怎么写?让AI工具助你一臂之力

    大学论文怎么写?让AI工具助你一臂之力大学论文怎么写?让AI工具助你一臂之力大学论文怎么写?让AI工具助你一臂之力大学论文怎么写?让AI工具助你一臂之力

    如果要选出大学学习过程中最令人头疼的事,写论文无疑能稳居榜首。从选题开题、内容撰写,到翻译润色、查重降重,每个步骤都耗时耗力,让人焦头烂额。然而,随着 ai 技术的发展,如今写论文这件事,已经可以借助智能工具变得更高效、更轻松。 开题太难?AI 来帮你破局! 论文的第一道难关就是开题。面对浩如烟海的…

    2026年9月24日 用户投稿
    100
  • Java Stream API:从嵌套集合中提取唯一值的两种高效方法

    本文详细介绍了如何利用Java Stream API中的flatMap()和mapMulti()操作,高效地从包含嵌套列表的复杂数据结构(如List中包含List)中提取并收集唯一的元素(如城市名称),替代传统的嵌套循环,提升代码的简洁性和可读性。 在java编程中,我们经常会遇到处理复杂数据结构的…

    2026年9月24日
    100
  • VSCode 怎样配置终端默认路径 VSCode 终端默认路径的配置技巧​

    在 vscode 中配置终端默认启动路径需修改 terminal.integrated.cwd 设置项;2. 可通过用户设置(全局生效)或工作区设置(项目专属)进行配置,优先级为工作区设置覆盖用户设置;3. 路径可使用绝对路径或相对路径(推荐相对路径以提升协作性),windows 系统需注意反斜杠转…

    2026年9月24日
    000
  • 1688找工厂商家如何快速上榜?怎样到1688上选好的厂家

    近年来,越来越多的企业倾向于在1688平台上寻找优质的工厂资源。然而,在众多商家中脱颖而出、实现快速上榜并非易事。本文将为您揭示1688平台上的工厂商家如何提升曝光度与知名度,助您轻松打造高人气店铺。 一、优化店铺信息 1. 完善店铺资料店铺资料是客户了解您的第一窗口,因此务必确保其完整性和专业性。…

    2026年9月24日
    000
  • 使用 PHP 解析 JSON 文件并在网页上显示特定数据

    本文旨在帮助开发者学习如何使用 PHP 解析 JSON 文件,并提取其中的特定数据,将其以结构化的方式展示在网页上。我们将通过一个简单的示例,演示如何读取 JSON 数据,解析成 PHP 数组,并最终以 HTML 表格的形式呈现。 PHP 解析 JSON 数据 JSON (JavaScript Ob…

    2026年9月24日
    100
  • OriginOS 6 深度体验:当操作系统回归「体验为王」

    OriginOS 6 深度体验:当操作系统回归「体验为王」OriginOS 6 深度体验:当操作系统回归「体验为王」OriginOS 6 深度体验:当操作系统回归「体验为王」OriginOS 6 深度体验:当操作系统回归「体验为王」

    2020 年,智能手机刚刚进入 5g 普及阶段,手机的硬件与软件都迎来了一次迭代浪潮——新形态的需求对操作系统的设计与交互都提出了诸多新的问题,originos 的首个版本,可以看作 vivo对这些问题的回答。 彼时,我曾有机会与 OriginOS 开发团队沟通,正如 OriginOS 的中文名原 …

    2026年9月24日 用户投稿
    100
  • 《Python完全自学教程》免费在线连载1.5

    《Python完全自学教程》免费在线连载1.5《Python完全自学教程》免费在线连载1.5《Python完全自学教程》免费在线连载1.5《Python完全自学教程》免费在线连载1.5

    说明: 本节内容,是针对非计算机专业的读者提供的补充知识。 1.5 操作系统 本节不是全面介绍操作系统知识,是提醒读者从开发者的角度认识自己的操作系统——根据多年的经验,至少要能熟练使用一些命令完成常见操作。 首先要声明硬件设备,本书所演示的代码都是基于个人计算机( Personal Compute…

    2026年9月24日 用户投稿
    700
  • 探索VSCode Jupyter Notebook集成与扩展

    VSCode集成Jupyter Notebook提升开发效率,安装Jupyter扩展后可直接运行.ipynb文件,支持内核选择、Shift+Enter执行单元格、图表渲染及变量状态保留;结合Python扩展、Pylance、GitLens等工具,实现调试、智能提示、版本控制与代码转换,适合数据分析与…

    2026年9月24日
    000
  • Linux用户adduser与useradd命令区别

    adduser是交互式脚本,默认创建家目录并设密码,适用于Debian/Ubuntu;2. useradd是底层命令,需手动加参数创建家目录和Shell,通用性强,适合脚本使用。 在Linux系统中,adduser 和 useradd 都可以用来创建新用户,但它们在实现方式、使用习惯和功能上存在明显…

    2026年9月24日
    000
  • 如何在PHP的require语句中传递参数并有效管理变量作用域

    本文探讨了在php中使用`require`或`include`语句时如何向被引入文件传递参数。文章详细阐述了通过直接变量作用域共享、利用`$_get`超全局变量(不推荐)以及将引入文件内容封装为函数或类(推荐最佳实践)这三种方法,并提供了相应的代码示例,旨在帮助开发者理解和选择最适合其场景的参数传递…

    2026年9月24日
    000
  • 迅雷浏览器怎么开启深色模式_迅雷浏览器夜间模式设置

    开启迅雷浏览器深色模式可减少夜间用眼疲劳,具体方法包括:一、通过浏览器菜单进入设置,选择外观中的深色或夜间主题,或开启“跟随系统”选项实现自动切换;二、在操作系统中启用深色模式(Windows路径为“设置>个性化>颜色”,macOS为“系统设置>通用>外观”),并确保浏览器版本最新以兼容显示;三、若…

    2026年9月24日
    100
  • DeepArt的AI混合工具怎么操作?快速生成艺术风格图像的方法

    使用DeepArt类工具时,先选匹配的风格图与内容图,调节风格强度避免失真,推荐尝试Artbreeder、RunwayML、NightCafe等多元平台以提升创作效果。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ DeepArt的AI混合…

    2026年9月24日
    000
  • windows11控制面板在哪里打开_windows11进入传统控制面板的办法

    windows11控制面板在哪里打开_windows11进入传统控制面板的办法windows11控制面板在哪里打开_windows11进入传统控制面板的办法windows11控制面板在哪里打开_windows11进入传统控制面板的办法windows11控制面板在哪里打开_windows11进入传统控制面板的办法

    1、通过Win+R输入control命令可快速打开控制面板;2、任务栏搜索“控制面板”并点击结果即可进入;3、开始菜单中展开“Windows 工具”文件夹可找到控制面板;4、文件资源管理器左侧导航栏下拉选择控制面板;5、桌面新建快捷方式输入explorer shell:ControlPanelFol…

    2026年9月24日 用户投稿
    200
  • 三星S系列手机微信收款语音播报怎么开启?配置语音的详细方法

    要开启三星S系列微信收款语音播报,需先在微信“收付款”中开启“收款到账语音提醒”,再确保手机通知权限开启、媒体音量正常,并将微信设为电池不优化应用。 三星S系列手机要开启微信收款语音播报,核心步骤其实不复杂:首先要在微信应用内部找到并激活“收款到账语音提醒”功能,同时,非常关键的一点是,确保你的三星…

    2026年9月24日
    100
  • Laravel Livewire 使用指南:构建交互式论坛的最佳实践

    本文旨在指导开发者如何在现有的 Laravel 项目中集成 Livewire,并以构建论坛为例,探讨 Livewire 组件的最佳使用方式和命名规范。文章将深入分析全页面组件和独立组件的选择,并提供实用的代码示例和建议,帮助开发者在保证项目结构清晰的前提下,充分利用 Livewire 的优势,构建高…

    2026年9月24日
    100

发表回复

登录后才能评论
关注微信