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
Objective Action
Jun 10, 2007



Ornedan posted:

Are these some optimisation flags Eclipse enables by default that could cause the difference?

Eclipse has its own compiler actually. They do that because they can do incremental compilation, some limited hot-swapping during debug, and it allows running code that has partial errors (sometimes).

That being said profiling Java code is a surprisingly delicate problem because, as you have already seen, the JVM under the covers is doing all sorts of just in time compilation caching and optimizations.

Generally I would recommend that you use something like the Java Microbenchmarking Harness and also that you put the code into a loop, let it execute a few times, and then run it for a few thousand iterations and aggregate the results. That will let the JVM have time to warm up and do its runtime optimizations so your numbers are more likely to be honest to real world performance.

If you are feeling really bold you could also look at using some of the new ahead of time compilation tools in JDK 17+ or GraalVM to pre-compile down to native code. This should eliminate the JIT warmup speeds if you have stuff that runs only rarely and only one or two times per lifetime of the application.

Objective Action fucked around with this message at 16:14 on Jul 9, 2023

Adbot
ADBOT LOVES YOU

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Ornedan posted:

Are these some optimisation flags Eclipse enables by default that could cause the difference?

e: oh wtf, whichever is the first one I measure time for is as fast in the javac-compiled bytecode as in Eclipse-compiled. So the javac results change if I reorder the speed tests.
sounds to me like you're starting to see interference from the profile-guided JIT; it's possible that you're reordering the tests across some internal boundary/threshold where recompilation and optimization takes place. HotSpot (being the JVM implementation you're most likely using) actually has three wayds to execute Java code: a stack interpreter, the Client Compiler (called "c1" internally) and the Server Compiler ("c2"). Both compilers are used at runtime to generate native assembly with the so-called "tiered compilation" approach: C1 is optimised for compilation speed and C2 is optimised for code quality, so C2 is used for hot code (for some internally determined definition of "hot"); infrequently-called code may not ever hit the server compiler (though this is configurable of course).

For microbenchmarks like this, you may wish to force HotSpot to always use the server compiler, under the assumption that your code in a real setting would trigger the optimizing compiler threshold anyway (which, by the sound of things, is indeed plausible). There's a HotSpot flag that will let you disable tiered compilation, and another that will set the C2 hot code threshold low enough to be triggered early.

e: beaten massively, this is what I get for leaving an old tab open :shobon:

Objective Action posted:

Generally I would recommend that you use something like the Java Microbenchmarking Harness and also that you put the code into a loop, let it execute a few times, and then run it for a few thousand iterations and aggregate the results. That will let the JVM have time to warm up and do its runtime optimizations so your numbers are more likely to be honest to real world performance.
oh, yes, I didn't think of this but if you're not already using jmh then strongly advise you to do so too.

Dijkstracula fucked around with this message at 15:35 on Jul 10, 2023

Lamech
Nov 20, 2001



Soiled Meat
edit: poooop

Lamech fucked around with this message at 02:18 on Jul 11, 2023

CPColin
Sep 9, 2003

Big ol' smile.
Well step one: Java is not JavaScript

Lamech
Nov 20, 2001



Soiled Meat
doh wrong one

see ya

Tesseraction
Apr 5, 2009

Can't really blame people for making the mistake given JavaScript specifically was chosen as the name to make people conflate the two.

Data Graham
Dec 28, 2009

📈📊🍪😋



Still pisses me off. What a dumb rear end in a top hat move

Ornedan
Nov 4, 2009


Cybernetic Crumb
Java code:
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;


@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class ReverseBitsBenchmark
{
  public static byte reverseStdlib(byte b)
  {
    return (byte)(Integer.reverse(b) >> 24);
  }

  public static byte reverseSwaps(byte b)
  {
    int r = (b & 0b11110000) >>> 4 | (b & 0b00001111) << 4;
    r = (r & 0b11001100) >>> 2 | (r & 0b00110011) << 2;
    r = (r & 0b10101010) >>> 1 | (r & 0b01010101) << 1;

    return (byte)r;
  }

  private static final int[] lookupReverseNybble =
  {
    0x0,0x8,0x4,0xc,0x2,0xa,0x6,0xe,0x1,0x9,0x5,0xd,0x3,0xb,0x7,0xf,
  };

  public static byte reverseNybbles(byte b)
  {
    return (byte)((lookupReverseNybble[b & 0b00001111] << 4) |
      lookupReverseNybble[(b & 0b11110000) >> 4]);
  }

  private static final byte[] lookupReverseByte =
  {
    (byte)0x0,(byte)0x80,(byte)0x40,(byte)0xc0,(byte)0x20,(byte)0xa0,
    (byte)0x60,(byte)0xe0,(byte)0x10,(byte)0x90,(byte)0x50,(byte)0xd0,
    (byte)0x30,(byte)0xb0,(byte)0x70,(byte)0xf0,(byte)0x8,(byte)0x88,
    (byte)0x48,(byte)0xc8,(byte)0x28,(byte)0xa8,(byte)0x68,(byte)0xe8,
    (byte)0x18,(byte)0x98,(byte)0x58,(byte)0xd8,(byte)0x38,(byte)0xb8,
    (byte)0x78,(byte)0xf8,(byte)0x4,(byte)0x84,(byte)0x44,(byte)0xc4,
    (byte)0x24,(byte)0xa4,(byte)0x64,(byte)0xe4,(byte)0x14,(byte)0x94,
    (byte)0x54,(byte)0xd4,(byte)0x34,(byte)0xb4,(byte)0x74,(byte)0xf4,
    (byte)0xc,(byte)0x8c,(byte)0x4c,(byte)0xcc,(byte)0x2c,(byte)0xac,
    (byte)0x6c,(byte)0xec,(byte)0x1c,(byte)0x9c,(byte)0x5c,(byte)0xdc,
    (byte)0x3c,(byte)0xbc,(byte)0x7c,(byte)0xfc,(byte)0x2,(byte)0x82,
    (byte)0x42,(byte)0xc2,(byte)0x22,(byte)0xa2,(byte)0x62,(byte)0xe2,
    (byte)0x12,(byte)0x92,(byte)0x52,(byte)0xd2,(byte)0x32,(byte)0xb2,
    (byte)0x72,(byte)0xf2,(byte)0xa,(byte)0x8a,(byte)0x4a,(byte)0xca,
    (byte)0x2a,(byte)0xaa,(byte)0x6a,(byte)0xea,(byte)0x1a,(byte)0x9a,
    (byte)0x5a,(byte)0xda,(byte)0x3a,(byte)0xba,(byte)0x7a,(byte)0xfa,
    (byte)0x6,(byte)0x86,(byte)0x46,(byte)0xc6,(byte)0x26,(byte)0xa6,
    (byte)0x66,(byte)0xe6,(byte)0x16,(byte)0x96,(byte)0x56,(byte)0xd6,
    (byte)0x36,(byte)0xb6,(byte)0x76,(byte)0xf6,(byte)0xe,(byte)0x8e,
    (byte)0x4e,(byte)0xce,(byte)0x2e,(byte)0xae,(byte)0x6e,(byte)0xee,
    (byte)0x1e,(byte)0x9e,(byte)0x5e,(byte)0xde,(byte)0x3e,(byte)0xbe,
    (byte)0x7e,(byte)0xfe,(byte)0x1,(byte)0x81,(byte)0x41,(byte)0xc1,
    (byte)0x21,(byte)0xa1,(byte)0x61,(byte)0xe1,(byte)0x11,(byte)0x91,
    (byte)0x51,(byte)0xd1,(byte)0x31,(byte)0xb1,(byte)0x71,(byte)0xf1,
    (byte)0x9,(byte)0x89,(byte)0x49,(byte)0xc9,(byte)0x29,(byte)0xa9,
    (byte)0x69,(byte)0xe9,(byte)0x19,(byte)0x99,(byte)0x59,(byte)0xd9,
    (byte)0x39,(byte)0xb9,(byte)0x79,(byte)0xf9,(byte)0x5,(byte)0x85,
    (byte)0x45,(byte)0xc5,(byte)0x25,(byte)0xa5,(byte)0x65,(byte)0xe5,
    (byte)0x15,(byte)0x95,(byte)0x55,(byte)0xd5,(byte)0x35,(byte)0xb5,
    (byte)0x75,(byte)0xf5,(byte)0xd,(byte)0x8d,(byte)0x4d,(byte)0xcd,
    (byte)0x2d,(byte)0xad,(byte)0x6d,(byte)0xed,(byte)0x1d,(byte)0x9d,
    (byte)0x5d,(byte)0xdd,(byte)0x3d,(byte)0xbd,(byte)0x7d,(byte)0xfd,
    (byte)0x3,(byte)0x83,(byte)0x43,(byte)0xc3,(byte)0x23,(byte)0xa3,
    (byte)0x63,(byte)0xe3,(byte)0x13,(byte)0x93,(byte)0x53,(byte)0xd3,
    (byte)0x33,(byte)0xb3,(byte)0x73,(byte)0xf3,(byte)0xb,(byte)0x8b,
    (byte)0x4b,(byte)0xcb,(byte)0x2b,(byte)0xab,(byte)0x6b,(byte)0xeb,
    (byte)0x1b,(byte)0x9b,(byte)0x5b,(byte)0xdb,(byte)0x3b,(byte)0xbb,
    (byte)0x7b,(byte)0xfb,(byte)0x7,(byte)0x87,(byte)0x47,(byte)0xc7,
    (byte)0x27,(byte)0xa7,(byte)0x67,(byte)0xe7,(byte)0x17,(byte)0x97,
    (byte)0x57,(byte)0xd7,(byte)0x37,(byte)0xb7,(byte)0x77,(byte)0xf7,
    (byte)0xf,(byte)0x8f,(byte)0x4f,(byte)0xcf,(byte)0x2f,(byte)0xaf,
    (byte)0x6f,(byte)0xef,(byte)0x1f,(byte)0x9f,(byte)0x5f,(byte)0xdf,
    (byte)0x3f,(byte)0xbf,(byte)0x7f,(byte)0xff,

  };

  public static byte reverseLookup(byte b)
  {
    return (byte)lookupReverseByte[b & 0xFF];
  }

  /**
   * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64BitsDiv
   */
  public static byte reverseBithack3(byte b)
  {
    return (byte)((((b & 0xFF) * 0x0202020202l) & 0x010884422010l) % 1023);
  }

  /**
   * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
   */
  public static byte reverseBithack4(byte b)
  {
    return (byte)((((b & 0xFF) * 0x80200802l) & 0x0884422110l) *
      0x0101010101l >> 32);
  }

  // --- Benchmarks ---

  private byte x = (byte)0b10100110;

  @Benchmark
  public byte testStdlib()
  {
    return reverseStdlib(x);
  }

  @Benchmark
  public byte testSwaps()
  {
    return reverseSwaps(x);
  }

  @Benchmark
  public byte testNybbles()
  {
    return reverseNybbles(x);
  }

  @Benchmark
  public byte testLookup()
  {
    return reverseLookup(x);
  }

  @Benchmark
  public byte testBithack3()
  {
    return reverseBithack3(x);
  }

  @Benchmark
  public byte testBithack4()
  {
    return reverseBithack4(x);
  }
}
pre:
Benchmark                          Mode  Cnt  Score   Error  Units
ReverseBitsBenchmark.testBithack3  avgt   25  1.417 ± 0.016  ns/op
ReverseBitsBenchmark.testBithack4  avgt   25  0.889 ± 0.010  ns/op
ReverseBitsBenchmark.testLookup    avgt   25  0.721 ± 0.009  ns/op
ReverseBitsBenchmark.testNybbles   avgt   25  1.073 ± 0.026  ns/op
ReverseBitsBenchmark.testStdlib    avgt   25  1.987 ± 0.107  ns/op
ReverseBitsBenchmark.testSwaps     avgt   25  1.874 ± 0.031  ns/op
Tests with JMH match the Eclipse-compiled results. So a lookup table is best, and the divisionless bithack is a close second.


I did poke the javac vs Eclipse thing a bit further. Moving each of the test loops into a separate method made javac output as fast as Eclipse output. So I'm guessing the javac-generated bytecode does something dumb with the 2nd and later loops.

Objective Action
Jun 10, 2007



Nice work! Always nice to see people doing fun stuff and reporting on it in the thread.

LostMy2010Accnt
Dec 13, 2018

So I am completely stumped with what I'm doing wrong with my Builder pattern. I've been staring at it for a week and combing SO hasn't found me any explanation on why it's occuring. I'm using Apache Commons for parsing a CSV file and creating a map of maps that looks like this Map<String, Map<Enum, Interface>>. The problem occuring is that after the map is populated, when I check the objects in the map; they're all pointing to the same object.

code:
Los Angeles Kings={Standard=stats.teams.StandardTeamStats@485966cc}
Montreal Canadiens={Standard=stats.teams.StandardTeamStats@485966cc}
Calgary Flames={Standard=stats.teams.StandardTeamStats@485966cc}
New York Islanders={Standard=stats.teams.StandardTeamStats@485966cc}
Toronto Maple Leafs={Standard=stats.teams.StandardTeamStats@485966cc}
Philadelphia Flyers={Standard=stats.teams.StandardTeamStats@485966cc}
New York Rangers={Standard=stats.teams.StandardTeamStats@485966cc}
Winnipeg Jets={Standard=stats.teams.StandardTeamStats@485966cc}
Washington Capitals={Standard=stats.teams.StandardTeamStats@485966cc}
Colorado Avalanche={Standard=stats.teams.StandardTeamStats@485966cc}
Columbus Blue Jackets={Standard=stats.teams.StandardTeamStats@485966cc}
New Jersey Devils={Standard=stats.teams.StandardTeamStats@485966cc}
Buffalo Sabres={Standard=stats.teams.StandardTeamStats@485966cc}
St Louis Blues={Standard=stats.teams.StandardTeamStats@485966cc}
Dallas Stars={Standard=stats.teams.StandardTeamStats@485966cc}
Anaheim Ducks={Standard=stats.teams.StandardTeamStats@485966cc}
Ottawa Senators={Standard=stats.teams.StandardTeamStats@485966cc}
Detroit Red Wings={Standard=stats.teams.StandardTeamStats@485966cc}
Nashville Predators={Standard=stats.teams.StandardTeamStats@485966cc}
Pittsburgh Penguins={Standard=stats.teams.StandardTeamStats@485966cc}
Seattle Kraken={Standard=stats.teams.StandardTeamStats@485966cc}
Edmonton Oilers={Standard=stats.teams.StandardTeamStats@485966cc}
San Jose Sharks={Standard=stats.teams.StandardTeamStats@485966cc}
Carolina Hurricanes={Standard=stats.teams.StandardTeamStats@485966cc}
Vancouver Canucks={Standard=stats.teams.StandardTeamStats@485966cc}
Arizona Coyotes={Standard=stats.teams.StandardTeamStats@485966cc}
Minnesota Wild={Standard=stats.teams.StandardTeamStats@485966cc}
Florida Panthers={Standard=stats.teams.StandardTeamStats@485966cc}
Chicago Blackhawks={Standard=stats.teams.StandardTeamStats@485966cc}
Vegas Golden Knights={Standard=stats.teams.StandardTeamStats@485966cc}
Boston Bruins={Standard=stats.teams.StandardTeamStats@485966cc}
Tampa Bay Lightning={Standard=stats.teams.StandardTeamStats@485966cc}
So here's the Class with nested builder class:
Java code:
/**
 * Standard related team stats class.
 */
public class StandardTeamStats implements IStats {
    private String teamName;
    private int gamesPlayed;
    private BigDecimal timeOnIce;

    private int wins;
    private int losses;
    private int overtimeLosses;
    private int nonShootoutWins;

    private int points;
    private BigDecimal pointPercentage;

    /**
     * Constructor for standard related team stats.
     * 
     * @param builder object for builder design pattern
     */
    private StandardTeamStats(Builder builder) {
        teamName = builder.teamName;
        gamesPlayed = builder.gamesPlayed;
        timeOnIce = builder.timeOnIce;
        wins = builder.wins;
        losses = builder.losses;

        overtimeLosses = builder.overtimeLosses;
        nonShootoutWins = builder.nonShootoutWins;
        points = builder.points;
        pointPercentage = builder.pointPercentage;
    }

    public String getTeamName() {
        return teamName;
    }

    public int getGamesPlayed() {
        return gamesPlayed;
    }

    public BigDecimal getTimeOnIce() {
        return timeOnIce;
    }

    public int getWins() {
        return wins;
    }

    public int getLosses() {
        return losses;
    }

    public int getOvertimeLosses() {
        return overtimeLosses;
    }

    public int getNonShootoutWins() {
        return nonShootoutWins;
    }

    public int getPoints() {
        return points;
    }

    public BigDecimal getPointPercentage() {
        return pointPercentage;
    }

    /**
     * Nested class to be used in a Builder Design Pattern.
     */
    public static class Builder {
        private String teamName;
        private int gamesPlayed;
        private BigDecimal timeOnIce;

        private int wins;
        private int losses;
        private int overtimeLosses;
        private int nonShootoutWins;

        private int points;
        private BigDecimal pointPercentage;

        public Builder() {
            // Empty constructor
        }

        public Builder teamName(String argTeamName) {
            teamName = argTeamName;
            return this;
        }

        public Builder gamesPlayed(String argGamesPlayed) {
            gamesPlayed = StatConverterHelper.generateIntegerStat(argGamesPlayed);
            return this;
        }

        public Builder timeOnIce(String argTimeOnIce) {
            timeOnIce = StatConverterHelper.generateBigDecimalStat(argTimeOnIce);
            return this;
        }

        public Builder wins(String argWins) {
            wins = StatConverterHelper.generateIntegerStat(argWins);
            return this;
        }

        public Builder losses(String argLosses) {
            losses = StatConverterHelper.generateIntegerStat(argLosses);
            return this;
        }

        public Builder overtimeLosses(String argOvertimeLosses) {
            overtimeLosses = StatConverterHelper.generateIntegerStat(argOvertimeLosses);
            return this;
        }

        public Builder nonShootoutWins(String argNonShootoutWins) {
            nonShootoutWins = StatConverterHelper.generateIntegerStat(argNonShootoutWins);
            return this;
        }

        public Builder points(String argPoints) {
            points = StatConverterHelper.generateIntegerStat(argPoints);
            return this;
        }

        public Builder pointPercentage(String argPointPercentage) {
            pointPercentage = StatConverterHelper.generateBigDecimalStat(argPointPercentage);
            return this;
        }

        public StandardTeamStats build() {
            return new StandardTeamStats(this);
        }
    }
}
Here's the class that's utilizing the Commons library to parse my csv file and create the stat object:
Java code:
/**
 * Class for creating the stat objects and compiling them into a Map of Maps.
 */
public class HockeyStatConsumer {
    private static final Logger LOG = LogManager.getLogger(HockeyStatConsumer.class);

    /**
     * Private constructor to maintain static behavior.
     */
    private HockeyStatConsumer() {
        // Private constructor to protect from having it instantiated.
    }

    /**
     * Leverage Apache Commons library for parsing a CSV file and returning the
     * results in a Map with stat objects.
     * 
     * @param  argFileName file name to ascertain flow of construction process
     * @return             Map of maps with stat objects associated with unique
     *                     identifier
     * @throws IOException if file name is incorrect or non-existent
     */
    public static Map<String, Map<EStatTypes, IStats>> generateStats(String argFileName)
            throws IOException {
        Map<String, Map<EStatTypes, IStats>> teamStats = new HashMap<>();

        try (BufferedReader input = new BufferedReader(new FileReader(argFileName))) {
            CSVFormat csvRaw = CSVFormat.DEFAULT.builder()
                    .setHeader()
                    .setSkipHeaderRecord(true)
                    .setAllowMissingColumnNames(true)
                    .build();

            Map<EStatTypes, IStats> elementStats = new EnumMap<>(EStatTypes.class);

            Iterable<CSVRecord> records = csvRaw.parse(input);

            for (CSVRecord team : records) {

                elementStats.put(EStatTypes.STANDARD,
                        new StandardTeamStats.Builder().teamName(team.get("Team"))
                                .gamesPlayed(team.get("GP"))
                                .timeOnIce(team.get("TOI"))
                                .wins(team.get("W"))
                                .losses(team.get("L"))
                                .overtimeLosses(team.get("OTL"))
                                .nonShootoutWins(team.get("ROW"))
                                .points(team.get("Points"))
                                .pointPercentage(team.get("Point %"))
                                .build());

                teamStats.put(team.get("Team"), elementStats);
            }

        }
        catch (IOException e) {
            LOG.fatal("File not found, incorrect name, or not exceptable formatting.");
            e.printStackTrace();
        }
        return teamStats;
    }
}
Details:
  • I'm using an Enum for my key and the value is the stat object
  • I'm using an interface so that I can create different stat classes that will be stored in the map as well. So the goal is the first key is the team name, then in the inner map the key is the stat type and the value is the stat object
  • The CSVFormat object is also using a builder design pattern as well
  • I have a helper class being used in the StandardTeamStats class that handles a few of the stats that need to be converted to an int or BigDecimal
  • To the best of my understanding, my mistake is that I'm pointing to the builder object in all elements in the map; hence the printed results at the top of my post

I haven't updated my repo recently, but if it would help I can cut a branch with this work in it and if that would help. Let me know if there's anything else that would help with figuring this out.

Also, critique on code and design is welcomed. This is early in my personal project so if I'm doing something ugly, let me know so I can work it. Not looking for you to solve it, just call it out and I'll gladly spend the time to learn how to do it.

Thank you.

LostMy2010Accnt fucked around with this message at 12:37 on Sep 13, 2023

Tesseraction
Apr 5, 2009

On my phone but from a glance it looks like here


Java code:

teamStats.put(team.get("Team"), elementStats); }

you're assigning the elementStats Map to every entry in teamStats, which is why the printed output is the same printed object's position in memory.

I might be misunderstanding but could you either comment or pseudocode what you're trying to do there and also what you expect it to print instead of what you showed in your post?

VegasGoat
Nov 9, 2011

Tesseraction posted:

On my phone but from a glance it looks like here


Java code:
teamStats.put(team.get("Team"), elementStats); }
you're assigning the elementStats Map to every entry in teamStats, which is why the printed output is the same printed object's position in memory.

I might be misunderstanding but could you either comment or pseudocode what you're trying to do there and also what you expect it to print instead of what you showed in your post?

Yeah probably just needs to move the elementStats = new… inside the records loop so each team has its own elementStats.

LostMy2010Accnt
Dec 13, 2018

Tesseraction posted:

On my phone but from a glance it looks like here


Java code:
teamStats.put(team.get("Team"), elementStats); }
you're assigning the elementStats Map to every entry in teamStats, which is why the printed output is the same printed object's position in memory.

I might be misunderstanding but could you either comment or pseudocode what you're trying to do there and also what you expect it to print instead of what you showed in your post?

Thank you for looking into it, I'll try to explain better what I'm doing.

So I'm trying to parse a CSV file and then from it create a Map that consists of a key for the team name and then a value of another map. In the inner map I want to use an enum to classify the type or name of the object and then the value is the object itself. for the loop here's what I'm trying to do:

code:
create the map of maps

create a BufferedReader Object with the csv file as the input
	create CSVFormat object and set the fields to build
	
	create an EnumMap to store all the stat objects I intend to populate it with

	create the iterator based on the CSVRecord

	for every row (team) in the CSVRecord that I'm itterating over
		add Enum stat as name and key as object
		put that map into the teamStats with team name as key

return the populated mape of maps
When I debug it, I see the team object I'm trying to create consists of the last team/element/entry that was processed. So I'd have 32 entries all with the same StanderTeamStats object in them.

Again, apologies if I'm not describing it well; I'm terrible with programing venacular, it's a weak spot of mine that I'm really tryin to improve upon.

LostMy2010Accnt
Dec 13, 2018

VegasGoat posted:

Yeah probably just needs to move the elementStats = new… inside the records loop so each team has its own elementStats.

Thank you. I'll give that a try and report back what happens.

Tesseraction
Apr 5, 2009

Okay looking into this a little closer, first thing I'm gonna pull up isn't the solution, but

Java code:
 elementStats.put(EStatTypes.STANDARD,
                        new StandardTeamStats.Builder().teamName(team.get("Team"))
                                .gamesPlayed(team.get("GP"))
                                .timeOnIce(team.get("TOI"))
                                .wins(team.get("W"))
                                .losses(team.get("L"))
                                .overtimeLosses(team.get("OTL"))
                                .nonShootoutWins(team.get("ROW"))
                                .points(team.get("Points"))
                                .pointPercentage(team.get("Point %"))
                                .build());
Builders should be made differently - see here https://www.digitalocean.com/community/tutorials/builder-design-pattern-in-java

Java code:
	//Builder Class
	public static class ComputerBuilder{

		// required parameters
		private String HDD;
		private String RAM;

		// optional parameters
		private boolean isGraphicsCardEnabled;
		private boolean isBluetoothEnabled;
		
		public ComputerBuilder(String hdd, String ram){
			this.HDD=hdd;
			this.RAM=ram;
		}

		public ComputerBuilder setGraphicsCardEnabled(boolean isGraphicsCardEnabled) {
			this.isGraphicsCardEnabled = isGraphicsCardEnabled;
			return this;
		}

		public ComputerBuilder setBluetoothEnabled(boolean isBluetoothEnabled) {
			this.isBluetoothEnabled = isBluetoothEnabled;
			return this;
		}
		
		public Computer build(){
			return new Computer(this);
		}

	}
Java code:
public static void main(String[] args) {
		//Using builder to get the object in a single line of code and 
                //without any inconsistent state or arguments management issues		
		Computer comp = new Computer.ComputerBuilder(
				"500 GB", "2 GB").setBluetoothEnabled(true)
				.setGraphicsCardEnabled(true).build();
	}
Builders have mandatory fields and non-mandatory; at the very least your team has to have a name or some other unique identifier, after all this is what's going to be the key to your Map.

As for the rest... if you could upload a sanitised version of your code/CSV file to your source repo it would help me at the very least dissect where the issue is. At the very least it'll let me run through the debugger to see where things start going south.

LostMy2010Accnt
Dec 13, 2018

Tesseraction posted:

Okay looking into this a little closer, first thing I'm gonna pull up isn't the solution, but


Builders have mandatory fields and non-mandatory; at the very least your team has to have a name or some other unique identifier, after all this is what's going to be the key to your Map.

As for the rest... if you could upload a sanitised version of your code/CSV file to your source repo it would help me at the very least dissect where the issue is. At the very least it'll let me run through the debugger to see where things start going south.

Thank you. I'm having issues with my project because I'm trying to learn Maven along the way so it's going to take me a little to get it going. I'll post back when I get it it squared away.

LostMy2010Accnt
Dec 13, 2018

Tesseraction posted:

...
As for the rest... if you could upload a sanitised version of your code/CSV file to your source repo it would help me at the very least dissect where the issue is. At the very least it'll let me run through the debugger to see where things start going south.

Okay I made the correction to my builder class and updated my branch with the changes.

https://github.com/sDriskell/HockeyStats/tree/build_csv_consumer

There's a csv file inside HockeyStatVisualizer that I'm using. It's only 32 rows but does have about 71 columns. Currently only working with the first 10 columns.

Still having issues with my maven pom file; it's new to me but I've not had luck building it, just importing dependencies for the project. Also working on why log4j2 isn't logging either; I think it might have something to do with where I have it in the project directory. If any of these are causing you issues, then don't sweat looking into this. Appreciate it, thanks.

Pedestrian Xing
Jul 19, 2007

LostMy2010Accnt posted:

Still having issues with my maven pom file; it's new to me but I've not had luck building it, just importing dependencies for the project. Also working on why log4j2 isn't logging either; I think it might have something to do with where I have it in the project directory. If any of these are causing you issues, then don't sweat looking into this. Appreciate it, thanks.

Your log4j2.xml should be under src/main/resources. What errors are you seeing with the pom?

Tesseraction
Apr 5, 2009

Okay I've download your git repo and it seems rather different from the code you were asking a question about. I don't see a Map anywhere here? This code seems to work fine?

franks
Jan 1, 2007

Alcoholism is the only
disease you can get
yelled at for having.

LostMy2010Accnt posted:

Still having issues with my maven pom file; it's new to me but I've not had luck building it, just importing dependencies for the project. Also working on why log4j2 isn't logging either; I think it might have something to do with where I have it in the project directory. If any of these are causing you issues, then don't sweat looking into this. Appreciate it, thanks.

I know it’s easy to try and do a lot at once, but I’d highly recommend trying to change one thing at a time so you can more easily identify where any problems are. I’m not a superdev by any means but that has been really helpful for my debugging.

LostMy2010Accnt
Dec 13, 2018

Pedestrian Xing posted:

Your log4j2.xml should be under src/main/resources. What errors are you seeing with the pom?

Ah I just had in source, thank you for catching that. Not seeing errors with pom more that: 1) I'm just trying to learn how to use it; 2) Eclipse is acting really odd whenever I try to modify it at times (Weird spacing, freezes, etc.).

Tesseraction posted:

Okay I've download your git repo and it seems rather different from the code you were asking a question about. I don't see a Map anywhere here? This code seems to work fine?

Sorry it should be the build_csv_consumer branch that I've commited the current work I have.

Please don't feel obligated to go too deep in this. I think this is really more of a byproduct of me trying to make multiple changes at a single time with this project. I hate wasting time so don't stress over this one.


franks posted:

I know it’s easy to try and do a lot at once, but I’d highly recommend trying to change one thing at a time so you can more easily identify where any problems are. I’m not a superdev by any means but that has been really helpful for my debugging.

Yeah, this was a learning lesson in that this week.

Thank you everyone for jumping in and helping. I think my lesson today is to not make so many changes concurrently so I'll take the L on that.

Tesseraction
Apr 5, 2009

Looking at the code (your Maven config seemed correct FWIW) it's doing what you want it to, just with the issue of you assigning the full Map<EStatTypes, IStats> elementStats to every Team entry in the Map<String, Map<EStatTypes, IStats>> teamStats.

Let's pick three teams, I'll take the first three in your CSV, the Anaheim Ducks, the Arizona Coyotes, and the Boston Bruins. As it goes over these three CSVRecord team elements:

elementStats creates a new entry for the Anaheim Ducks, with the stats you specified, effectively a key,value of ["Anaheim Ducks", StandardTeamStatsObj@1]

It then adds this to teamStats as ["Anaheim Ducks", [ ["Anaheim Ducks", StandardTeamStatsObj@1] ] ]

next it adds an entry of ["Arizona Coyotes",StandardTeamStatsObj@2] to elementStats, this now makes it [ ["Anaheim Ducks", StandardStatsObj@1] , ["Arizona Coyotes",StandardStatsObj@2] ]
now you're adding that to teamStats as ["Arizona Coyotes", [ ["Anaheim Ducks", StandardStatsObj@1] , ["Arizona Coyotes",StandardStatsObj@2] ] ]

And because Java passes by reference, the entry for Anaheim Ducks has now changed to ["Anaheim Ducks", [ ["Anaheim Ducks", StandardStatsObj@1] , ["Arizona Coyotes",StandardStatsObj@2] ] ]

So lastly the Boston Bruins will be added to teamStats as ["Boston Bruins", [ ["Anaheim Ducks", StandardStatsObj@1] , ["Arizona Coyotes",StandardStatsObj@2] , ["Boston Bruins",StandardStatsObj@3] ] ]

I hope this clarifies why your code isn't doing what you're expecting? I guess we can simplify this a bit: for the three loops, to save a bit of time I'm shortening the teams to AD, AC and BB:

loop 1 elementStats adds ["AD",STS@1]
elementStats is an object we will call object ES@1
loop 1 teamStats adds ["AD",ES@1]

loop 2 elementStats adds ["AC",STS@2]
elementStats is the same object, ES@1
loop 2 teamStats adds ["AC", ES@1]

loop 3 elementStats adds ["BB",STS@3]
elementStats is the same object, ES@1
loop 2 teamStats adds ["BB", ES@1]

Does that make sense?

Pedestrian Xing
Jul 19, 2007

LostMy2010Accnt posted:

Ah I just had in source, thank you for catching that. Not seeing errors with pom more that: 1) I'm just trying to learn how to use it; 2) Eclipse is acting really odd whenever I try to modify it at times (Weird spacing, freezes, etc.).

Turn off any kind of auto-import or sync your IDE might be doing on pom.xml modification and trigger it manually when you make a change.

Ihmemies
Oct 6, 2012

I have a problem deciding what is the least crap way of implementing choicebox values in javafx. Depending on user selections and choiceboxes, I need to have a variable_id (for API calls) associated with the choice, or a LineChart.class for example, so I know what kind of XYChart the user wants to draw.

How would you store the choices? Enums? Classes? Something else? Enums work ok'ish with strings, like this:

Java code:
public enum AxisType {
    CONSUMPTION("Consumption", "124", "Electricity Consumption (1 Hour)"),
    PRODUCTION("Production", "74", "Electricity Production (1 Hour)"),
    PRICE("Price", "00", ""),
    TEMPERATURE("Temperature", "00", ""),
    WIND("Wind", "00", "");

    private final String label;
    private final String variableId;
    private final String description;

    AxisType(String label, String variableId, String description) {
        this.label = label;
        this.variableId = variableId;
        this.description = description;
    }

    public String getVariableId() {
        return variableId;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return label;
    }

    public static List<String> stringValues() {
        List<String> stringValues = new ArrayList<>();
        for (AxisType type : AxisType.values()) {
            stringValues.add(type.toString());
        }
        return stringValues;
    }
}
But if I want to store a class - for example LineChart.class or AreaChart.class - I can't get the constructor to work with a Class<?> or Class<? extends XYChart<Number, Number>>. It always crashes and burns because of invalid syntax.

This seems to work:

Java code:
public enum ChartType {
    LINE_CHART("Line chart") {
        @Override
        public XYChart<Number, Number> createChart() {
            return new LineChart<>(new NumberAxis(), new NumberAxis());
        }
    },
    AREA_CHART("Area chart") {
        @Override
        public XYChart<Number, Number> createChart() {
            return new AreaChart<>(new NumberAxis(), new NumberAxis());
        }
    };

    private final String label;

    ChartType(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return label;
    }

    public abstract XYChart<Number, Number> createChart();

    public static List<String> stringValues() {
        List<String> stringValues = new ArrayList<>();
        for (ChartType type : ChartType.values()) {
            stringValues.add(type.toString());
        }
        return stringValues;
    }
}
Then this in the actual program:

Java code:
ChartType selectedChartType = chartTypeChoiceBox.getValue();
XYChart<Number, Number> chart = selectedChartType.createChart();
Why it is so hard to store classes? How else would I figure out what kind of chart I need to draw, based on user choice? Any pro tips..?

This thing is a 4 man course project, still on prototype stage, so I can try out all kinds of stuff.

Ihmemies fucked around with this message at 06:14 on Sep 17, 2023

MrQueasy
Nov 15, 2005

Probiot-ICK

Ihmemies posted:

I have a problem deciding what is the least crap way of implementing choicebox values in javafx. Depending on user selections and choiceboxes, I need to have a variable_id (for API calls) associated with the choice, or a LineChart.class for example, so I know what kind of XYChart the user wants to draw.

I don't understand why you need to store a class here? Instantiating from a Class<?> value is not really done except when you're doing some really nasty reflection/bytecode manipulation fuckery.

Personally I would go with a similar way that in my brain looks cleaner (completely my preferences/biases though)
Java code:
    LINE_CHART("Line chart", () -> new LineChart<>(new NumberAxis(), new NumberAxis()),
    AREA_CHART("Area chart", () -> new AreaChart<>(new NumberAxis(), new NumberAxis());
    private final String label;
    private final Supplier<XYChart<Number, Number> createFn;

    ChartType(String label, Supplier<XYChart<Number, Number>> createFn) {
        this.label = label;
        this.createFn = createFn;
    }

    @Override
    public String toString() {
        return label;
    }

    public XYChart<Number, Number> createChart() {
        return createFn.get();
    }

    public static List<String> stringValues() {
        List<String> stringValues = new ArrayList<>();
        for (ChartType type : ChartType.values()) {
            stringValues.add(type.toString());
        }
        return stringValues;
    }
This is because I use 11 most of the time for work. If I could use 17+, then I'd probably use Sealed classes over enums for this particular use-case despite them being a bit clunky.

EDIT: Oh, JavaFX. hmm.

Ihmemies
Oct 6, 2012

Well that seems to work too. We are using 17 so I guess I can research sealed classes too. Thanks :D

LostMy2010Accnt
Dec 13, 2018

Tesseraction posted:

Looking at the code (your Maven config seemed correct FWIW) it's doing what you want it to, just with the issue of you assigning the full Map<EStatTypes, IStats> elementStats to every Team entry in the Map<String, Map<EStatTypes, IStats>> teamStats.

Let's pick three teams, I'll take the first three in your CSV, the Anaheim Ducks, the Arizona Coyotes, and the Boston Bruins. As it goes over these three CSVRecord team elements:

elementStats creates a new entry for the Anaheim Ducks, with the stats you specified, effectively a key,value of ["Anaheim Ducks", StandardTeamStatsObj@1]

It then adds this to teamStats as ["Anaheim Ducks", [ ["Anaheim Ducks", StandardTeamStatsObj@1] ] ]

next it adds an entry of ["Arizona Coyotes",StandardTeamStatsObj@2] to elementStats, this now makes it [ ["Anaheim Ducks", StandardStatsObj@1] , ["Arizona Coyotes",StandardStatsObj@2] ]
now you're adding that to teamStats as ["Arizona Coyotes", [ ["Anaheim Ducks", StandardStatsObj@1] , ["Arizona Coyotes",StandardStatsObj@2] ] ]

And because Java passes by reference, the entry for Anaheim Ducks has now changed to ["Anaheim Ducks", [ ["Anaheim Ducks", StandardStatsObj@1] , ["Arizona Coyotes",StandardStatsObj@2] ] ]

So lastly the Boston Bruins will be added to teamStats as ["Boston Bruins", [ ["Anaheim Ducks", StandardStatsObj@1] , ["Arizona Coyotes",StandardStatsObj@2] , ["Boston Bruins",StandardStatsObj@3] ] ]

I hope this clarifies why your code isn't doing what you're expecting? I guess we can simplify this a bit: for the three loops, to save a bit of time I'm shortening the teams to AD, AC and BB:

loop 1 elementStats adds ["AD",STS@1]
elementStats is an object we will call object ES@1
loop 1 teamStats adds ["AD",ES@1]

loop 2 elementStats adds ["AC",STS@2]
elementStats is the same object, ES@1
loop 2 teamStats adds ["AC", ES@1]

loop 3 elementStats adds ["BB",STS@3]
elementStats is the same object, ES@1
loop 2 teamStats adds ["BB", ES@1]

Does that make sense?

poo poo. Okay I see what you're saying. Thank you for taking the time to look into this and explaining what I was missing. Much appreciated!


Pedestrian Xing posted:

Turn off any kind of auto-import or sync your IDE might be doing on pom.xml modification and trigger it manually when you make a change.

Oh that makes sense. Thank you.

Ihmemies
Oct 6, 2012

We're doing a desktop app for course, because web abbs were explicitly forbidden. We ended up using javafx because that's what a few guys have used earlier.



Is there some "easy" way to specify the line/area colors? I looked at assigning an ID to each data series (line) depending on datatype, and then applying the color for that id with CSS. Like nuclear = YELLOW, wind = GREEN, hydro = BLUE etc.

But no, this poo poo rear end piece of garbage apparently gives data series id's automatically from 0..n, based on the add order to chart.

So I'd have to make some kind of hell construct to figure out the id of each added series... etc. I don't even want to think about it. The chart can have any amount of series depending on datatype. Each datatype should have a specific color always...

Who ***** thought that it is ***** good idea to label the series automatically with incrementing id, which depends on add order...

Already thinking about implementing a webview inside the javafx app.

Ihmemies fucked around with this message at 11:31 on Oct 20, 2023

Tesseraction
Apr 5, 2009

Could you extend the Chart.Data object to include its type of energy and use that to determine its colour? Sorry if I'm misremembering JavaFX, I haven't touched it in 15 years.

Tempora Mutantur
Feb 22, 2005

CPColin posted:

I like that future() function that it calls, which does a bounds check, then performs an array operation that does the same bounds check, except correctly (it should be >=, not >).

I am slightly terrified that I just decided to interview at a place using Vert.x and this is apparently the most recent reference to using it here, as well as hardly any mention of it anywhere online

as a hardened spring guy who has enough experience with web flux to make it not explode, why do I want vert.x instead of spring + web flux for reactive apps? what am I gaining with vert.x that makes up for losing everything spring gives me?

(the answer will be "because their management pays you to write it using vert.x" but I'd like to know if there's an actual good reason)

RandomBlue
Dec 30, 2012

hay guys!


Biscuit Hider

Tempora Mutantur posted:

I am slightly terrified that I just decided to interview at a place using Vert.x and this is apparently the most recent reference to using it here, as well as hardly any mention of it anywhere online

as a hardened spring guy who has enough experience with web flux to make it not explode, why do I want vert.x instead of spring + web flux for reactive apps? what am I gaining with vert.x that makes up for losing everything spring gives me?

(the answer will be "because their management pays you to write it using vert.x" but I'd like to know if there's an actual good reason)

IIRC Vert.x is a much smaller microservices framework with some performance gains over Spring/Spring Boot.

OTOH it's not anywhere near as popular with all the issues that implies.

I haven't worked with it myself though.

Volguus
Mar 3, 2009

Tempora Mutantur posted:

because their management pays you to write it using vert.x

and that should be enough.

Janitor Prime
Jan 22, 2004

PC LOAD LETTER

What da fuck does that mean

Fun Shoe

Tempora Mutantur posted:

(the answer will be "because their management pays you to write it using vert.x" but I'd like to know if there's an actual good reason)

Seriously dude, you think working at any of the FAANG companies will get your relevant experience in technology X, only to find that internally they use some janky custom built poo poo that then spawned into the frameworks you love.

CPColin
Sep 9, 2003

Big ol' smile.

CPColin posted:

I like that future() function that it calls, which does a bounds check, then performs an array operation that does the same bounds check, except correctly (it should be >=, not >).

I went back and looked, by the way, and somebody did come along and fix it so it's >= and not >, but there's still a question of why they bother to throw IndexOutOfBoundsException explicitly when ArrayIndexOutOfBoundsException extends that class anyway. I guess maybe they're trying to hide the detail that an array is involved?

smackfu
Jun 7, 2004

We use Vertx at work. I’m not an expert but I don’t like the resulting code. Lots of callback methods to get the async behavior. Tends to end up with massive methods with stupid level of indentation that are not trivial to refactor. Also difficult in practice to properly catch errors if they are thrown in the callback.

Submarine Sandpaper
May 27, 2007


Not being a java dev or even knowing java I've been given 2k lines of uncommented code that I did not write to own. It lives in a SaaS solution.

The method that's called is passed multiple SQL statements for tables that do not exist locally as well as a flat file of employee information. I do not have a development workspace where I can setup temp tables for testing nor would I really be able to without being able to setup a mini SaaS product. Pushing code up to the SaaS solution and a test run after any changes takes about 4 hours.

Having never used Eclipse or any other java IDE I have no idea how I can step through this code to see what methods are actually being used. There are methods in different classes with the same name, some are called, some are literally example code the vendor threw in there from their KBs which I know are not used. I need to get familiarity with Eclipse before I start to modify this, and using "Control + H" on methods is making my eyes bleed. I know when compiling the Jar if I delete the wrong method or class it'll let me know, but I want to approach it in the inverse so I can get these 2k lines of code down to a more manageable 800 or so.

I guess what I'm looking for is a good Eclipse primer and the OP is like 14 years old.

Volguus
Mar 3, 2009
You have a while to go until it becomes an IDE question. You need to find out what do you need to do to run and debug the code that you have to modify. Which in turn requires a bit more knowledge of the product itself. Then you can come and ask "how do I do X in Eclipse" (or whatever other IDE. I'm sure intellij will be suggested, not that it will make a difference).

Submarine Sandpaper
May 27, 2007


What if, due to not having local class dependencies, I could never effectively get an actual local run in the IDE? Seems like I'll need to cut and compile and test :(
I was hoping I could say call com.vendor.foo.impla(bar) and just run through the classes that enumerates through. Not an actual test case, just sorta how problems will display if I axe the wrong method or class. An unused code plugin gave nada.

com.vendor.foo is not a public library. I'll hunt for some docs but I can't even find documentation to determine environmental variables or subdomains where the code is running to solve for hardcoded dev vs prod variables (lmao it's worse than that, hard coded domains etc in code).

Submarine Sandpaper fucked around with this message at 15:53 on Feb 7, 2024

CmdrRiker
Apr 8, 2016

You dismally untalented little creep!

Submarine Sandpaper posted:

Not being a java dev or even knowing java I've been given 2k lines of uncommented code that I did not write to own. It lives in a SaaS solution.

The method that's called is passed multiple SQL statements for tables that do not exist locally as well as a flat file of employee information. I do not have a development workspace where I can setup temp tables for testing nor would I really be able to without being able to setup a mini SaaS product. Pushing code up to the SaaS solution and a test run after any changes takes about 4 hours.

Having never used Eclipse or any other java IDE I have no idea how I can step through this code to see what methods are actually being used. There are methods in different classes with the same name, some are called, some are literally example code the vendor threw in there from their KBs which I know are not used. I need to get familiarity with Eclipse before I start to modify this, and using "Control + H" on methods is making my eyes bleed. I know when compiling the Jar if I delete the wrong method or class it'll let me know, but I want to approach it in the inverse so I can get these 2k lines of code down to a more manageable 800 or so.

I guess what I'm looking for is a good Eclipse primer and the OP is like 14 years old.

I am very sorry, but what you are describing is a horrible nightmare of programming that I would never wish on another developer.

At that point I wouldn't even try to salvage it into "working". I would try to refactor it into a couple of objectives mapped into classes and several runtimes into routines to accomplish a certain thing?

Eclipse is just a thing to vomit boilerplate code into your project. It isn't necessary to do what you want. Please just break it apart into more pieces with more concrete objectives.

Adbot
ADBOT LOVES YOU

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb
What's a good way of identifying 3rd party Java dependencies that are no longer actively maintained?

It's pretty straightforward with maven to find out which dependencies are out of date, meaning there is a newer version available.

What about for the case when you are on the latest version of a dependency, but there hasn't been a new version in a while and the project is no longer maintained?

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