Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在java中从字符串指定类属性_Java_Csv_Filtering_Java.util.scanner - Fatal编程技术网

如何在java中从字符串指定类属性

如何在java中从字符串指定类属性,java,csv,filtering,java.util.scanner,Java,Csv,Filtering,Java.util.scanner,所以我用扫描仪读取一个文件,它的格式类似: title, name, age Mr, Matthew, 20 mr, Paul, 30 miss, Anne, 24 CSV^ 控制台程序 Scanner input = new Scanner(System.in); System.out.println("Please select what data you want to load:"); String selection = input.next();

所以我用扫描仪读取一个文件,它的格式类似:

title, name, age
Mr, Matthew, 20
mr,  Paul, 30
miss, Anne, 24 
CSV^

控制台程序

    Scanner input = new Scanner(System.in);

    System.out.println("Please select what data you want to load:");

    String selection = input.next();

    int temp = 0;

    for(int i=0; i< header.length; i++){

        if(header[i].equals(selection)){

            temp = i;
        break;

      }
    }
扫描仪输入=新扫描仪(System.in);
System.out.println(“请选择要加载的数据:”);
字符串选择=input.next();
内部温度=0;
对于(int i=0;i
temp将为我们提供指定选项的索引,因此如果是2,我们将希望访问age属性

当我的控制台应用程序运行时,我会提示他们(用户)输入他们想要的数据。 所以他们可能会输入“age”,所以我不知道如何获取这个“age”字符串并使用它访问person对象。 程序输出的理想情况应该是:
20,30,24
遍历各个年龄段并打印

我接受他们的输入,所以
String input=scanner.nextLine()
然后,我循环遍历person对象数组以获取输入的索引。一旦我有了这个索引,我就想在索引处访问person的属性。所以,如果我的索引是1,我想访问属性“name”

在javascript中,我可以用字符串说
person['age']
,尽管java是一个完全不同的故事。我研究了java的“反射API”,尽管这是一个繁重的学习过程

我研究了java的“反射API”,尽管这是一个繁重的学习过程

嗯,反思才是出路。它广泛应用于许多框架中

但也许一个更简单的解决方案会满足您的需要。使用
开关
决定返回哪个属性,并将其封装在
Person
类的方法中:

class Person {
  private String name, title;
  private int age;

  public loadData(String csv){
      String[] list = csv.split(",");
      name = list[0];
      title = list[1];
      age = Integer.parseInt(list[2]);
  }

  public Object attribute(String attribute) {
      switch (attribute) {
          case "name": return this.name;
          case "title": return this.title;
          case "age": return this.age;
          default: throw new RuntimeException("Invalid attribute: " + attribute);
      }
  }
}
public class Person {
  Map<String, String> props = new HashMap<>();

  public void addProperty(String propertyName, String value) {
    // could add error checking to ensure propertyName not null/emtpy
    props.put(propertyName, value);
  }

  /**
   * returns the value of the property; may return null
  */
  public String getProperty(String propertyName) {
    return props.get(propertyName);
  }
}

将开关封装在方法中符合OOP原则,因为它隐藏了其他对象的属性存储方式,只公开了查询属性的接口。反射破坏了所有的封装。

首先,我们应该为您的
Person
类添加一个构造函数

class Person {
  public Person(String name, String title, int age) {
    this.name = name;
    this.title = title;
    this.age = age;
  }
}
现在,当您阅读输入时,您可以使用
映射
,如下所示。在这里,在阅读每一行之后,我们创建一个
Person
对象,然后使用该人的年龄在地图中创建一个条目,其中键为
age
,值为
Person

Map<Integer, Person> mapOfPeople = new HashMap<>();
while (input.hasNextLine()) {
    String line[] = input.nextLine().split(",");
    Perso person = new Perso(line[1], line[0], Integer.parseInt(line[2].trim()));
    mapOfPeople.put(person.getAge(), person);
}

虽然通常我不赞成使用
Map
来保存对象的字段,但如果属性的数量很大,甚至可能在CSV文件中有所不同(例如,一些文件中有一个人上过大学,另一个没有),那么使用
Map
来保存属性可能是合适的

在这种情况下,可以定义一个简单的
Person
类:

class Person {
  private String name, title;
  private int age;

  public loadData(String csv){
      String[] list = csv.split(",");
      name = list[0];
      title = list[1];
      age = Integer.parseInt(list[2]);
  }

  public Object attribute(String attribute) {
      switch (attribute) {
          case "name": return this.name;
          case "title": return this.title;
          case "age": return this.age;
          default: throw new RuntimeException("Invalid attribute: " + attribute);
      }
  }
}
public class Person {
  Map<String, String> props = new HashMap<>();

  public void addProperty(String propertyName, String value) {
    // could add error checking to ensure propertyName not null/emtpy
    props.put(propertyName, value);
  }

  /**
   * returns the value of the property; may return null
  */
  public String getProperty(String propertyName) {
    return props.get(propertyName);
  }
}
尽管注意,对于大多数数据集,我希望名称不是单个条目,因为通常会有姓、名等。尽管如此,有限数量的常见期望值的模式是相同的。此外,还可以进行调整,以便可以直接获得某些已知字段的整数值

然后,在解析文件时,保留包含属性定义的标题行。然后,对于随后读取的每一行,创建一个新的
Person
对象,然后按顺序添加属性

List<Person> allPersons = new ArrayList<>();

while ( (line = READ_NEXT_LINE) ) {
  // NOTE: this is not a safe way to handle CSV files; should really
  //   use a CSV reader as fields could have embedded commas
  attrs[] = line.split(",");
  Person p = new Person();
  for (int i = 0; i < titleRow.length; ++i) {
    p.addProperty(titleRow[i], attrs[i]);
  }

  allPersons.add(p);
}

请注意,这种方法确实打破了
Javabean
的概念,但这可能是一个问题,也可能不是一个问题,这取决于您的需求。

“当我的控制台应用程序运行时,我会提示他们(用户)输入他们想要的数据”--请也共享该代码。@NicholasK doneSo您只想按
年龄
搜索吗?没错@尼古拉斯反射实际上是最糟糕的选择,应该尽量避免。它很慢,因为JIT编译器无法优化它;它很容易出错,因为在编译时无法检测到错误。这是一个很有帮助的答案,尽管在我的实际程序(不是上面的程序)中,我有20个或更多的属性,并且正在尝试避免为硬编码的可能性做准备,因为它不是很有效。学习API的效率较低,你自己说的API有一个陡峭的学习曲线。。。不是吗?如果数据集包含超过1个给定年龄的人,会发生什么情况?此外,我知道OP只对年龄搜索感兴趣,但正如OP在对另一个问题的评论中所指出的那样,如果存在许多属性,那么长期方法似乎不太可能只依赖一个年龄属性进行搜索。因此,这个示例代码不会缩放。嗯,是的,缩放不是这里的问题。我确实理解两个人年龄相同的问题,但我想把这个问题转到@Matthew Fallon。在这种情况下会发生什么?
List<Person> allPersons = new ArrayList<>();

while ( (line = READ_NEXT_LINE) ) {
  // NOTE: this is not a safe way to handle CSV files; should really
  //   use a CSV reader as fields could have embedded commas
  attrs[] = line.split(",");
  Person p = new Person();
  for (int i = 0; i < titleRow.length; ++i) {
    p.addProperty(titleRow[i], attrs[i]);
  }

  allPersons.add(p);
}
// find all people of a given age
List<Person> peopleAge20 = allPersons.stream()
            .filter(p -> p.getAge() == 20)
            .collect(Collectors.toList());
    System.out.println(peopleAge20);        

    // summary statics (average age) for all people
    IntSummaryStatistics stats = 
            allPersons.stream().mapToInt(p -> p.getAge()).summaryStatistics();
    System.out.printf("Average age: %f\n", stats.getAverage());