Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Carbon dioxide
Oct 9, 2012

What is the best way to optimize the following bit of code in Java 8?

code:
void method(List<Long> selectedFooIds, List<Foo> allowedFoos) {

   List<Long> allowedIds;
   for (Foo allowed : allowedFoos) {
      allowedIds.add(allowed.getId());
   }

   for (Long selectedId: selectedFooIds) {
      if (allowedIds.contains(selectedId)) {
         doSomethingImportant(selectedId);
      }
   }
}
The selectedFooIds is a list that comes directly from user input, and I expect it will usually contain only a few items, while the allowedFoos is a much larger list. I want to use doSomethingImportant with every selectedId that is an id of an allowedFoo.

Carbon dioxide fucked around with this message at 18:45 on Mar 3, 2016

Adbot
ADBOT LOVES YOU

sunaurus
Feb 13, 2012

Oh great, another bookah.
code:
void method(List<Long> selectedFooIds, List<Foo> allowedFoos) {
   List<Long> allowedIds = allowedFoos.stream().map(Foo::getId).collect(Collectors.toList());
   selectedFooIds.stream().filter(id -> allowedIds.contains(id)).forEach(id -> doSomethingImportant(id));
}
Something like this?

Sedro
Dec 31, 2008
You probably want allowedIds to be a Set

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.
Hm, if you're really sure selectedFooIDs is the smaller of the two, then that's pretty good already. I agree with Sedro that you should make allowedIDs a set because they're unique, no need to have duplicates or check for duplicates. Not a huge optimization if the lists don't have duplicates but if they do it helps, and it doesn't hurt if they don't.

Well, you could use a hashset to make it faster so you don't have to iterate the set when you call contains().

https://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html

code:
void method(List<Long> selectedFooIds, List<Foo> allowedFoos) {

   HashSet<Long> allowedIds = new HashSet<Long>();
   for (Foo allowed : allowedFoos) {
      allowedIds.add(allowed.getId());
   }

   for (Long selectedId: selectedFooIds) {
      if (allowedIds.contains(selectedId)) {
         doSomethingImportant(selectedId);
      }
   }
}
Like that. Everything else stays the same because they're both collections. Should be quicker.

Illegal Move posted:

code:
void method(List<Long> selectedFooIds, List<Foo> allowedFoos) {
   List<Long> allowedIds = allowedFoos.stream().map(Foo::getId).collect(Collectors.toList());
   selectedFooIds.stream().filter(id -> allowedIds.contains(id)).forEach(id -> doSomethingImportant(id));
}
Something like this?

Is this actually more efficient or is it just shorter code? I feel like its gotta be doing the same O(n^2) operation either way.

Zaphod42 fucked around with this message at 19:25 on Mar 3, 2016

sunaurus
Feb 13, 2012

Oh great, another bookah.

Zaphod42 posted:

Is this actually more efficient or is it just shorter code? I feel like its gotta be doing the same O(n^2) operation either way.

It's not more efficient (as far as I know), I just assumed that he meant shorter code because he said "Java 8", but now that I've reread his post, I think I may have been wrong!

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

Both of those look right to me depending on what you want to optimize :v:. Is that code particularly slow or do you just imagine it might be?

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Wouldn't it be even more fun to do

Java code:
void method(List<Long> selectedFooIds, List<Foo> allowedFoos) {

   HashSet<Long> allowedIds = new HashSet<Long>();
   for (Foo allowed : allowedFoos) {
      allowedIds.add(allowed.getId());
   }

   allowedIds.retainAll(selectedFooIds);

   for (Long id: allowedIds) {
      doSomethingImportant(id);
   }
}
I don't know if it's actually more efficient (I guess it depends on how much stuff you're working with?), but if I had to guess I'd assume Collection operations like retainAll are pretty well optimised. Specifying the set size might help too

I just like all the neat collections wrangling functions :shobon:

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

baka kaba posted:

Wouldn't it be even more fun to do

Java code:
void method(List<Long> selectedFooIds, List<Foo> allowedFoos) {

   HashSet<Long> allowedIds = new HashSet<Long>();
   for (Foo allowed : allowedFoos) {
      allowedIds.add(allowed.getId());
   }

   allowedIds.retainAll(selectedFooIds);

   for (Long id: allowedIds) {
      doSomethingImportant(id);
   }
}
I don't know if it's actually more efficient (I guess it depends on how much stuff you're working with?), but if I had to guess I'd assume Collection operations like retainAll are pretty well optimised. Specifying the set size might help too

I just like all the neat collections wrangling functions :shobon:

Oh, for some reason I thought he was calling doSomethingImportant(Foo) on the foo objects, but if that just needs the long ID then yeah, that works great.

And even if it doesn't you could probably put them in a HashMap<Long, Foo> and then use the keyset with retainAll() and then pull the relevant entries from the HashMap... :cheeky:

Carbon dioxide
Oct 9, 2012

Streams have some API magic going on where they parallel process things as much as possible. A stream method doesn't need to wait for the previous method to have finished. So if you have Stream.filter(whatever).map(whatever) it will somehow combine those methods to give a really fast result.

I guess that doesn't really matter in this case, but I'm trying to get the hang of Java 8, and I thought this bit of code I was dealing with could be replaced by some smart use of Streams.

Using a HashSet is also a good idea, though.

Sedro
Dec 31, 2008

Zaphod42 posted:

Hm, if you're really sure selectedFooIDs is the smaller of the two, then that's pretty good already. I agree with Sedro that you should make allowedIDs a set because they're unique, no need to have duplicates or check for duplicates. Not a huge optimization if the lists don't have duplicates but if they do it helps, and it doesn't hurt if they don't.

Well, you could use a hashset to make it faster so you don't have to iterate the set when you call contains().
I hope there's not a set implementation with a linear time contains. Whether there's duplicates or not doesn't matter in this instance, because we're dealing with Long and not a custom type.


baka kaba posted:

Wouldn't it be even more fun to do

Java code:
void method(List<Long> selectedFooIds, List<Foo> allowedFoos) {

   HashSet<Long> allowedIds = new HashSet<Long>();
   for (Foo allowed : allowedFoos) {
      allowedIds.add(allowed.getId());
   }

   allowedIds.retainAll(selectedFooIds);

   for (Long id: allowedIds) {
      doSomethingImportant(id);
   }
}
I don't know if it's actually more efficient (I guess it depends on how much stuff you're working with?), but if I had to guess I'd assume Collection operations like retainAll are pretty well optimised. Specifying the set size might help too

I just like all the neat collections wrangling functions :shobon:
You've changed the behavior because you will doSomethingImportant in an arbitrary order now

Sedro fucked around with this message at 19:56 on Mar 3, 2016

Carbon dioxide
Oct 9, 2012

I suppose HashSet.retainAll() is also faster than List.retainAll()?

Loezi
Dec 18, 2012

Never buy the cheap stuff

Carbon dioxide posted:

What is the best way to optimize the following bit of code in Java 8?

Depending on what doSomethingImportant(id) is, you could also use parallelStream() to do something like this:

Java code:
        selectedFooIds
                .parallelStream()
                .filter(selectedId ->  allowedFoos
                            .parallelStream()
                            .anyMatch(
                                    allowedFoo -> 
                                            allowedFoo.getId() == selectedId
                            )
                ).forEach(
                        selectedAllowedId -> doSomethingImportant(selectedAllowedId)
                );
Would have to profile it, but it could run a bit faster since it can do stuff in parallel. But this won't be possible in all cases.

E: And yeah, use sets if possible. They should be faster for non-trivial sizes.

Loezi fucked around with this message at 20:12 on Mar 3, 2016

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Sedro posted:

You've changed the behavior because you will doSomethingImportant in an arbitrary order now

That's true, if it's important! You could copy the list and do a retainAll on that, if one-off filtering is more efficient

I should have spotted that though, I was blinded by the Collections goodness

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.
Doing it in parallel is technically the exact same big-O runtime and amount of instructions executed. Its equally as efficient, although on a multi-core processor it would be 'faster' yeah. Depends upon what you mean by optimize.

In general though, don't forget: Pre-mature optimization is the devil! Don't worry about efficiency too much (beyond "don't do really stupid wasteful operations if there's a clear alternative) unless you're sure this is a bottleneck.

http://c2.com/cgi/wiki?PrematureOptimization

E: Also doing it parallel means that method you're calling has to be thread-safe now.

Zaphod42 fucked around with this message at 21:15 on Mar 3, 2016

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Carbon dioxide posted:

I suppose HashSet.retainAll() is also faster than List.retainAll()?

They both basically iterate over their contents and call contains(element) on the collection you pass in to retain from, so I'd expect the type of passed collection to matter more. ArrayList.contains() iterates over every element until it finds one that matches, HashSet.contains() uses hashing for faster access. Benchmarking would be the way to go though, if it's important!

HFX
Nov 29, 2004

baka kaba posted:

They both basically iterate over their contents and call contains(element) on the collection you pass in to retain from, so I'd expect the type of passed collection to matter more. ArrayList.contains() iterates over every element until it finds one that matches, HashSet.contains() uses hashing for faster access. Benchmarking would be the way to go though, if it's important!

To give a bit more in depth explanation, the operation originally as originally written is the intersection of two sets. As noted by baka kaba, the retainAll in the case of a general list structure is an n^2 operation. However, by using a set optimized structure like a HashSet, the operation becomes an n operation. If order is a concern, consider a TreeSet which provides in order operation.

M31
Jun 12, 2012
If order is not important it might also be faster to create a set of the selected ids instead and loop over the allowed ids.

code:
void method(List<Long> selectedFooIds, List<Foo> allowedFoos) {
    Set<Long> selected = new HashSet<>(selectedFooIds);
    allowedFoos.stream()
            .map(Foo::getId)
            .filter(selected::contains)
            .forEach(this::doSomethingImportant);
}

casual poster
Jun 29, 2009

So casual.
Why the heck does this keep giving me a "OutOfMemoryError: Java heap space" error? Reading stuff online doesn't really help.

code:

package wordinspection;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

public class WordInspection {
    private File file;
    private Scanner reader;
    private ArrayList<String> list;
    
    
    public WordInspection(File file) throws Exception{
        this.file = file;
        this.list = new ArrayList<String>();
         this.reader = new Scanner(this.file);
        
        
        while (this.reader.hasNextLine()){
            String line = this.reader.nextLine();
            this.list.add(line);
        }
    }
    
    public int wordCount() {
       
        
        return this.list.size();
    }

    
    public List<String> wordsContainingZ(){
        List<String> z = new ArrayList<String>();
       
        for (String string: this.list){
            while (string.indexOf('z')>= 0){
                z.add(string);
                
            }
        }
        return z;
    }
}

It happens in the wordsContainingZ method. I really can't figure it out.

EDIT: I'm an idiot. You can all laugh at me. It's because I used while instead of an if.

speng31b
May 8, 2010

Java has immutable strings and the variable isnt getting reassigned, take a second to think about this:

code:
while (string.indexOf('z')>= 0){
                z.add(string);
                
            }

CPColin
Sep 9, 2003

Big ol' smile.
Now I'm laughing at you, instead!

speng31b
May 8, 2010

Why? Was the problem unclear?

CPColin
Sep 9, 2003

Big ol' smile.
Casual poster had already edited in the answer by the time you replied.

casual poster
Jun 29, 2009

So casual.
I appreciated the response anyways!

What I don't get was why this was different than before. In the past I would of just created an infinite loop but this time I ran out of memory?

Kuule hain nussivan
Nov 27, 2008

casual poster posted:

I appreciated the response anyways!

What I don't get was why this was different than before. In the past I would of just created an infinite loop but this time I ran out of memory?

It keeps adding the string to z, which grows infinitely large, causing you to run out of memory. Your previous loops probably just caused int overflows or something like it, which doesn't stop execution.

casual poster
Jun 29, 2009

So casual.
ah ok, that makes sense. Thanks.

Boz0r
Sep 7, 2006
The Rocketship in action.
If a class is defined inside a method, will it waste time on runtime defining the class every time the method is run?

speng31b
May 8, 2010

Not much more overhead than regular object allocation. I'd worry more about the implicit strong reference to the outer class that the inner class keeps, and potentially leaking stuff that way.

speng31b fucked around with this message at 14:20 on Mar 11, 2016

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

Boz0r posted:

If a class is defined inside a method, will it waste time on runtime defining the class every time the method is run?

To clarify, the compiler will generate the class definition at compile time, along with synthetic accessors etc. If you take a look at the generated classes, you'll find something like YourClass$1, YourClass$2, etc for the anonymous inner methods of your class.

So, you'll pay the instancing penalty of any object, but otherwise there's no real cost.

22 Eargesplitten
Oct 10, 2010



Is the Eclipse refactoring tool worth using on a small project? About a thousand lines total. I figure if I'm going to use JUnit, I may as well run the refactoring so I have something to automatically test.

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

What refactoring are you looking to do? I mean, as long as you have a snapshot from before you run the tool it can't hurt to try on a small project.

speng31b
May 8, 2010

Learning how to use refactoring tools is an important part of an effective workflow so yeah. Like the above post mentioned, make sure your project is in a good state with version control before you go nuts.

22 Eargesplitten
Oct 10, 2010



Yep, I've got a git repository set up for the project. I can just roll it back if I need to.

Does anyone have a good source for learning JUnit? The tutorials I've found don't really explain anything, just give you stuff to copy and paste.

22 Eargesplitten fucked around with this message at 02:27 on Mar 12, 2016

baquerd
Jul 2, 2007

by FactsAreUseless

22 Eargesplitten posted:

Does anyone have a good source for learning JUnit? The tutorials I've found don't really explain anything, just give you stuff to copy and paste.

What are you having trouble learning in JUnit?

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

This one looks decent (assuming you're using JUnit4)
https://www.javacodegeeks.com/2014/11/junit-tutorial-unit-testing.html

smackfu
Jun 7, 2004

Maybe something like Test Driven Development by Example would be useful?
http://www.amazon.com/Test-Driven-Development-By-Example/dp/0321146530

JUnit as such is a pretty shallow subject in my opinion, but writing good tests or using mocking is where the complexity comes in.

TheresaJayne
Jul 1, 2011

22 Eargesplitten posted:

Is the Eclipse refactoring tool worth using on a small project? About a thousand lines total. I figure if I'm going to use JUnit, I may as well run the refactoring so I have something to automatically test.

Refactoring should be a regular use of every developer, as should JUnit.

My development process is RGR (Red Green Refactor )

(typical TDD development BTW)

You write a failing test (RED)
You write code to make the test Pass (GREEN)
you then refactor the code to make it not suck so much (REFACTOR)

Rinse and repeat until software released

TheresaJayne
Jul 1, 2011

22 Eargesplitten posted:

Yep, I've got a git repository set up for the project. I can just roll it back if I need to.

Does anyone have a good source for learning JUnit? The tutorials I've found don't really explain anything, just give you stuff to copy and paste.

Unit testing can take a little while to "get" but once you understand the process its easy.

One big mistake lots of people make is to do the Partial Mock .

Stay clear of that, a Class has a TestClass and in that test class the one main rule is NEVER EVER EVER Mock any part of the Class you are testing.


As for TDD examples try the bowling Kata http://butunclebob.com/files/downloads/Bowling%20Game%20Kata.ppt

Gravity Pike
Feb 8, 2009

I find this discussion incredibly bland and disinteresting.

TheresaJayne posted:

Stay clear of that, a Class has a TestClass and in that test class the one main rule is NEVER EVER EVER Mock any part of the Class you are testing.

Gah, I've wasted so much time writing tests that don't do anything besides ensure that my mocks do what I think they do. :P

22 Eargesplitten
Oct 10, 2010



baquerd posted:

What are you having trouble learning in JUnit?

How to set up the test suite and test case classes. I feel like once I've got the basic structure up and running, I can figure everything else out. I get that the idea is to test that input of x to function foo causes an output of y.

Adbot
ADBOT LOVES YOU

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...
Bear in mind that TDD is not for everyone. Code first, tests later is also perfectly valid.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply