Devolver lista ordenada en Java

I am coding something like this:

List<Bean> beans = service.findBeans();
Collections.sort(beans, new BeanComparator());
return beans;

It works perfectly. What I am looking for is a shortcut to do this with just one line:

return somelibrary.Collections.sort(service.findBeans(), new BeanComparator());

o:

return somelibrary.newList(service.findBeans(), new BeanComparator());

Note that it is required a mutable list.

preguntado el 22 de mayo de 12 a las 20:05

what is wrong with the original? -

What is the purpose of the library if it's just doing the exact same thing that Collections.sort already provides? -

Your original code looks great. Why change it? Three lines is better than one in my opinion. Why do people think it's better to jam a bunch of code into one line? Leave it as is and enjoy the readability! -

It is java, the most things need more than one line. -

@Marko The real problem here isn't that one version is longer than the other, or that we'd have to add another dependency. If the proposed API was well designed and made sense, I'd be the first that would want it added to the standard API (though there's a long list of really sensible, good functions the collections API is badly missing). The real problem is that an in-place sort no debe return its input parameter, because that would make for a bad API design. Most people would expect a sort that returns a Collection, to return a sorted copia of the input parameter. -

6 Respuestas

This is one line:

List<Bean> beans = service.findBeans(); Collections.sort(beans, new BeanComparator()); return beans;

But more seriously, Java isn't really the right language for one-liners. Also, just because something is a one-liner doesn't mean that it is any better. For example, I was initially surprised to discover that this:

return condition ? a : b;

Creates a longer bytecode than

if( condition )
    return a;
else
    return b;

But that's just how the language and compiler are.

If you insist on your one-liner, Guayaba's Ordering lo puede hacer:

return Ordering.from( new BeanComparator() ).sortedCopy( service.findBeans() );

The returned list is modifiable, serializable, and has random access.

Efficiency-wise I think there's a bit of a waste in terms of overhead. And also you're now dependent on a 3rd-party library. You'd be essentially using very powerful tools for a very simple task. It's overkill if this is all you're using it for.

contestado el 22 de mayo de 12 a las 22:05

@thereality And there's such a thing as perl ;) I don't think the first version is especially cluttered. A sort version that sorts in-place but returns a reference to the input parameter would imo be badly designed, because most people would expect a sorted copy to be returned from such an API and the input parameter be unchanged. Python - a language that usually keeps quite a good balance between short and readable (much more so than java) - would look pretty much identical for the given problem. - Voo

@trutheality - true... I guess my statement was a little broad. Just trying to get a point across to those who like to write long, hard to read lines of code ;) - jahroy

@trutheality Thanks for the critics and for the Guava option. - falsarella

I believe the following function will yield the results you want. Just put it in the class of your choice.

public static <T> List<T> sort(List<T> list, Comparator<? super T> compare) {
    Collections.sort(list, compare);
    return list;
}

contestado el 23 de mayo de 12 a las 17:05

You could use apache CollectionUtils to collate the list with a comparator and an empty list.

CollectionUtils.collate(service.findBeans().iterator(),Collections.EMPTY_LIST.iterator(),new beanComparator())

CollectionUtils really should add a utility method that returns the sorted list...

Classic rebut to use-more-lines is LOGGING. You logging for readability purposes should not take up more than one line. Logging is static noise when you're trying to find out what code is actually doing, yet logging is fairly critical.

So logging should be compact (in one line) and quiet (should not throw exceptions/be nullsafe) and should be performant (if turned off should not introduce excess processing beyond isDebugOn() check.

Second rebut is fluent interfaces such as JOOQ which are becoming much more prevalent.

Respondido el 29 de diciembre de 14 a las 19:12

I guess if you have no duplicates and don't mind hacky code you could use:

return new ArrayList<Bean>(new TreeSet<Bean>(service.findBeans()));

Respondido 10 Abr '13, 23:04

Unfortunately, this approach uses the natural ordering to sort, not allowing us to use a custom Comparator. - falsarella

I think the original question posted is valid. Because the "Collections.sort(..)" method has the intended side-effect of sorting the passed-in Collection, if you wanted to maintain your original Collection, you'd have to do the following:

List<Bean> beans = service.findBeans();
List<Bean> sortedBeans = new ArrayList<Bean>(beans);
Collections.sort(sortedBeans, new BeanComparator());
return sortedBeans;

In the case above, it's probably not that big a deal that we sort the Collection returned by a service method. But, what if the Collection we are sorting was a method parameter, and the caller did not want the Collection passed-in sorted?

I usually prefer to have methods without consequences.

Since "Collections.sort(..)" affects the list, I have to write the following code:

public void doSomethingWithBeansInOrder(List<Bean> beans) {
    Collection<Bean> sortedBeans = new ArrayList<Bean>(beans);
    Collections.sort(sortedBeans, ...comparator...;

    for (Bean bean : sortedBeans) {
        .. do something
    }
}

I find the definition of "sortedBeans" ugly.

If "(Collections.sort(..)" (or something like it), returned a new Collection and did not affect the passed-in Collection, I could write:

public void doSomethingWithBeansInOrder(List<Bean> beans) {
    for (Bean bean : Collections.sort(beans, ...comparator...) {
        .. do something
    }
}

La respuesta para Guayaba's Ordering is best, in my opinion.

contestado el 02 de mayo de 14 a las 17:05

To start with, Java 8 introduced the ordenar() metod on the List interface. So, an example of sorting the actual list would be:

List<Integer> integerList = Arrays.asList(3, 2, 1);
integerList.sort(Comparator.naturalOrder());
return integerList;

Here, I used the pre-defined naturalOrder() comparator, which in turn relies on Comparable, but a custom comparator can also be used. This still requires two statements.

However, if the desired behaviour is to create a new sorted list, and leave the orignial as it was before, I guess a stream would be the easiest way to do it:

integerList.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());

The same thing as above applies to the comparator here.

Respondido el 08 de diciembre de 16 a las 07:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.