Java 8 and above:
List<String> namesList = personList.stream()
.map(Person::getName)
.collect(Collectors.toList());
In Java 16+ you can end it with .toList()
If you need to make sure you get an ArrayList as a result, you have to change the last line to:
...
.collect(Collectors.toCollection(ArrayList::new));
Java 7 and below:
The standard collection API prior to Java 8 has no support for such transformation. You'll have to write a loop (or wrap it in some "map" function of your own), unless you turn to some fancier collection API / extension.
(The lines in your Java snippet are exactly the lines I would use.)
In Apache Commons, you could use CollectionUtils.collect and a Transformer
In Guava, you could use the Lists.transform method.
Java 8 and above:
List<String> namesList = personList.stream()
.map(Person::getName)
.collect(Collectors.toList());
In Java 16+ you can end it with .toList()
If you need to make sure you get an ArrayList as a result, you have to change the last line to:
...
.collect(Collectors.toCollection(ArrayList::new));
Java 7 and below:
The standard collection API prior to Java 8 has no support for such transformation. You'll have to write a loop (or wrap it in some "map" function of your own), unless you turn to some fancier collection API / extension.
(The lines in your Java snippet are exactly the lines I would use.)
In Apache Commons, you could use CollectionUtils.collect and a Transformer
In Guava, you could use the Lists.transform method.
You might have done this but for others
using Java 1.8
List<String> namesList = personList.stream().map(p -> p.getName()).collect(Collectors.toList());
When I have encountered this type of problem, it typically involves creating some ugly code in your method to do that iteration. In essense, there is no way to do things any differently, you have to iterate, and collect the UUID's (but, you could wait for Java8 and do lambdas ..).
But, there is no reason why you have to do it outside of the Something class. A trick you can do which keeps like-code together, is to put a static method on Something, which does:
public static final List<UUID> getUUIDs(Iterable<Something> somethings) {
List<UUID> ids = new ArrayList<UUID>();
for(Something thing : somethings) {
ids.add(thing.getId());
}
return ids;
}
Now that code is stashed away somewhere useful, and when you need it you can:
for (UUID uuid : Something.getUUIDs(things) {
... do something ....
}
You can do it with Guava's Function and Lists (Functional idioms in Guava, explained):
Function<Something, UUID> getIdFunction = new Function<Something, UUID>() {
public UUID apply(Something input) {
return input.getId();
}
};
List<UUID> ids2 = Lists.transform(things, getIdFunction);
(If you're unable to include a 3rd party library to your project for any reason you still can copy the code of relevant classes or create your own implementation with the same pattern.)
Try this:
Collection<String> names = CollectionUtils.collect(personList, TransformerUtils.invokerTransformer("getName"));
Use apache commons collection api.
You'll have to iterate through your List<Obj> and collate the foo entries into a new List
e.g.
List<String> foos = new ArrayList<String>();
for (Obj obj : objs) {
foos.add(obj.foo)
}
or for Java 8 and beyond, use streams thus:
objs.stream().map(o -> o.foo).collect(toList());
If the fields don't change for the objects while they're in your list, you can use a map of collections (or lists or sets, depending on what you need) to facilitate this comparison:
Map<Field, List<Class2>> map = new HashMap<>();
To insert:
Class2 c = new Class2();
List<Class2> bucket = map.get(c.fieldY);
if( null == bucket ){
bucket = new ArrayList<>();
map.put( c.fieldY, bucket );
}
bucket.add( c );
To look up:
List<Class2> result = map.get( a.fieldX );
This only works if the fields don't change while the objects are in the map of lists, and it only makes sense to do if you are making these lookups a lot.
It is not possible to do this in a list without some form of iteration, but if you change to a mapping you can get around that with the following code:
Map<FieldYType, Class2> B= new HashMap();
B.put(c.fieldY, C);
Class2 D = B.get(A.fieldX);
D==C;//true
D.fieldY==A.fieldX;//true
So here you dont iterate at all, you just use a single get function. You also might want to use a different map type, but thats up to you and your code design.
I know this is a year old question, but I think it can be useful for others.
I have found a partial solution using this LOC
Field [] attributes = MyBeanClass.class.getDeclaredFields();
Here is a working example:
import java.lang.reflect.Field;
import org.apache.commons.beanutils.PropertyUtils;
public class ObjectWithSomeProperties {
private String firstProperty;
private String secondProperty;
public String getFirstProperty() {
return firstProperty;
}
public void setFirstProperty(String firstProperty) {
this.firstProperty = firstProperty;
}
public String getSecondProperty() {
return secondProperty;
}
public void setSecondProperty(String secondProperty) {
this.secondProperty = secondProperty;
}
public static void main(String[] args) {
ObjectWithSomeProperties object = new ObjectWithSomeProperties();
// Load all fields in the class (private included)
Field [] attributes = object.getClass().getDeclaredFields();
for (Field field : attributes) {
// Dynamically read Attribute Name
System.out.println("ATTRIBUTE NAME: " + field.getName());
try {
// Dynamically set Attribute Value
PropertyUtils.setSimpleProperty(object, field.getName(), "A VALUE");
System.out.println("ATTRIBUTE VALUE: " + PropertyUtils.getSimpleProperty(object, field.getName()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Have you tried ReflectionToStringBuilder? It looks like is should do what you describe.
Why don't you return the whole Place object ?
places.stream().min(Comparator.comparing(Place::getPrice)).get()
Firstly, it's really unclear what you want as at first, you seem to say that
I have a list of locations returned by Google places API and decided to find a Place with a lowest price.
then at the bottom of your description, you say that:
It returns me the lowest price but it'll be great to get a name of the Place as well (it has a name attribute).
as if the latter seems to be what you want?
Nevertheless, here are both solutions:
if you want to find the min value by the count after grouping for whatever reason that may be... then you could do something along the lines of:
places.stream()
.collect(Collectors.groupingBy(Place::getPrice))
.entrySet().stream()
.min(Comparator.comparingInt((Map.Entry<Integer, List<Place>> e) -> e.getValue().size()))
.map(e -> new SimpleEntry<>(e.getKey(), e.get(0)));
note that above i've used Integer as the entry key, feel free to change this to the appropriate type if it's not an Integer.
Otherwise, if you're simply after the object with the lowest price then you can do:
places.stream().min(Comparator.comparingInt(Place::getPrice));
or:
Collections.min(places, Comparator.comparingInt(Place::getPrice));
There's no need for grouping and all the stuff going on.
Your way looks fine. You can write it with less lines of code if you use Java 8 Streams, but that would require 4 iterations over the cards list instead of the single iteration you currently have.
For example, to create the list of counts, you can write :
List<Integer> counts = cards.stream().map(Card::getCount).collect(Collectors.toList());
If you are developing a set game, here is a solution for checking and completing card sets:
Card.java:
import java.util.Locale;
public final class Card {
public static void main(String[] args) {
Card a = new Card(Count.ONE, Color.RED, Fill.STRIPED, Shape.DIAMOND);
Card b = new Card(Count.TWO, Color.RED, Fill.SOLID, Shape.DIAMOND);
Card c = completeSet(a, b);
System.out.println(c);
}
public int count;
public int color;
public int fill;
public int shape;
public Card() {
}
public Card(Count count, Color color, Fill fill, Shape shape) {
setCount(count);
setColor(color);
setFill(fill);
setShape(shape);
}
// getters and setters to operate with the attribute enumerations
public Count getCount() {
return Count.values()[count];
}
public Color getColor() {
return Color.values()[color];
}
public Shape getShape() {
return Shape.values()[shape];
}
public Fill getFill() {
return Fill.values()[fill];
}
public void setCount(Count count) {
this.count = count.ordinal();
}
public void setColor(Color color) {
this.color = color.ordinal();
}
public void setShape(Shape shape) {
this.shape = shape.ordinal();
}
public void setFill(Fill fill) {
this.fill = fill.ordinal();
}
public static int completeAttribute(int a, int b) {
if (a == b) {
// attribute for each same
return a;
} else {
// attribute for each different
int c;
for (c = 0; c < 3; c++) {
if (c != a && c != b) {
break;
}
}
return c;
}
}
public static Card completeSet(Card a, Card b) {
// determine missing card to make a set
Card result = new Card();
result.count = completeAttribute(a.count, b.count);
result.color = completeAttribute(a.color, b.color);
result.shape = completeAttribute(a.shape, b.shape);
result.fill = completeAttribute(a.fill, b.fill);
return result;
}
public static boolean isSet(Card a, Card b, Card c) {
// check if it is a set by completing it
return completeSet(a, b).equals(c);
}
@Override
public boolean equals(Object that) {
// currently unused
if (this == that) {
return true;
}
return that != null && that instanceof Card && this.equals((Card) that);
}
public boolean equals(Card that) {
if (this == that) {
return true;
}
return that != null
&& this.color == that.color
&& this.count == that.count
&& this.fill == that.fill
&& this.shape == that.shape;
}
@Override
public int hashCode() {
// currently unused
int result = count;
result = 31 * result + color;
result = 31 * result + shape;
result = 31 * result + fill;
return result;
}
@Override
public String toString() {
// pretty print attributes
String result = getCount() + " " + getColor() + " " + getFill() + " " + getShape();
result = result.toLowerCase(Locale.ROOT);
if(getCount() != Count.ONE) {
result += "s";
}
return result;
}
// enumerations for pretty names
public enum Count {
ONE,
TWO,
THREE
}
public enum Color {
RED,
GREEN,
VIOLET
}
public enum Shape {
ELLIPSE,
DIAMOND,
TWIRL
}
public enum Fill {
OPEN,
STRIPED,
SOLID
}
}
Output: three red open diamonds
If you are using Java 8, you can do:
private String[] getFields() {
Class<? extends Component> componentClass = getClass();
Field[] fields = componentClass.getFields();
List<String> lines = new ArrayList<>(fields.length);
Arrays.stream(fields).forEach(field -> {
field.setAccessible(true);
try {
lines.add(field.getName() + " = " + field.get(this));
} catch (final IllegalAccessException e) {
lines.add(field.getName() + " > " + e.getClass().getSimpleName());
}
});
return lines.toArray(new String[lines.size()]);
}
or to improve formatting:
private String[] getFields() {
Class<? extends Component> componentClass = getClass();
Field[] fields = componentClass.getFields();
List<String> lines = new ArrayList<>(fields.length);
Arrays.stream(fields)
.forEach(
field -> {
field.setAccessible(true);
try {
lines.add(field.getName() + " = " + field.get(this));
} catch (final IllegalAccessException e) {
lines.add(field.getName() + " > "
+ e.getClass().getSimpleName());
}
});
return lines.toArray(new String[lines.size()]);
}
Note that this is adding to @EricStein's excellent answer on normal concatenation instead of StringBuilders.
(I'm just starting to look into Streams, so if this is bad, please comment on why)
Otherwise...
Just a small comment:
lineBuilder.append(" = "); lineBuilder.append(value);
can easily be:
lineBuilder.append(" = ").append(value);
Same with:
lineBuilder.append(" > "); lineBuilder.append(e.getClass().getSimpleName());
becomes:
lineBuilder.append(" > ").append(e.getClass().getSimpleName());
Also, I would use a simple array instead of an ArrayList:
private String[] getFields() {
Class<? extends Component> componentClass = getClass();
Field[] fields = componentClass.getFields();
String[] lines = new String[fields.length];
int index = 0;
for (Field field : fields) {
StringBuilder lineBuilder = new StringBuilder();
lineBuilder.append(field.getName());
field.setAccessible(true);
try {
Object value = field.get(this);
lineBuilder.append(" = ");
lineBuilder.append(value);
} catch (IllegalAccessException e) {
lineBuilder.append(" > ");
lineBuilder.append(e.getClass().getSimpleName());
}
lines[index++] = lineBuilder.toString();
}
return lines;
}
EDIT: The above review, if not using Java 8, should be replaced by @EricStein's code.
Also, getFields() is a bad name. Try getFieldDescriptions().
For getFields(), String concatenation is a not-unreasonable alternative you can consider. For toString(), using delete() is probably easier to read than the conditional check, there's probably no real performance gain due to branch prediction. It is distinctly wrong to merge the two methods. getFields() is probably not the best name, since it doesn't actually return the fields. Good names are hard, and nothing is jumping immediately to mind.
public abstract class Component {
private String[] getFields() {
final List<String> lines = new ArrayList<>();
for (final Field field: this.getClass().getFields()) {
field.setAccessible(true);
try {
lines.add(field.getName() + " = " + field.get(this));
} catch (final IllegalAccessException e) {
lines.add(field.getName() + " > " + e.getClass().getSimpleName());
}
}
return lines.toArray(new String[lines.size()]);
}
@Override
public final String toString() {
final StringBuilder builder = new StringBuilder(this.getClass().getSimpleName());
builder.append('(');
for (final String field : this.getFields()) {
builder.append(field);
builder.append(", ");
}
builder.delete(builder.length() - 2, builder.length());
builder.append(')');
return builder.toString();
}
}