简体   繁体   English

使 Java HashMap Object 内置 processFile 方法可从 main 方法访问的代码

[英]Code to make Java HashMap Object built in processFile method accessible from main method

So I have the following program written in Java, which reads a text file's contents to a HashMap and takes in a year from the user to return what team won the World Series that year and how many times that team has won the World Series.所以我用 Java 编写了以下程序,它将文本文件的内容读取到HashMap并在一年内从用户那里返回当年赢得世界大赛的球队以及该球队赢得世界大赛的次数。 I've successfully built the HashMap but I'm struggling with how I would make that HashMap accessible within the main driver method of the program (I understand why it's not accessible, I'm looking for how to access it).我已经成功构建了HashMap ,但我正在努力解决如何在程序的主驱动程序方法HashMap可访问(我明白为什么它无法访问,我正在寻找如何访问它)。 Right now, the instantiated HashMap in the main method is empty.现在,main方法中实例化的HashMap是空的。 I've been stuck on this for a while and can't seem to find a way to do this.我已经坚持了一段时间,似乎无法找到一种方法来做到这一点。 Any insight would be greatly appreciated!任何见解将不胜感激!

import java.io.*; // contains all classes used in file processing
import java.io.File; // allows program to gather file information
import java.io.FileNotFoundException;

import java.util.*;
import java.util.Scanner; // allows program to get user input

public class Program3 {

    public void processFile(String filename)
    {
        // pass filename as arg to File class
        File worldSeries = new File("Program3.txt");

        // Create a Scanner object
        Scanner scan;

        // Create String line variable to read each line
        String line = "";

        try {
            // HashMap which tracks each year's World Series Winner
            HashMap<Integer,String> yearWinner = new HashMap<Integer,String>();
            // HashMap which tracks the number of times each team wins the World Series
            HashMap<String,Integer> numWins = new HashMap<String,Integer>();

            // Set startYear
            int startYear = 1903;

            // Pass filename to Scanner object
            scan = new Scanner(worldSeries);

            // Check for another line in input to scan
            while(scan.hasNextLine()){
                // Skip years during which the WorldSeries was not played
                if(startYear == 1904 || startYear == 1994) {
                    startYear++;
                }
                line = scan.nextLine(); // reads nextLine of String data type
                yearWinner.put(startYear, line); //  inserts a mapping into a HashMap
                if(numWins.containsKey(line)) { // checks if a key is mapped into the HashMap or not
                    numWins.put(line, numWins.get(line)+1); // if key exists, increment numWins value
                }else {
                    numWins.put(line,1); // if key does not exist, set numWins to 1
                }
                startYear++; // increment year
            }
            //testing for some case
            System.out.println(yearWinner.get(1905));
            System.out.println(numWins.get("New York Yankees"));
        } catch (FileNotFoundException e) {
            System.out.println("File not found");
        }
    }
    /*
    collectInput - method to collect user input for the year.
     */
    public int collectInput() {
        Scanner in = new Scanner(System.in); // Scanner object to read user input.

        int year; // declare year
        System.out.print("Please enter a year between 1903 & 2020: ");
        year = in.nextInt(); // collect the user input

        // check the year is either 0(sentinel value) or within range 1903 and 2020.
        while (year != 0 && (year < 1903 || year > 2020)) {
            // otherwise collect a valid year.
            System.out.print("Year is invalid! Please enter a year between 1903 & 2020: ");
            year = in.nextInt();
        }

        return year; // return the year.
    }
    /*
    displayOutput - method gets the user input and displays the output.
    @param winners - class instance
    @param yearWinner - map which stores year and team
    @param winsMap - map which stores team and number of wins
     */
    public void displayOutput(Program3 winners, HashMap<Integer, String> yearWinner, HashMap<String, Integer> numWins) {

        // loop the input until sentinel value is entered
        while (true) {

            // call the method to collect input from user
            int year = collectInput();

            // validate for sentinel value
            if (year == 0) {
                System.out.println("Thank you, goodbye!");
                return; // end program
            }

            // get the winning team for the given year.
            String winningTeam = winners.getWinningTeamForYear(year, yearWinner);

            // if there is winning team for the given year..
            if (winningTeam != null) {
                // get the number of wins of that team between 1903 and 2020.
                int numOfWins = winners.getNumberOfWins(winningTeam, numWins);
                // display the winning team and number of wins.
                System.out.println("The winning for the Year " + year + " is: " + winningTeam);
                System.out.println("Number of Wins secured by team: " + winningTeam + " is " + numOfWins);
            }
        }
    }
    // pass the year and get the winning team
    public String getWinningTeamForYear(int year, HashMap<Integer, String> yearWinner) {
        // if there is an entry for the given year.. to validate excluded years
        if (yearWinner.containsKey(year)) { // if yearWinner containsKey
            return yearWinner.get(year); // return the winning team
        }
        else {
            // display the message and return null.
            System.out.println("World Series not held in " + year);
            return null;
        }
    }

    // pass the team name in the hashmap and get the number of wins
    public int getNumberOfWins(String winningTeam, HashMap<String, Integer> numWins) {
        return numWins.get(winningTeam);
    }

    public static void main(String[] args) {

        HashMap<Integer, String> yearWinner = new HashMap<>(); // hashmap to store year and winners.
        HashMap<String, Integer> numWins = new HashMap<>(); // hashmap to store winners and number of wins.

        String fileName = "Program3.txt"; // file name where the data is stored.
        // You can also use full path of file Ex. E:\\InputFiles\\Program3.txt (\\ delimiter slash indicating \)

        Program3 winners = new Program3();
        winners.processFile("Program3.txt");
        System.out.println(yearWinner);
        winners.displayOutput(winners, yearWinner, numWins); // non static method to collect user input and display output.

    }
}

Program3.txt from which HashMap is being built:正在构建Program3.txtHashMap

Boston Americans
New York Giants
Chicago White Sox
Chicago Cubs
Chicago Cubs
Pittsburgh Pirates
Philadelphia Athletics
Philadelphia Athletics
Boston Red Sox
Philadelphia Athletics
Boston Braves
Boston Red Sox
Boston Red Sox
Chicago White Sox
Boston Red Sox
Cincinnati Reds
Cleveland Indians
New York Giants
New York Giants
New York Yankees
Washington Senators
Pittsburgh Pirates
St. Louis Cardinals
New York Yankees
New York Yankees
Philadelphia Athletics
Philadelphia Athletics
St. Louis Cardinals
New York Yankees
New York Giants
St. Louis Cardinals
Detroit Tigers
New York Yankees
New York Yankees
New York Yankees
New York Yankees
Cincinnati Reds
New York Yankees
St. Louis Cardinals
New York Yankees
St. Louis Cardinals
Detroit Tigers
St. Louis Cardinals
New York Yankees
Cleveland Indians
New York Yankees
New York Yankees
New York Yankees
New York Yankees
New York Yankees
New York Giants
Brooklyn Dodgers
New York Yankees
Milwaukee Braves
New York Yankees
Los Angeles Dodgers
Pittsburgh Pirates
New York Yankees
New York Yankees
Los Angeles Dodgers
St. Louis Cardinals
Los Angeles Dodgers
Baltimore Orioles
St. Louis Cardinals
Detroit Tigers
New York Mets
Baltimore Orioles
Pittsburgh Pirates
Oakland Athletics
Oakland Athletics
Oakland Athletics
Cincinnati Reds
Cincinnati Reds
New York Yankees
New York Yankees
Pittsburgh Pirates
Philadelphia Phillies
Los Angeles Dodgers
St. Louis Cardinals
Baltimore Orioles
Detroit Tigers
Kansas City Royals
New York Mets
Minnesota Twins
Los Angeles Dodgers
Oakland Athletics
Cincinnati Reds
Minnesota Twins
Toronto Blue Jays
Toronto Blue Jays
Atlanta Braves
New York Yankees
Florida Marlins
New York Yankees
New York Yankees
New York Yankees
Arizona Diamondbacks
Anaheim Angels
Florida Marlins
Boston Red Sox
Chicago White Sox
St. Louis Cardinals
Boston Red Sox
Philadelphia Phillies
New York Yankees
San Francisco Giants
St. Louis Cardinals
San Francisco Giants
Boston Red Sox
San Francisco Giants
Kansas City Royals
Chicago Cubs
Houston Astros
Boston Red Sox
Washington Nationals
Los Angeles Dodgers

Add the two maps as parameters to the processFile() method.将这两个映射作为参数添加到processFile()方法。

Parameters of a collection type that are passed in empty, and expected to be filled by the method, are referred to as result collectors .以空方式传递并期望由方法填充的集合类型的参数称为结果收集器

By using parameters instead of return value, you can have more than one.通过使用参数而不是返回值,您可以拥有多个。

public void processFile(String filename, HashMap<Integer,String> yearWinner,
                        HashMap<String,Integer> numWins)
{
    ... code unchanged ...

    try {
        // delete the lines that declared yearWinner and numWins

        // Set startYear
        int startYear = 1903;

        ... code unchanged ...
public static void main(String[] args) {

    ... code unchanged ...

    winners.processFile("Program3.txt", yearWinner, numWins);

    ... code unchanged ...
}

The Answer by Andreas is correct and smart.安德烈亚斯的回答是正确而聪明的。 But there is a downside to passing such result collector arguments.但是传递这样的结果收集器 arguments 有一个缺点。 The fact that they are being used to communicate back to the calling method is not obvious.它们用于与调用方法进行通信的事实并不明显。

In Java 16 and later, we can make more obvious the results by returning a record that holds both of the generated maps.Java 16及更高版本中,我们可以通过返回包含两个生成的地图的record来使结果更加明显。

Records记录

The records feature lets us briefly declare a class whose primary purpose is to transparently and immutable communicate data.记录功能让我们可以简单地声明一个 class,其主要目的是透明和不可变地通信数据。 Simply declare the type and name of the member fields within parentheses.只需在括号内声明成员字段的类型和名称。 The compiler implicitly creates the constructor, getters, equals & hashCode , and toString .编译器隐式创建构造函数、getter、 equals & hashCodetoString

Be aware that you can declare your record in a separate .java file, nested within a class, or even locally within a method.请注意,您可以在单独的.java文件中声明您的record ,嵌套在 class 中,甚至在方法中本地声明。

record Results ( Map<Integer,String> yearWinner, Map<String,Integer> numWins ) 
{
}

Notice that we can promise to return the more general Map interface rather than specific concrete HashMap implementation.请注意,我们可以 promise 返回更通用的Map接口,而不是具体的具体HashMap实现。 This polymorphic encapsulation gives us the freedom to later change our choice of Map implementation.这种 多态封装让我们可以自由地在以后更改我们对Map实现的选择。

The getter methods are named the same as the property (member field) they export. getter 方法的名称与它们导出的属性(成员字段)相同。 The JavaBeans-style naming with get… / is… is not used.使用带有get… / is…的 JavaBeans 样式命名。

System.out.println( myResults.yearWinner() ) ;

Change your processing method to return an object of this record type.更改您的处理方法以返回此记录类型的 object。

public Results processFile( String filename )  // Returns a `Results` object. 
{
    …
    HashMap<Integer,String> yearWinner = … ;
    HashMap<String,Integer> numWins = … ;
    return new Results( yearWinner , numWins ) ;
}

Better to return unmodifiable maps .最好返回不可修改的地图 Call Map.copyOf in Java 10 and later.在 Java 10 及更高版本中调用Map.copyOf A record by definition is meant to immutably communicate data.根据定义, record意味着不可变地传递数据。 So make your record as deeply immutable as is practicable.因此,尽可能让您的记录保持不变。

public Results processFile( String filename )
{
    …
    HashMap<Integer,String> yearWinner = … ;
    HashMap<String,Integer> numWins = … ;
    return new Results( Map.copyOf( yearWinner ) , Map.copyOf( numWins ) ) ;  // Return immutable maps, copied from our mutable maps.
}

Of course in older versions of Java, you could have declared a class to do the same thing (return results to calling method).当然,在旧版本的 Java 中,您可以声明一个 class 来做同样的事情(将结果返回给调用方法)。 But declaring a conventional class involves so much boilerplate that programmers often do not bother.但是声明一个传统的 class 涉及太多样板文件,程序员通常不会打扰。 The new records feature was expressly developed to address this kind of need to merely communicate immutable data.新的记录功能是专门为解决这种仅传达不可变数据的需求而开发的。 A nice bonus benefit is a huge reduction in the boilerplate.一个不错的额外好处是样板代码的大量减少。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM