什么相当于JAVA的流API中的C#的Select子句

时间:2017-05-15 07:34:45

标签: java c# java-8 java-stream

我想过滤Person类的列表,最后使用Streams映射到Java中的一些匿名类。我能够在C#中轻松地做同样的事情。

人类

class Person
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Address { get; set; }
}

以期望格式映射结果的代码。

 List<Person> lst = new List<Person>();

 lst.Add(new Person() { Name = "Pava", Address = "India", Id = 1 });
 lst.Add(new Person() { Name = "tiwari", Address = "USA", Id = 2 });
 var result = lst.Select(p => new { Address = p.Address, Name = p.Name }).ToList();

现在,如果我想访问新创建类型的任何属性,我可以使用下面提到的语法轻松访问。

Console.WriteLine( result[0].Address);

理想情况下,我应该使用循环来迭代结果。

我知道在java中我们收集ToList并映射Select。 但我无法只选择Person类的两个属性。 我该怎么做Java

4 个答案:

答案 0 :(得分:13)

好吧,您可以将Person个实例映射到匿名类的实例,例如假设

class Person {
    int id;
    String name, address;

    public Person(String name, String address, int id) {
        this.id = id;
        this.name = name;
        this.address = address;
    }
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public String getAddress() {
        return address;
    }
}

你可以做到

List<Person> lst = Arrays.asList(
                       new Person("Pava", "India", 1), new Person("tiwari", "USA", 2));
List<?> result = lst.stream()
    .map(p -> new Object() { String address = p.getAddress(); String name = p.getName(); })
    .collect(Collectors.toList());

但是你可能会注意到,它并不简洁,更重要的是,result变量的声明不能引用匿名类型,这使得匿名类型的实例几乎无法使用。 / p>

目前,lambda表达式是唯一支持声明隐含类型变量的Java功能,它可以是匿名的。例如,以下内容可行:

List<String> result = lst.stream()
    .map(p -> new Object() { String address = p.getAddress(); String name = p.getName(); })
    .filter(anon -> anon.name.startsWith("ti"))
    .map(anon -> anon.address)
    .collect(Collectors.toList());

答案 1 :(得分:2)

您似乎想transform Person您的map具有3个属性的持有者有2个属性。这是一个简单的lst.stream().map(p -> new AbstractMap.SimpleEntry(p.address, p.name)) .collect(Collectors.toList()); 操作:

SimpleEntry

这会将您的条目收集到{{1}},这只是两个值的持有者。如果你需要两个以上,那你就不走运了 - 你需要创建自己的持有人(班级)。

答案 2 :(得分:1)

如果您知道要选择哪些属性并且这不会改变,我建议您使用Person的属性子集编写一个小类。然后,您可以将每个人映射到该类的实例并将其收集到列表中:

Stream.of(new Person(1, "a", "aa"), new Person(2, "b", "bb"), new Person(3, "b", "bbb"),
          new Person(4, "c", "aa"), new Person(5, "b", "bbb"))
      .filter(person -> true)    // your filter criteria goes here
      .map(person -> new PersonSelect(person.getName(), person.getAddress()))
      .collect(Collectors.toList());

// result in list of PersonSelects with your name and address

如果所需属性集不同,则可以使用数组。它看起来与您的C#代码更相似,但不提供类型安全性:

Stream.of(new Person(1, "a", "aa"), new Person(2, "b", "bb"), new Person(3, "b", "bbb"),
          new Person(4, "c", "aa"), new Person(5, "b", "bbb"))
      .filter(person -> true)
      .map(person -> new Object[] {person.getName(), person.getAddress()})
      .collect(Collectors.toList())
      .forEach(p -> System.out.println(Arrays.asList(p)));

// output: [a, aa], [b, bb], [b, bbb], [c, aa], [b, bbb]

答案 3 :(得分:0)

如果要创建 Person实例的列表,首先应提供构造函数,例如像这样:

class Person {
  public int id;
  public String name;
  public String address;

  public Person( int pId, String pName, String pAddress ) {
    super();
    id = pId;
    name = pName;
    address = pAddress;
  }
}

然后你可以使用流:

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

lst.add(new Person(1, "Pava", "India" ));
lst.add(new Person( 2, "tiwari", "USA" ) );

//since id is an int we can't use null and thus I used -1 here    
List<Person> result = lst.stream().map(p -> new Person(-1, p.name, p.address)).collect(Collectors.toList());

如果您想过滤人员,请在filter()stream()之间加map()

List<Person> result = lst.stream().filter(p -> p.name.startsWith( "P" )).map(p -> new Person( -1, p.name, p.address )).collect(Collectors.toList());