开发者

Language Tricks to Shorten My Java Code? [closed]

开发者 https://www.devze.com 2022-12-18 22:52 出处:网络
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references,or expertise, but this question will likely solicit debate, a
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance. Closed 11 years ago.

I am currently rediscovering Java (working with Ruby a lot recently), and I love the compilation-time checking of everything. It makes refactoring so easy. However, 开发者_Python百科I miss playing fast-and-loose with types to do an each loop. This is my worst code.

Is this as short as it can be? I have a collection called looperTracks, which has instances that implement Looper. I don't want to modify that collection, but I want to iterate through its members PLUS the this (which also implements Looper).

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks.length + 1);
for (LooperTrack track : looperTracks) {
    allLoopers.add(track);
}
allLoopers.add(this);

for (Looper looper : allLoopers) {
    // Finally! I have a looper

I'm particularly concerned about any features that are new to Java from 1.5 on that I may have missed. For this question I am not asking about JRuby nor Groovy, though I know that they would work for this.

Edit: Sorry (too much Ruby!)... looperTracks is of type LooperTrack[] and LooperTrack implements Looper.


You could at least use the fact that you can construct one collection using another as the base values. According to the docs:

Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator. The ArrayList instance has an initial capacity of 110% the size of the specified collection.

Which means that there is probably going to be room forthis without having to do any resizing.

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks);
allLoopers.add(this);

for (Looper looper : allLoopers) {
    // Finally! I have a looper


There are at least two possible built-in ways to shorten your code:

You could use Collection.addAll(Collection) that appends each element in the collection passed as parameter to the end of the collection.:

List<Looper> allLoopers = new ArrayList<Looper>();

...

allLoopers.addAll(looperTracks);
allLoopers.add(this);

for(Looper looper : allLoopers) {
  ...
}

or you can use a constructor that takes a collection as a parameter:

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks);

Due to the change of question: All arrays can easily be converted to collections using java.util.Arrays e.g.

List<Looper> someLooperTracks = Arrays.asList(looperTracks). 

This will wrap the array in a fixed-size list.


I don't think you can make it shorter than this...

for (Looper looper : new ArrayList<Looper>(looperTracks){{ add(EnclosingClass.this); }}) {
    // Finally! I have all loopers
}


Guava makes this pretty easy:

for (Looper looper : ObjectArrays.concat(looperTracks, this)) {}

Here is the documentation for the method ObjectArrays#concat.


I've just implemented an Iterator of Iterables (it is implemented in a more robust/tested/reviewed way by Guava Iterables.concat(Iterable...)):

// make a concatenation of iterables
public static <T> Iterable<T> $(final Iterable<T> first, final Iterable<T>... iterables) {
    List<Iterator<T>> allIterables = new LinkedList<Iterator<T>>();
    allIterables.add(first.iterator());

    for (Iterable<T> iterable : iterables) {
        allIterables.add(iterable.iterator());
    }

    final Iterator<Iterator<T>> iterators = allIterables.iterator();

    return new Iterable<T>() {

        @Override
        public Iterator<T> iterator() {
            return new Iterator<T>() {

                private Iterator<T> current = iterators.next();

                @Override
                public boolean hasNext() {
                    if (current.hasNext()) {
                        return true;
                    } else {
                        if (iterators.hasNext()) {
                            current = iterators.next();
                            return current.hasNext();
                        } else {
                            return false;
                        }
                    }
                }

                @Override
                public T next() {
                    return current.next();
                }

                @Override
                public void remove() {
                }
            };
        }
    };
}

using it your code becomes:

for (Looper looper : $($(looperTracks), this)) {

}

in the case you care the implementation is being part of my Dollar library (relesead as LGPL3).


Why can't you just add them all as part of the constructor call?

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks);

allLoopers.add(this);

for(Looper looper : allLoopers) {
...
}


Depending on typing, you could use:

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks);
allLoopers.add(this);

or:

List<Looper> allLoopers = new ArrayList<Looper>(looperTracks.length + 1);
allLoopers.addAll(looperTracks);
allLoopers.add(this);


In case you don't want to use Groovy or JRuby because of their dynamic nature, you should consider using Scala. Scala is statically typed but more concise than Java.


Is it a requirement that you assemble everything into one list? If not, what's wrong with this?

for (Looper looper : looperTracks) {
    doSomething(looper);
}
doSomething(this);


Try

Looper[] loop = new Looper[looperTracks.length + 1];
System.arraycopy(looperTracks, 0, loop, 0, looperTracks.length);
loop[looperTracks.length] = this;
for (Looper l : loop) { ... }

but honestly, why not just loop through the existing array, and then do whatever you want to do with the loop to this afterwards?

The List-version of the above looks like:

List<Looper> loop = new ArrayList<Looper>(Arrays.asList(looperTracks));
loop.add(this);
for (Looper l : loop) { ... }


You can try using an immutable list by using the nCopies() method. Quoting from the API reference,

public static <T> List<T> nCopies(int n, T o)

Returns an immutable list consisting of n copies of the specified object. The newly allocated data object is tiny (it contains a single reference to the data object). This method is useful in combination with the List.addAll method to grow lists. The returned list is serializable.

this will avoid the first foreach iteration.


I'm just going to throw this out there but don't try and make your code shorter at the expense of making it readable.

Readable code is always my aim when I start writing code, simply because I know that at some point in the future either myself or someone else is going to look at it and have to understand it.

0

精彩评论

暂无评论...
验证码 换一张
取 消