Welche Klassen fehlen im JDK?

Landei

Top Contributor
Welche ganz einfachen, allgemein verwendbaren Java-Klassen wurden eurer Meinung nach von Sun und Oracle einfach "vergessen"?

Mal der Versuch einer persönlichen Liste:

- Option<A> implements Iterable<A> (als Null-Ersatz, kann ein A enthalten)
- Pair<A,B> (enthält ein A und ein B)
- Triple<A,B,C> (enthält ein A, B und C)
- Either<A,B> (enthält entweder ein A oder ein B)
- ImmutableDate (unveränderliches Datum mit vernünftiger Schnittstelle)
- CharList implements List<Character> (Wrapper um StringBuilder):

Java:
import java.util.AbstractList;

public class CharList extends AbstractList<Character> {

    private StringBuilder sb;

    public CharList() {
        sb = new StringBuilder();
    }

    public CharList(String s) {
        sb = new StringBuilder(s);
    }

    public CharList(char[] cs) {
        sb = new StringBuilder(new String(cs));
    }

    @Override
    public Character get(int i) {
        return sb.charAt(i);
    }

    @Override
    public Character set(int index, Character c) {
        char result = sb.charAt(index);
        sb.setCharAt(index,c);
        return result;
    }

    @Override
    public void add(int index, Character c) {
        sb.insert(index, c);
    }

    @Override
    public Character remove(int index) {
        char result = sb.charAt(index);
        sb.deleteCharAt(index);
        return result;
    }

    @Override
    public int size() {
        return sb.length();
    }

    @Override
    public String toString() {
        return sb.toString();
    }

    @Override
    public void clear() {
        sb.setLength(0);
    }
}

Und schon gehen allerhand lustige Sachen:
Java:
List<Character> list = new CharList("garbage");
Collections.shuffle(list);
System.out.println(list); //rabggae oder so...
 
Zuletzt bearbeitet:
hallo landei

interessanter post!

ein paar sachen, welche von mir aus gesehen fehlen:

- eine einfache smtp-client klasse. (diese javax.mail-geschichte ist über 1 mb gross, und muss zusätzlich heruntergeladen werden)

- eine einfach http(s)-client klasse. (wieso ist das nicht dabei? ständig braucht man diese apache-libraries dafür...)

- eine collection, welche einen avl-tree implementiert (treemap verwendet einen "rot/schwarz-baum" soviel ich weiss...)

- einen schnellen stack! mein aus einen c-code nachgeschriebener quicksort (rekursion nicht indem sich die methode selber aufruft, sondern über einen stack) läuft mit dem java-stack nur etwa halb so schnell wie mit array-basierenden stacks. der java-stack ist instanzbasiert, oder...?


etwas wie eine value-pair habe ich auch schon gebraucht, genauer eine "name-value-pair". dort kann man halt nur den "value" über generics bestimmen, der "name" steht fest - ist ein string.
 
code habe ich vergessen, die instanzierung erfolgt über eine factory und die konstanten sind für reflection gedacht (hatte einen besonderen fall...):

Java:
package pairing;

import java.util.List;

import string.MyStringUtil;

public final class NVPair<T>
{
    private final String attributeName;

    private T attributeValue = null;

    public static final String ATTRIBUTE_NAME = "attributeName";

    public static final String ATTRIBUTE_VALUE = "attributeValue";

    private NVPair(final String attributeName, final T attributeValue)
    {
        this.attributeName = attributeName;
        this.attributeValue = attributeValue;
    }

    public String getAttributeName()
    {
        return this.attributeName;
    }

    public T getAttributeValue()
    {
        return this.attributeValue;
    }

    public static <T> NVPair<T> getValuePair(final String attributeName, final T attributeValue)
    {
        return new NVPair<T>(attributeName, attributeValue);
    }

    public void setAttributeValue(final T attributeValue)
    {
        this.attributeValue = attributeValue;
    }

    @Override
    public String toString()
    {
        return MyStringUtil.myToString(this);
    }

    @SuppressWarnings("unchecked")
    public static String convertNVPairListAttributeNameToCSV(final List<NVPair> list)
    {
        String ret = "";

        for (int counter = 0; counter < list.size(); counter++)
        {
            final String attr = list.get(counter).getAttributeName().toString();
            ret += attr;

            if (counter < (list.size() - 1))
            {
                ret += ", ";
            }
        }

        return ret;
    }

}



einige realisieren sowas über eine hashmap mit einem eintrag. na ja, geht auch, ist aber sicher einiges langsamer...
 
Zuletzt bearbeitet:
hier der http-client, wo etwa das "NVPair" verwendet wird:

Java:
package http_raw;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

import pairing.NVPair;

public class RawHTTPClient
{
    private String mServer = null;

    private int mPort = 0;

    public void setConnection(final String caServer, final int caPort)
    {
        this.mServer = caServer;
        this.mPort = caPort;
    }

    public String doHttpPost(final String caURL, final NVPair<String>[] nvPairArr)
    {
        final StringBuilder response = new StringBuilder();
        BufferedReader lBufferedReader = null;

        try
        {
            final URL clURL = new URL("http://" + this.mServer + ":" + this.mPort + caURL);

            final URLConnection lConnection = clURL.openConnection();
            lConnection.setDoInput(true);
            lConnection.setDoOutput(true);
            lConnection.setUseCaches(false);
            lConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            final DataOutputStream lDataOutputStream = new DataOutputStream(lConnection.getOutputStream());

            String data = "?";

            for (int cnt = 0; cnt < nvPairArr.length; cnt++)
            {
                final NVPair<String> element = nvPairArr[cnt];

                String sep = "&";

                if (cnt == (nvPairArr.length - 1))
                {
                    sep = "";
                }

                data = data + element.getAttributeName() + "=" + element.getAttributeValue() + sep;
            }

            lDataOutputStream.writeBytes(data);
            lDataOutputStream.flush();
            lDataOutputStream.close();

            lBufferedReader = new BufferedReader(new InputStreamReader(lConnection.getInputStream()));

            String lTmp = null;

            while ((lTmp = lBufferedReader.readLine()) != null)
            {
                response.append(lTmp + "\r\n");
            }
        }
        catch (final Exception caException)
        {
            throw new RuntimeException(caException);
        }
        finally
        {
            try
            {
                if (lBufferedReader != null)
                {
                    lBufferedReader.close();
                }
            }
            catch (final Exception caException)
            {
                final Runtime clRuntime = Runtime.getRuntime();
                clRuntime.gc();
            }
        }

        return response.toString();
    }

    public String doHttpPost(final String caURL, final String caParameters)
    {
        final StringBuilder response = new StringBuilder();
        BufferedReader lBufferedReader = null;

        try
        {
            final URL clURL = new URL("http://" + this.mServer + ":" + this.mPort + caURL);

            final URLConnection lConnection = clURL.openConnection();
            lConnection.setDoInput(true);
            lConnection.setDoOutput(true);
            lConnection.setUseCaches(false);
            lConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            final DataOutputStream lDataOutputStream = new DataOutputStream(lConnection.getOutputStream());
            lDataOutputStream.writeBytes(caParameters);
            lDataOutputStream.flush();
            lDataOutputStream.close();

            lBufferedReader = new BufferedReader(new InputStreamReader(lConnection.getInputStream()));

            String lTmp = null;

            while ((lTmp = lBufferedReader.readLine()) != null)
            {
                response.append(lTmp + "\r\n");
            }
        }
        catch (final Exception caException)
        {
            throw new RuntimeException(caException);
        }
        finally
        {
            try
            {
                if (lBufferedReader != null)
                {
                    lBufferedReader.close();
                }
            }
            catch (final Exception caException)
            {
                final Runtime clRuntime = Runtime.getRuntime();
                clRuntime.gc();
            }
        }

        return response.toString();
    }

    public String doHttpGet(final String caURLAndParameters)
    {
        String lRetString = "";
        InputStreamReader lInputStreamReader = null;
        BufferedReader lBufferedReader = null;

        try
        {
            final URL clURL = new URL("http://" + this.mServer + ":" + this.mPort + caURLAndParameters);
            lInputStreamReader = new InputStreamReader(clURL.openStream());
            lBufferedReader = new BufferedReader(lInputStreamReader);
            String lTmpString = null;

            while ((lTmpString = lBufferedReader.readLine()) != null)
            {
                lRetString = lRetString + lTmpString + "\r\n";
            }
        }
        catch (final Exception caException)
        {
            throw new RuntimeException(caException);
        }
        finally
        {
            try
            {
                if (lInputStreamReader != null)
                {
                    lInputStreamReader.close();
                }
                if (lBufferedReader != null)
                {
                    lBufferedReader.close();
                }
            }
            catch (final Exception caException)
            {
                final Runtime clRuntime = Runtime.getRuntime();
                clRuntime.gc();
            }
        }

        return lRetString.trim();
    }
}
 
hier noch der https-client, ist strukturell unterschiedlich zum http-client (hatte auch nicht vor, eine komponentenbibliothek zu schreiben, sondern etwas was mir eine gerade aufgetretenes problem löst...):

Java:
package http_raw;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.Socket;
import java.security.SecureRandom;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class RawHTTPSClient
{
    private String mServer = null;

    private int mPort = 0;

    public void setConnection(final String caServer, final int caPort)
    {
        this.mServer = caServer;
        this.mPort = caPort;
    }

    public String doSSLHttpGet(final String caURL)
    {
        return this.doHttps(0, caURL);
    }

    // may be not working...
    public String doSSLHttpPost(final String caURL)
    {
        return this.doHttps(1, caURL);
    }

    private String doHttps(final int caMethod, String aURL)
    {
        if (aURL == null)
        {
            aURL = "";
        }

        String lMethod = null;

        switch (caMethod)
        {
            case 0:
                lMethod = "GET";
                break;
            case 1:
                lMethod = "POST";
                break;
            default:
                break;
        }

        Socket lSocket = null;
        BufferedReader lBufferedReader = null;
        StringWriter lStringWriter = null;
        Writer lWriter = null;

        try
        {
            final SSLContext lSSLContext = SSLContext.getInstance("SSL");
            lSSLContext.init(null, RawHTTPSClient.getWeakTrustManager(), new SecureRandom());
            final SSLSocketFactory lSSLSocketFactory = lSSLContext.getSocketFactory();
            lSocket = lSSLSocketFactory.createSocket(this.mServer, this.mPort);

            lWriter = new OutputStreamWriter(new BufferedOutputStream(lSocket.getOutputStream()));
            final String url = lMethod + " https://" + this.mServer + ":" + this.mPort + aURL + " HTTP/1.0\r\n";

            lWriter.write(url);
            lWriter.write("\r\n");
            lWriter.flush();

            lBufferedReader = new BufferedReader(new InputStreamReader(lSocket.getInputStream()));

            int lChar = 0;

            lStringWriter = new StringWriter();

            while ((lChar = lBufferedReader.read()) != -1)
            {
                lStringWriter.append((char) lChar);
            }
        }
        catch (final Exception caException)
        {
            throw new RuntimeException(caException);
        }
        finally
        {
            try
            {
                if (lStringWriter != null)
                {
                    lStringWriter.close();
                }

                if (lBufferedReader != null)
                {
                    lBufferedReader.close();
                }

                if (lWriter != null)
                {
                    lWriter.close();
                }

                if (lSocket != null)
                {
                    lSocket.close();
                }
            }
            catch (final Exception caException)
            {
                final Runtime clRuntime = Runtime.getRuntime();
                clRuntime.gc();
            }
        }

        return lStringWriter.toString();
    }

    private static final TrustManager[] getWeakTrustManager()
    {
        final TrustManager[] clWeakTrustManagerArr = new TrustManager[] { new X509TrustManager()
        {
            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }

            public void checkClientTrusted(final java.security.cert.X509Certificate[] certs, final String authType)
            {

            }

            public void checkServerTrusted(final java.security.cert.X509Certificate[] certs, final String authType)
            {

            }
        } };

        return clWeakTrustManagerArr;
    }
}
 
Mal der Versuch einer persönlichen Liste: [...]
Viele der Punkte wurden nicht vergessen, die machen ohne Lambdas einfach keinen Sinn. Was bringt mir ein Option wenn ich den darin liegenden Wert nur über Javas anonyme Klassen bearbeiten kann? Das sieht dann ja hässlicher aus als wenn ich Option nicht benutzen würde.

Nichtsdestotrotz, ich hätte gerne eine vernünftige Collection-Bibliothek. Also eine, mit der man auch Strings komfortabel verarbeiten kann und bei der man nicht alle paar Zeilen immer wieder den gleichen Code schreiben muss (wie mit Schleife über Collection iterieren und neue Collection erzeugen). Eine Factory für Collections wäre auch nicht schlecht, damit man z.B. einfach
Code:
Set.of(1,2,3)
schreiben kann. Unveränderliche Collection-Klassen wären auch nicht schlecht.

Aber da fällt mir ein: Java 8 soll ja bald kommen. Irgendwann. Wenn es denn mal fertig ist.
 
(manches mag bei java kommen/in Planung sein, ich schreib einfach mal)

nicht wirklich ne Klasse, aber der Elvis operator: Proposal: Elvis and Other Null-Safe Operators

ansonsten:

- bessere Boolean klasse (mit and, or, xor etc)
- Closures
- bessere File klasse, bzw FileUtils (Inhalt lesen, schreiben etc)

mhm mehr fallen mir grad nicht ein (ausser Landeis genannten)
 
Viele der Punkte wurden nicht vergessen, die machen ohne Lambdas einfach keinen Sinn. Was bringt mir ein Option wenn ich den darin liegenden Wert nur über Javas anonyme Klassen bearbeiten kann? Das sieht dann ja hässlicher aus als wenn ich Option nicht benutzen würde.

Wenn
Code:
Option<T>
ein
Code:
Iterable<T>
ist, kann man immerhin schreiben:

Java:
Option<String> stringOption = ...
Option<Integer> intOption = Option.<Integer>none();
for(String s : stringOption) {
   intOption = Option.some(s.length());
}

Zugegebenermaßen nicht umwerfend elegant, aber immerhin...
 
@Landei: Coole Fragestellung. 🙂

Spontan fallen mir Sachen ein wie (Namen sind hoffentlich sprechend genug, sind nicht immer nur Klassen):
  • Code:
    System.arrayequals()
    (wie
    Code:
    System.arraycopy()
    )
  • ArrayIterator
  • ganze Pakete zu Kodierungen à la Base64, BCD etc.
  • Rational (Bruchzahlen à la Nenner/Zähler)
  • Complex (Wrapper-Klasse für komplexe Zahlen)
  • ComplexMath (wie Math mit primitiven Datentypen, aber für komplexe Zahlen)
  • FastMath (Math-Variante, die nur Näherungen berechnet, dafür aber wesentlich schneller ist)
  • BigDecimalMath
  • IntegerMath (Ganzzahloperationen für long bzw. int, wobei Überläufe etc. abgefragt werden können bzw. überprüft werden)
  • Matrix (für Matrizenoperationen etc.)
  • Klassen für FFT (DFT/DCT/DST/DHT) und Wavelets
  • Spezielle Collections-Implementierungen für primitive Datentypen, à la IntIntHashMap etc.
  • Interface java.util.Filter<T> (gibt es als DirectoryStream.Filter<T>, aber in java.nio.file, WTF! Könnte eigentlich viele "spezielle" Filterklassen im JDK ersetzen.)
  • java.util.Trie (Typvariablen bitte dazudenken)
  • SetList<E> (List-Typ, wobei jedes Element in dieser Liste nur einmal vorkommen darf; manchmal doch recht praktisch)
  • CSVReader und CSVWriter
  • HTMLParser
  • GlobalHotkeys
  • ncurses-Schnittstelle
  • ScalableVectorGraphics (SVG)

Viele/einige/alle(?) Sachen gibt's zwar über externe Libs, aber ich bin der Meinung, dass vor allem diese Mathematische-Grundlagen-Sachen eigentlich mit dem JDK kommen sollten. Es ist sozusagen ein "Fehler", dass folgende Libs überhaupt existieren (müssen):

Ark
 
Zuletzt bearbeitet:
Mittlerweile binde ich googles guava oft ein. Da gibt es einige Klassen die ich mir auch im JDK wünschen würden. Zum Beispiel wären das:

- Optional damit man mit
Code:
null
besser umgehen kann. Statt einer Klasse würde ich mir dafür aber auch den Elvis-Operator wüschen

- Preconditions um Parameter einfach checken zu können.

- Multimap eine Map mit beliebigen Key und einer Liste von Werten. Praktisch um Werte zu gruppieren.

- EventBus um Evente zu verarbeiten, wesentlich einfacher als das Observerpattern selbst zu implementieren.
 
Ganz "realistisch": Ein ComparableComparator - ein Comparator, der beliebige Comparables vergleicht (schaut euch mal die entsprechenden Klassen an, welcher Code da dupliziert wurde, weil es den NICHT gibt :autsch: )

Ansonsten stimmt es: SEHR viel von dem, was man "immer schon mal haben wollte", gibt es in Guava. Und auch vieles, was man bisher nicht vermisst hat, bei dem man wenn man es sieht aber denkt: "Hey, das ist ja praktisch, damit könnte man .... :reflect: " 😀

Es ist schwierig, die Grenze zu ziehen. Vieles braucht man nur in SEHR speziellen Zusammenhängen. Es gibt schon Stimmen, die sich (teilweise zu Recht) über die Explosion der Standard-API beschweren. Solange es sowas wie Jigsaw nicht gibt, sollte man mit Erweiterungen IMHO nicht ganz so verschwenderisch umgehen. Es soll auch den Namen "Standard-API" verdienen.

Z.B. Complex numbers ... ja, bei sehr vielen Mathematisch-Wissenschaftlichen Themen braucht man das, aber bei 99% der in Java geschriebenen Anwendungen braucht man das nicht. Meistens ist es so, dass jemand, der sich "ernsthaft" mit einer bestimmten Sache beschäftigt, mehr braucht, als man vernünftig in einer Standard-API unterbringen könnte. (Erstbestes Beispiel: Joa, Math.random() tut's doch? Aber wenn man kryptographisch sichere, große Zufallszahlen will, kommt man um eine Lib mit Mersenne Twister & Co eben nicht drumrum...)

@Ark, BTW: "System.arrayequals()" -> Arrays.equals(...)

@Landei: Einige der genannten Punkte kommen wohl daher, dass du... *räusper* von einem bestimmten JVM-Alien infiziert bist, das jetzt aus deinem Bauch raus will 😀

Ich finde, einige Dinge könnten in die Standard-API augenommen werden, weil sie sehr allgemein und insbesondere domänenunabhängig (!) sind. Ganz prominent (und auch schon in Guava) : Sowas wie Predicate und Function. Allerdings stehen 1. einige Entwicklungen für Java 8 an, die diese Erweiterungen vermutlich überflüsig machen, und 2. würde das dann noch einen ganzen Rattenschwanz von "Wenn dies dann aber zumindest auch das"-Wünschen nach sich ziehen.... (Plakativ: Warum nur Tuple und Triple, und nicht auch Quadruple oder alle weiteren aus javatuples - Main ...?)
 
"System.arrayequals()" -> Arrays.equals(...)
Das ist mir schon klar. Es geht mir darum, ähnlich wie bei
Code:
System.arraycopy()
die Möglichkeiten der Maschine auszunutzen. So kann man sich z.B. leicht Code vorstellen, der bei einem byte[]-Array jeweils 8 Bytes auf einmal vergleicht, wenn es sich um eine 64-Bit-Maschine handelt usw. 😉

Wo wir gerade bei Arrays sind: Ein one-fits-all-0-Elemente-Array wäre auch nicht schlecht. ^^ Und relationale Algebra für sortierte(!) Arrays à la
Code:
Arrays.addAll()
oder
Code:
Arrays.containsAll()
wäre auch praktisch. Oder
Code:
Arrays.toArraySet()
, das Mehrfachvorkommen eliminiert … und so 😉

Ark
 
Zuletzt bearbeitet:
hmm ... schon interessant was hier alles kommt was sich einige als bestandteil der SE-API wünschen ... bei einigen dingen würde ich mitgehen ... bei anderen denke ich mir eher : java wurde dafür eigentlich ursprünglich nicht konzipiert ...

sicher ... sowas wie n ordentlicher Base64-codec sollte eigentlich dabei sein ... aber global hotkeys gehen dann doch ne nummer zu weit ... zu mal sowas stark system-abhängig ist

@jmar83
die java-mail-api ist bestandteil der EE-API ... warum diese in die SE-API aufgenommen werden sollte ergibt für mich keinen sinn ...
zu mal die lib als JAR mit SMTP, POP3 und IMAP gerade mal 500kb groß ist ...
 
@Landei: Einige der genannten Punkte kommen wohl daher, dass du... *räusper* von einem bestimmten JVM-Alien infiziert bist, das jetzt aus deinem Bauch raus will 😀

Man wird sich ja noch Anregungen holen dürfen 🙂

Jedenfalls sind das alles Sachen, die auch unter Java sinnvoll sein können. Wenn ich wirklich funktionales Java haben wöllte, hätte ich Functional Java auf die Wunschliste gesetzt.
 
Klar wäre es schon Funktionen zu besitzen, gerade Stringmanipulation u.s.w. ist ein Graus mit Standart-Java-Mitteln. Die Frage ist natürlich schon, wo fängt man an und wo hört man auf.

Besser eine externe Bibliothek als ein Urwald an Klassen und Helferklassen für jeden Spezialfall...
 
sorry ... aber codes die NULL raisen wurden 1) nicht genug getestet und 2) einfach nur schlecht implementiert ...

wenn man nicht 100% sicher sein kann das X nie NULL ist dann schreibt man einfach if(x==null) ...

ALLE RuntimeException lassen sich durch richtige programmierung und richtiges testen (ich spreche hier mal nicht von diesem bullshit "unit-test") komplett ausschließen ... auch wenn if(x==null) nicht wirklich das beste ist so ist es doch immer noch besser als catch(NullPointerException) oder sogar catch(RuntimeException) ... wobei es (wie mir mal an nem beispiel gezeigt wurde) durchaus sinn macht Throwable zu catchen ... obwohl auch das eigentlich NIE vorkommen sollte ... und eher zeugnis für sehr miesen code ist ...
 

Neue Themen


Zurück
Oben