I wanted to filter list of Person class and finally map to some anonymous class in Java using Streams. I am able to do the same thing very easily in C#.
Person class
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Code to map the result in desire format.
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();
Now if I wanted to access any property of newly created type I can easily access by using below mentioned syntax.
Console.WriteLine( result[0].Address);
Ideally I should use loop to iterate over the result.
I know that in java we have collect for ToList and map for Select. But i am unable to select only two property of Person class. How can i do it Java
To convert temperatures in degrees Celsius to Fahrenheit, multiply by 1.8 (or 9/5) and add 32.
Celsius and Fahrenheit are two temperature scales. The Fahrenheit and Celsius scales have one point at which they intersect. They are equal at -40 °C and -40 °F.
Equal to operator: Represented as '==', the equal to operator checks whether the two given operands are equal or not. If so, it returns true. Otherwise, it returns false. For example, 5==5 will return true.
-= Subtract AND assignment operator. It subtracts the right operand from the left operand and assigns the result to the left operand. C -= A is equivalent to C = C - A.
Java does not have structural types. The closest you could map the values to, are instances of anonymous classes. But there are significant drawbacks. Starting with Java 16, using record
would be the better solution, even if it’s a named type and might be slightly more verbose.
E.g. assuming
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;
}
}
you can do
List<Person> lst = List.of(
new Person("Pava", "India", 1), new Person("tiwari", "USA", 2));
var result = lst.stream()
.map(p -> {
record NameAndAddress(String name, String address){}
return new NameAndAddress(p.getName(), p.getAddress());
})
.collect(Collectors.toList());
result.forEach(x -> System.out.println(x.name() + " " + x.address()));
The anonymous inner class alternative would look like
List<Person> lst = List.of(
new Person("Pava", "India", 1), new Person("tiwari", "USA", 2));
var result = lst.stream()
.map(p -> new Object(){ String address = p.getAddress(); String name = p.getName();})
.collect(Collectors.toList());
result.forEach(x -> System.out.println(x.name + " " + x.address));
but as you might note, it’s still not as concise as a structural type. Declaring the result
variable using var
is the only way to refer to the type we can not refer to by name. This requires Java 10 or newer and is limited to the method’s scope.
It’s also important to keep in mind that inner classes can create memory leaks due to capturing a reference to the surrounding this
. In the example, each object also captures the value of p
used for its initialization. The record
doesn’t have these problems and further, it automatically gets suitable equals
, hashCode
, and toString
implementations, which implies that printing the list like System.out.println(result);
or transferring it to a set like new HashSet<>(result)
will have meaningful results.
Also, it’s much easier to move the record
’s declaration to a broader scope.
Prior to Java 10, lambda expressions are the only Java feature that supports declaring variables of an implied type, which could be anonymous. E.g., the following would work even in Java 8:
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());
It seems that you want to transform
your Person
with 3 properties to a Holder that has 2 properties. And that is a simple map
operation:
lst.stream().map(p -> new AbstractMap.SimpleEntry(p.address, p.name))
.collect(Collectors.toList());
This is collecting your entries to SimpleEntry
that is just a Holder for two values. If you need more then two, you are out of luck - you will need to create your own holder(class).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With