Java 8 sort on Class member's property - java

Class declaration:
class Entity {
String name;
SubEntity subEntity; // subEntity has a method getAmount() which returns int
}
I understand with Java 8 we can sort like:
entities.sort(Comparator.comparing(Entity::name));
But is there a way I can sort it on sub-entities' properties, for eg:
entities.sort(Comparator.comparing(Entity::SubEntity::getAmount()));
P.S: All in for any one-liners.

Not by using a method reference, no - but it's easy to do with a lambda instead:
entities.sort(Comparator.comparing(entity -> entity.getSubEntity().getAmount()));
Fundamentally there's nothing magical about Comparator.comparing - it just accepts a Function<? super T,? extends U> keyExtractor parameter, so you need to work out some way of creating such a function. A method reference is one convenient way of creating a function, but a lambda expression is more flexible one.

Guys gave you good answers. It isn't supposed to be an improvement over their answers. I just want to provide an alternative idea.
entities.sort(Comparator.comparing(((Function<Entity, SubEntity>)Entity::getSubEntity).andThen(SubEntity::getAmount)));
I formed a key extractor by combining two functions Entity::getSubEntity and SubEntity::getAmount with Function#andThen. Both have been written as method references. The cast is required to determine the type of an instance and call andThen on that instance.

You can do that via a lambda as opposed to a method reference:
entities.sort(Comparator.comparing(x -> x.getSubEntity().getAmount())
If you you have indeed an int as you say in your comments, then use :
Comparator.comparingInt(...)

Related

How to use function interface, and use it as function argument?

I am not that good with function interface.
How to make Function<S, Set<S>> and how to send it as parameter?
public class Algorithms {
public static <S> Optional<Node<S>> search(S s0, Function<S, Set<S>> succ, Predicate<S> goal) {
.
.
.
return Optional.empty();
}
}
Any interface with exactly one non-default method is a functional interface, and Function meets that condition. That means you can implement it using a lambda expression. For example, let's say we're using this search function to search someone's family tree:
search(alice, (person) -> person.getChildren(), (person) -> person.getName().equals("Bob"));
The second argument, (person) -> person.getChildren(), creates a Function<Person, Set<Person>> that calls getChildren() on its argument. (We know it should accept a Person and return a Set<Person> from how we're passing it to search.) Likewise, the third argument creates a Predicate<Person> that checks if their name is "Bob".
Now, there are two "convenience" features I'm glossing over here. When the lambda only takes one argument (as is the case with both Function and Predicate), you can omit the parentheses around the name. Secondly, when a lambda only calls some method on its argument, you can use a method reference, which is just a more concise way of writing the lambda:
search(alice, Person::getChildren, person -> person.getName().equals("Bob"));
That's entirely equivalent, just more concise.
You can also implement functional interfaces the "old-school" way, i.e. by writing an (anonymous) class, but lambda syntax avoids a lot of boilerplate and is more readable. It's still fundamentally doing the same thing (and your IDE should be able to transform the one to the other, if that's helpful for you).

how to explain generics used in ImmutableList.builder().build() in guava?

I just saw this kind of code ImmutableList<String> list= ImmutableList.<String>builder().build();
which really confused me. How to understand the diamond after ImmutableList.?
Most parameterized types in java show up on a type. This looks like so:
interface List<T> {
void add(T elem);
}
So, any List type is parameterized, and as generics is really just a mechanism to link things, what it links is that a List<String> has an add method that takes String objects, and a get(int) method that returns a String, etc.
But, methods themselves may also want this linking behaviour. For example, let's say I want to make a method that takes 2 arguments of the same type, and returns the first non-null one. Here too I want to link things: The types of the 2 argument, and the return type? All the same thing, caller's choice as to what it might be.
Java supports this: Methods can ALSO have generics:
public <T> T firstNonNull(T a, T b) {
return a == null ? b : a;
}
is valid java, and you can call it:
String a = firstNonNull("hello", "world!");
Compiles without requiring a cast.
Java will infer generics if it can; it does that in my previous example (the two arguments are both strings; java infers you meant T to be String there). But you can, if you want, be explicit about it. This is where this funky syntax comes in:
Number a = ClassContainingFNN.<Number>firstNonNull(null, null);
You need the dot to use this syntax, hence why I had to make the call a little longer. With the ImmutableList builder method, java can't (easily) infer what type you wanted, as the call to builder() itself doesn't let the compiler know that you're attempting to build a list of, say, strings. That's why forcing it by explicitly telling java what you want the type param to be is useful, thus, why the usual way to call this builder is:
ImmutableList.<String>builder().add(aString).add(anotherString).build();
Java will always try to infer something if you don't explicitly pick something, but it would just infer Object here. Unless you wanted a list of objects, you need the 'forcibly pick a type' option.
See java support jls-15.12 for supporting TypeArguments after entering Type.
MethodInvocation:
MethodName ( [ArgumentList] )
TypeName . [TypeArguments] Identifier ( [ArgumentList] )
The builder is generic method
public static <E> Builder<E> builder()
And because it's static you entered before method name the type using diamond operator
In case of new instance it'll be as you expected:
new ImmutableList.Builder<Color>()

Why is there no Instance-level Stream.concat method in Java?

I know that Stream.concat exists (doc) to concatenate two streams. However, I have run into cases where I need to add "a few more" items to an existing stream, and then continue processing on it. In such a situation, I would have expected to be able to chain together methods like:
getStream(someArg)
.map(Arg::getFoo)
.concat(someOtherStreamOfFoos) // Or append, or...
.map(...)
However, no such instance-level chainable append/concat method exists.
This isn't a question asking for solutions to this problem, or more elegant approaches (although I would of course be grateful for any other viewpoints!). Rather, I'm asking about the design factors that led to this decision. The Stream interface was, I trust, designed by some extremely smart people who are aware of the Principle of Least Astonishment - so, I must assume that their decision to omit this (to me) intuitively-obvious method signifies either that the method is an antipattern, or that it is not possible due to some technical limitation. I'd love to know the reason.
I can give you one reason it wouldn't have worked.
Stream.concat is defined as
static <T> Stream<T> concat(Stream<? extends T> a,
Stream<? extends T> b)
You can concat a Stream<HashMap> and Stream<Map> into a Stream<Map>, or even concat a Stream<HashMap> and a Stream<TreeMap> into a Stream<Map>. To do that with an instance method, you would need to be able to declare a type parameter like <U super T>, which Java doesn't allow.
// It'd look kind of like this, if Java allowed it.
public <U super T> Stream<U> concat(Stream<? extends U> other)
Java only allows upper-bounded type parameters, not lower-bounded.
Concatenating a Stream<Something> and a Stream<SomethingElse> might seem unusual, but type inference often produces type parameters too specific to work with an instance method. For example,
Stream.concat(Stream.of(dog), animalStream)
which would require an explicit type parameter if written as
Stream.<Animal>of(dog).concat(animalStream)
I think it is just missed functionality of Stream API.
Note that RxJava's Observable has method "concatWith" with required functionality, so your question is reasonable:
Observable<String> o1 = ...;
Observable<Integer> o2 = ...;
o1.map(s -> s.length())
.concatWith(o2)
....
Java 8 has another functionality is nice to have is get another Optional if current Optional is empty, like:
Optional.ofNullable(x).orElse(anotherOptional)
What I want to say that this concat you described is possible, just not implemented in the Stream.

How can I avoid using an interface in java 8?

I just want to know if its possible to avoid the use of an interface in this code
public interface FunctionT<T,R> {
R apply(Integer...args);
}
public static FunctionT sum = (params) -> Arrays.asList(params)
.stream()
.reduce(Integer::sum).get();
The type of a lambda expression in Java is a functional interface. This means that the lambda must be provided with a target type that is a functional interface. This could be yours (FunctionT) or a standard one like java.util.function.Function.
Put another way, function types in Java are nominal, not structural.
(Also, you don't want to blindly call get() on an Optional, you want to use one of the safe methods like orElse() or ifPresent(). Otherwise you lose all the safety of using Optional in the first place.)

Does Google Collections API have an equivalent of the Ruby Enumerable#inject method?

I read through the javadoc and couldn't find anything that resembles it.
No, it does not.
While it does have certain functional programming elements (Predicate, Function), those were to support specific needs and its core focus is not adding functional programming elements for Java (seeing as how it's terribly verbose currently). See this issue for a bit on that.
I think that you don't have a exact inject method.. but you can obtain a similar solution by using the transformValues methods supplied
Maps.transformValues(Map<K,V1> fromMap, Function<? super V1,V2> function)
List.transform(List<F> fromList, Function<? super F,? extends T> function)
Of course you'll need a Function class defined ad hoc to work with the passed parameter of the inject:
class MyFunction<Type, Type>
{
static String variable;
Type apply(Type t)
{
//do whatever you want with t
// and storing intermediate result to variable
// return same t to make this function work like identity
return t;
}
}

Categories

Resources