Base utils class

Discussion in 'Programming' started by FiXed, Jun 30, 2016.

  1. So I've been writing a little bit of a utils class to hold quite a bit of methods for myself, it's a package containing this method so I can add more classes to utilize inside the Utils class or just in general I just need ideas on what to add, my current class looks like this:
    Code (Java):
    package utils;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.Random;
    import java.util.regex.Pattern;

    public class Utils {

        private static final Random random = new Random();

        public static final <T> T getRandom(Map<T, Double> chances) {
            double chance = random.nextDouble() * 100;
            List<T> simpleArray = new ArrayList<T>();
            for (T value : chances.keySet())
                if (chances.get(value) > chance)
                    simpleArray.add(value);
            if (simpleArray.isEmpty())
                return null;
            return simpleArray.get(random.nextInt(simpleArray.size()));
        }

        public static final double calculate(String string) {
            if (string == null || string.isEmpty())
                return 0;
            String copy = string.replaceAll("^0-9+\\-*/\\.\\^]", "");
            if (copy.isEmpty())
                return 0;
            for (char character : new char[] { '^', '*', '/', '+', '-' })
                copy = calculate(copy, character);
            return Double.parseDouble(copy);
        }

        private static final String calculate(String copy, char type) {
            String[] vals = copy.split("\\" + type);
            double outcome = 0.0;
            for (int i = 0; i < vals.length - 1; i++) {
                String val1 = vals[i];
                String val2 = vals[i + 1];
                String[] first = val1.split("[+\\-/*\\^]");
                String[] second = val2.split("[+\\-/*\\^]");
                String secondRaw = val2.replace(second[0], "");
                double firstVal = Double.parseDouble(first[first.length - 1]);
                double secondVal = Double.parseDouble(second[0]);
                outcome = firstVal - secondVal;
                switch (type) {
                case '^':
                    outcome = Math.pow(firstVal, secondVal);
                    break;
                case '*':
                    outcome = firstVal * secondVal;
                    break;
                case '/':
                    outcome = firstVal / secondVal;
                    break;
                case '+':
                    outcome = firstVal + secondVal;
                    break;
                case '-':
                    outcome = firstVal - secondVal;
                    break;
                }
                copy = copy.replaceFirst(Pattern.quote(first[first.length - 1] + type + second[0]),
                        String.valueOf(outcome));
                vals[i + 1] = outcome + secondRaw;
            }
            return copy;
        }

        public static final void writeCommand(final String command) {
            try {
                final Process process = Runtime.getRuntime().exec(command);
                final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (final IOException x) {
                x.printStackTrace();
            }
        }

    }
     
    containing a weighted random system, a calculation method, and a method to write out DOS commands.

    I think it's coded pretty well but if you have any ideas on what I could add or what I should add let me know as well as if you have any ideas on how I could improve on what I currently have.
     
  2. Only add what you need, and maybe make the method names a bit more descriptive. And the getRandom() is really inefficient.
     
  3. How is it inefficient? And yeah I've added only what I need like calculate and command methods, I like to mix DOS into Java to have some more fun with it
     
  4. You are using an entirely unneeded list and several unneeded steps, and there is no reason to use a map, it just adds more complexity and inefficiency (maps are made for searching efficiency, not memory efficiency or iteration). Use the Pair class, or make your own simple container that just supports the random operations.
     
  5. So you're suggesting to just use a set or list of container classes?
    Something like this:
    Code (Java):
    public class Container<A, B> {
     
        private final A first;
        private final B second;
     
        public Container(A first, B second) {
            this.first = first;
            this.second = second;
        }
     
        public A getFirst() {
            return first;
        }
     
        public B getSecond() {
            return second;
        }
     
    }
    I've also fixed up the code in the method a bit so now it looks a little like this:
    Code (Java):
        public static final <T> T getRandom(Set<Container<T, Double>> chances) {
            double top = 0.0;
            for (final Container<T, Double> cont : chances) {
                if (cont.getSecond() >= top) {
                    top = cont.getSecond();
                }
            }
            return getRandom(chances, top);
        }

        public static final <T> T getRandom(Set<Container<T, Double>> chances, double cap) {
            final double chance = ThreadLocalRandom.current().nextDouble(cap);
            final List<T> simpleArray = new ArrayList<T>();
            for (final Container<T, Double> cont : chances) {
                if (cont.getSecond() > chance) {
                    simpleArray.add(cont.getFirst());
                }
            }
            if (simpleArray.isEmpty()) {
                return getRandom(chances, cap);
            }
            return simpleArray.get(ThreadLocalRandom.current().nextInt(simpleArray.size()));
        }
     
    #5 FiXed, Jul 1, 2016
    Last edited: Jul 1, 2016
  6. Yes, although there is utterly no reason not to make them public and just remove the silly getters, they serve utterly no purpose except to prevent modification of the value (final works better for something so simple) and to fulfill OOP prettiness OCD.
     
  7. Haha okay I'll remove the getters but does the container class look good?
     
  8. Remove final from static methods and put it before the class name. I think that you can add Utils#sendTitle(Player,String,String), Utils#sendActionBar(Player,String), Utils#clearInventory(Player) (which clears the player inventory and set armor contents to null) and finally I think that also a function to add Commands in runtime would be useful!
     
    #8 JohnnyKPL, Jul 3, 2016
    Last edited: Jul 3, 2016
  9. I'm trying to make it NOT use the spigot API, this is more of a general utils class and why remove final from them?
     
  10. Using good OOP practice is always the right thing to do. What he's done is called encapsulation, and even though it isn't necessary here, it's good practice.

    I assume you aren't planning on extending Utils anytime soon, so it is essentially redundant. Setting those methods to final simply prevents them from being hidden. Rather, utility classes could be marked final and contain a private default constructor to prevent instances from being created. This is a matter of preference, though.
     
  11. I'd rather have them final just because I NEVER want them to change which is the correct practice and making the getters in the container class is the right thing to do I thought...
     
  12. I think you misunderstood me.
    Yes, using getters in the container class is the right way to do it, and those fields are good to be final.
    What I'm pointing out is that your methods have static AND final modifiers. Most of the time people don't use those modifiers together, because static methods aren't subject to polymorphism. You can read more in my last post.
     
  13. ah I see, you're correct, I added this method as well just to mess with strings, replacing the nth time a character ocurrs with a string:
    Code (Java):
        public static String replaceNthTerm(String string, char replacer, String replaceWith, int nth) {
            int i = 1;
            if (nth <= 0 || string == null || string.isEmpty() || replaceWith.isEmpty() || replaceWith == null)
                return string;
            for (int pos = 0; pos < string.length(); pos++) {
                if (string.charAt(pos) == replacer && i++ == nth) {
                    char[] charArray = string.toCharArray();
                    char[] secArray = replaceWith.toCharArray();
                    List<Object> chars = new ArrayList<Object>();
                    for (char character : charArray)
                        chars.add(Character.valueOf(character));
                    int placeholder = pos;
                    chars.set(pos, "");
                    for (int var = 0; var < secArray.length; var++)
                        chars.add(placeholder++, secArray[var]);
                    String newString = "";
                    for (Object charac : chars)
                        newString += charac;
                    return newString;
                }
            }
            return string;
        }