GithubHelp home page GithubHelp logo

functions's Introduction

Java Functions

To include the full library in your project (not recommended!), add the following to your POM:

<project>
...
    <dependencies>
        ...
        <dependency>
            <groupId>net.mintern</groupId>
            <artifactId>functions-ternary-all</artifactId>
            <version>1.0</version>
        </dependency>
        ...
    </dependencies>
...
</project>

You almost certainly do not want or need all of the 16,000+ (!) classes, so replace ternary-all with the subset you need.

Every Java @FunctionalInterface you want!

This project provides @FunctionalInterfaces for every possible function of 0 to 3 arguments. It enumerates all combinations of parameters and return values for all Java types:

  • void
  • boolean
  • byte
  • short
  • char
  • int
  • long
  • float
  • double
  • Object

The functions are named in a logical way that is well-suited for automatic code generation but remains readable. For example:

  • NilToLong: long call()
  • ObjIntToNil<T>: void call(T t, int i)
  • BoolToShort: short call(boolean bool)
  • DblFloatByteToChar: char call(double d, float fl, byte b)
  • ObjObjObjToObj<T, U, V, R>: R call(T t, U u, V v)

Checked interfaces

As with Java 8's java.util.function package, none of the above methods throw exceptions. Especially in the case of IOException this can lead to lambdas that are much uglier than necessary. To solve this problem, this project also provides a checked version for every interface, indicated by its presence in a .checked package and an E suffix:

  • NilToLongE<E extends Exception>: long call() throws E
  • ObjIntToNilE<T, E extends Exception>: void call(T t, int i) throws E
  • BoolToShortE<E extends Exception>: short call(boolean bool) throws E

...and so on. This means that you can now write a method like this:

void withReader(Path p, ObjToNilE<BufferedReader, IOException> f) throws IOException {
    try (BufferedReader r = Files.newBufferedReader(p, Charset.forName("UTF-8"))) {
        f.call(r);
    }
}

and call it as follows:

withReader(path, reader -> {
    String line;
    while ((line = reader.readLine()) != null) { // <-- may throw!
        // do something with line
    }
});

This works! In other words, there's no need to catch and wrap the exception when you use these checked interfaces in obvious places.

Static methods

It gets better than that! Even when a method expects an unchecked functional interface, you can still avoid the exception handling boilerplate:

Stream<Path> paths = ...;
String[] firstLines = paths
        .map(ObjToObj.uncheckedIO(path -> Files.newBufferedReader(path, utf8)))
        .map(ObjToObj.uncheckedIO(BufferedReader::readLine))
        .toArray(String[]::new);

Both newBufferedReader and getLine can throw exceptions, but the uncheckedIO method transparently converts an ObjToObjE<T, U, IOException> to an ObjToObj<T, U>, wrapping any thrown IOException with an UncheckedIOException!

A more general unchecked(Function<? super E, RuntimeException> wrap, f) is also provided that allows you to wrap your exception however you wish, or you can use unchecked(f) to simply wrap it in a RuntimeException.

But Stream.map takes a Function!

I'm glad you noticed that! Any net.mintern.functions interface that has the same signature as a Java interface extends the Java one, meaning that you can just plug it right in! For example:

  • NilToNil extends Runnable
  • NilToObjE<V> extends Callable<V>
  • ObjIntToNil<T> extends ObjIntConsumer<T>
  • ObjObjToObj<T, U, R> extends BiFunction<T, U, R>

and so on.

bind

In case that's not enough, every non-nullary function provides both static and instance bind and rbind methods. If you are tired of this pattern:

hexStrings.mapToInt(hexString -> Integer.valueOf(hexString, 16))

then you can replace it with:

hexStrings.mapToInt(ObjIntToInt.rbind(Integer::valueOf, 16))

It's not a huge win in this case, but perhaps you'll find places where it is!

Sensible packaging

As you might imagine, providing all of these type combinations results in an explosion in the number of classes. In order to avoid pulling in so many functions that you are unlikely to use, I've split them up as follows:

  • nullary (20 classes): checked and unchecked functions to produce every type (a la Java's Suppliers)
  • unary-core (48 classes): 1-argument functions that accept int, long, double, or Object, returning void, boolean, int, long, double, or Object. The unchecked unary-core functions correspond to Java's Function and Predicate types.
  • unary-extended (96 classes): unary-core, but with boolean, byte, char, and float arguments and return values
  • unary-all (36 classes): all of unary-extended, plus short types (because who uses short?)
  • binary-core (192 classes): like unary-core, but for 2-argument functions (includes replacements for BiFunction, ObjIntConsumer, BiPredicate, etc.)
  • binary-extended (960 classes): you get the idea
  • binary-all (468 classes)
  • ternary-core (768 classes): exactly what you think it is
  • ternary-extended (8448 classes): not a typo!
  • ternary-all (5364 classes)

Only pull in what you need!

Note that every extended package pulls in its corresponding core package, in addition to the other extended packages that take fewer arguments. Likewise, all pulls in extended. This means that a dependency on binary-extended will also pull in binary-core, unary-extended, unary-core, and nullary.

Contributing

I will happily accept Pull Requests. If you have any questions, ask away.

Building

In the root directory, run mvn install. That will build everything.

Where are all the source files?

For this project, I used an ancient-but-solid (by modern standards) template language called FreeMarker to provide a template that generates all of the source. A handy FreeMarker PreProcessor (FMPP)—in conjunction with an FMPP Maven plugin that I came across on Stack Overflow—turns that template into thousands of Java source files.

Some data definitions are in semicolon-delimited (scsv!) files in the FreeMarker configuration, but most of the logic for generating everything is in a single template file: Functions.java.ft.

What's next?

I'll be using this library to build out modern Pair and Triple libraries, Either types, Collection and Stream (and BiStream and TriStream) enhancements, and more. If you like this library, keep an eye on the mintern-java organization for new ones!

functions's People

Contributors

mintern avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.