【问题标题】:java create time range attribute for data classjava为数据类创建时间范围属性
【发布时间】:2021-10-19 08:16:23
【问题描述】:

我是 Java 新手,目前正在做一个小练习。没有外部库。我有一个csv file,其中包含有关 covid 病例的数据。现在我需要为这些数据创建一个类。每个数据对象都有两个属性:区域和时间范围。区域可以是大陆或国家。时间范围是一对开始日期和结束日期。输入区域和时间范围后,它将显示适合这些条目的行。例如越南和 2021 年 6 月 1 日 - 2021 年 6 月 30 日将有以下结果:

这是读取 csv 行的代码:

File inputFile = new File("covid-data.csv");
        Scanner sc = new Scanner(inputFile);
        String str;
        String[] tokens;
        while (sc.hasNext()) {
            str = sc.nextLine();
            tokens = str.split(",");
            Data d = new Data(tokens[2], tokens[3]);
        }

这是我的数据类:

public class Data {
    String area;
    String time_range;

    public Data(String a, String time) {
        area = a;
        time_range = time;
    }

我不知道如何处理时间范围,所以我现在只能将它分配给“时间”列。此处不能使用外部库。我是否需要创建具有单独开始日期和结束日期的哈希图?我还需要转换为日期格式还是将其保留为字符串?谢谢!!

【问题讨论】:

    标签: java class object oop


    【解决方案1】:

    没有外部库。我有一个 csv 文件,其中包含有关 covid 病例的数据。

    哎呀。糟糕的开始。读取 CSV 比您想象的要复杂,并且是一个非常好的依赖项(例如,您的代码不支持的多行 CSV。如果出现任何非 ASCII 字符,您的代码将随机开始失败。您的代码不处理引用的值。您的代码不会让您轻松编组 - CSV 库所做的所有事情)。现代开发本质上与依赖关系捆绑在一起。你对他们的厌恶是你需要解决的。

    给定一个包含时间范围的字符串,您需要:

    • 提取开始和结束时间,例如使用.split。
    • 使用LocalDate.parse 并以正确的格式传递,将'start' 和'end' 字符串转换为java.time.LocalDate 实例;它可能只是 ISO 格式,有一个预制的 DateTimeFormatter 实例。
    • 然后一个简单的 for 循环就可以完成这项工作:
    LocalDate start = ...., end = ....;
    for (LocalDate current = start; !current.isAfter(end); current = current.plusDays(1)) {
        // this code is called once for each date, and `current` holds that date.
    }
    

    【讨论】:

      【解决方案2】:

      首先,Answer by rzwitserloot 中的两点都是正确且明智的:

      • 禁止使用外部库意味着错过了使用 Java 的最佳理由:其庞大而丰富的支持库生态系统。
      • 为您的工作使用 java.time 类,例如 LocalDate。切勿使用旧的日期时间类,例如 Date 或 Calendar。

      具体来说,我建议添加ThreeTen-Extra 库以利用其LocalDateRange 类来包含一对LocalDate 对象。该类提供了方便的方法,例如abuts、overlaps、contains 等。

      我建议您通过使用半开放方法定义一个时间跨度来完成所有日期处理,其中开始是包含而结束是独占 .因此,该月从第一个月开始,一直持续到但不包括接下来几个月的第一个月。 6 月为 6 月 1 日至 7 月 1 日。LocalDateRange 默认使用半开,但如果您坚持,也可以适应全封闭(包括开头和结尾)。

      在 Java 16 及更高版本中,使用 records 功能定义一个类以透明且不可变地保存您的数据。您只需声明每个成员字段的类型和名称。编译器隐式创建默认构造函数、getter、equals & hashCode 和toString。额外功能:除了嵌套或单独(同上enum 和interface),还可以在本地定义记录。

      所以你的整个班级只有一条短线:

      record CovidDaily ( String isoCode , String continent , String location, LocalDate date , … ) {}
      

      过滤行、循环或使用流。

      LocalDate start = LocalDate.of( 2021 , Month.JUNE , 1 ) ;
      LocalDate end = LocalDate.of( 2021 , Month.JULY , 1 ) ;
      List< CovidDaily > hits = new ArrayList<>() ;
      List< CovidDaily > dailies = … ;
      for( CovidDaily covidDaily: dailies ) 
      {
          LocalDate ld = covidDaily.date() ;
          if( ( ! ld.isBefore( start ) ) && ( ld.isBefore( end ) ) 
          { hits.add( covidDaily) ; } // Else ignore this record and move on to next.
      }
      

      通常最好返回不可修改的结果。

      return List.copyOf( hits ) ;
      

      流式方法更短。

      LocalDate start = LocalDate.of( 2021 , Month.JUNE , 1 ) ;
      LocalDate end = LocalDate.of( 2021 , Month.JULY , 1 ) ;
      List< CovidDaily > dailies = … ;
      return dailies.stream().filter( covidDaily -> ( ! covidDaily.date().isBefore( start ) ) && ( covidDaily.date().isBefore( end ) ) ).toList();
      

      使用LocalDateRange。

      LocalDateRange range = LocalDateRange.of( 
          LocalDate.of( 2021 , Month.JUNE , 1 ) ,
          LocalDate.of( 2021 , Month.JULY , 1 ) ) ;
      List< CovidDaily > dailies = … ;
      return dailies.stream().filter( covidDaily -> range.contains( covidDaily.date() ) ).toList();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-06
        • 2014-11-26
        • 1970-01-01
        • 2019-07-19
        • 2014-06-25
        • 1970-01-01
        • 2012-11-10
        • 2020-01-30
        相关资源
        最近更新 更多