All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.organicdesign.fp.function.Function1 Maven / Gradle / Ivy
// Copyright 2013-12-30 PlanBase Inc. & Glen Peterson
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.organicdesign.fp.function;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import org.organicdesign.fp.Option;
import org.organicdesign.fp.collections.UnmodIterable;
import org.organicdesign.fp.xform.Transformable;
import org.organicdesign.fp.xform.Xform;
/**
This is like Java 8's java.util.function.Function, but retrofitted to turn checked exceptions
into unchecked ones.
*/
@FunctionalInterface
public interface Function1 extends Function, Consumer {
// ========================================== Static ==========================================
enum Const implements Function1 {
IDENTITY {
@Override
public Object applyEx(Object t) throws Exception {
return t;
}
@SuppressWarnings({"unchecked", "TypeParameterExplicitlyExtendsObject"})
@Override
public Function1 compose(Function1 super S,? extends Object> f) {
// Composing any function with the identity function has no effect on the original
// function (by definition of identity) - just return it.
return (Function1) f;
}
}
}
enum ConstBool implements Function1 {
/**
A predicate that always returns true. Use accept() for a type-safe version of this predicate.
*/
ACCEPT {
@Override public Boolean applyEx (Object ignored) throws Exception {
return Boolean.TRUE;
}
},
/**
A predicate that always returns false. Use ConstBool.REJECT for a type-safe version of this predicate.
*/
REJECT {
@Override public Boolean applyEx (Object ignored) throws Exception {
return Boolean.FALSE;
}
}
}
/** Use {@link Const#IDENTITY} instead. */
@Deprecated
Function1 IDENTITY = Const.IDENTITY;
@SuppressWarnings("unchecked")
static Function1 identity() { return (Function1) Const.IDENTITY; }
static Function1 or(Function1 a, Function1 b) {
// Composition is not necessary in every case:
return a == ConstBool.ACCEPT ? a : // If any are true, all are true.
a == ConstBool.REJECT ? b : // return whatever b is.
b == ConstBool.ACCEPT ? b : // If any are true, all are true.
b == ConstBool.REJECT ? a : // Just amounts to if a else false.
(S s) -> (a.apply(s) == Boolean.TRUE) || (b.apply(s) == Boolean.TRUE); // compose
}
static Function1 and(Function1 a, Function1 b) {
// Composition is not necessary in every case:
return a == ConstBool.ACCEPT ? b : // return whatever b is.
a == ConstBool.REJECT ? a : // if any are false, all are false.
b == ConstBool.ACCEPT ? a : // Just amounts to if a else false.
b == ConstBool.REJECT ? b : // If any are false, all are false.
(S s) -> (a.apply(s) == Boolean.TRUE) && (b.apply(s) == Boolean.TRUE); // compose
}
static Function1 negate(Function1 super S,Boolean> a) {
return a == ConstBool.ACCEPT ? reject() :
a == ConstBool.REJECT ? accept() :
(S s) -> (a.apply(s) == Boolean.TRUE) ? Boolean.FALSE : Boolean.TRUE;
}
/** Use {@link ConstBool#ACCEPT} instead */
@Deprecated
Function1 ACCEPT = ConstBool.ACCEPT;
/** Use {@link ConstBool#REJECT} instead */
@Deprecated
Function1 REJECT = ConstBool.REJECT;
/** Returns a type-safe version of the ConstBool.ACCEPT predicate. */
@SuppressWarnings("unchecked")
static Function1 accept() { return (Function1) ConstBool.ACCEPT; }
/** Returns a type-safe version of the ConstBool.REJECT predicate. */
@SuppressWarnings("unchecked")
static Function1 reject() { return (Function1) ConstBool.REJECT; }
/**
Composes multiple functions into a single function to potentially minimize trips through
the source data. The resultant function will loop through the functions for each item in the
source. For a few functions and many source items, that takes less memory. Considers no
function to mean the IDENTITY function. This decision is based on the way filters work and
may or may not prove useful in practice. Please use the identity()/IDENTITY
sentinel value in this abstract class since function comparison is done by reference.
LIMITATION: You could have a function that maps from T to U then the next from U to V, the
next from V to W and so on. So long as the output type of one matches up to the input type of
the next, you're golden. But type safety curls up and dies when you try to detect the
IDENTITY function at some point in the chain.
For arbitrary chaining, it's best to roll your own. The following example shows how simple it
is to chain two functions with an intermediate type into a single composite function:
public static <A,B,C> Function1<A,C> chain2(final Function1<A,B> f1,
final Function1<B,C> f2) {
return new Function1<A,C>() {
@Override
public C applyEx(A a) throws Exception {
return f2.applyEx(f1.applyEx(a));
}
};
}
Even with 2 arguments, there are several signatures that would work: imagine where A=B, B=C,
or A=C. I just don't see the value to providing a bunch of chain2(), chain3() etc. functions
that will ultimately not be type-safe and cannot perform optimizations for you, when you can
roll your own type safe versions as you need them. Only the simplest case seems worth
providing, along the lines of the and() helper function in Filter()
@param in the functions to applyEx in order. Nulls and IDENTITY functions are ignored.
No functions means IDENTITY.
@param the type of object to chain functions on
@return a function which applies all the given functions in order.
*/
static Function1 compose(Iterable> in) {
if (in == null) {
return identity();
}
final List> out = new ArrayList<>();
for (Function1 f : in) {
if ((f == null) || (f == Const.IDENTITY)) {
continue;
}
out.add(f);
}
if (out.size() < 1) {
return identity(); // No functions means to return the original item
} else if (out.size() == 1) {
return out.get(0);
} else {
return v -> {
V ret = v;
for (Function1 f : out) {
ret = f.applyEx(ret);
}
return ret;
};
}
}
/**
Composes multiple predicates into a single predicate to potentially minimize trips through
the source data. The resultant predicate will loop through the predicates for each item in
the source, but for few predicates and many source items, that takes less memory. Considers
no predicate to mean "accept all." Use only accept()/ACCEPT and reject()/REJECT since
function comparison is done by reference.
@param in the predicates to test in order. Nulls and ACCEPT predicates are ignored. Any
REJECT predicate will cause this entire method to return a single REJECT predicate. No
predicates means ACCEPT.
@param the type of object to predicate on.
@return a predicate which returns true if all input predicates return true, false otherwise.
*/
static Function1 and(Iterable> in) {
if (in == null) { return accept(); }
Transformable> v =
(in instanceof UnmodIterable) ? (UnmodIterable>) in
: Xform.of(in);
return v.filter(p -> (p != null) && (p != ConstBool.ACCEPT))
.foldLeft(accept(),
(accum, p) -> (p == reject()) ? p : and(accum, p),
accum -> accum == reject());
}
/**
Composes multiple predicates into a single predicate to potentially minimize trips through
the source data. The resultant predicate will loop through the predicates for each item in
the source, but for few predicates and many source items, that takes less memory. Considers
no predicate to mean "reject all." Use only accept()/ConstBool.ACCEPT and ConstBool.REJECT since
function comparison is done by reference.
@param in the predicates to test in order. Nulls and ConstBool.REJECT predicates are ignored. Any
ACCEPT predicate will cause this entire method to return the ACCEPT predicate.
No predicates means ConstBool.REJECT.
@param the type of object to predicate on.
@return a predicate which returns true if any of the input predicates return true,
false otherwise.
*/
static Function1 or(Iterable> in) {
if (in == null) { return reject(); }
Transformable> v =
(in instanceof UnmodIterable) ? (UnmodIterable>) in
: Xform.of(in);
return v.filter(p -> (p != null) && (p != ConstBool.REJECT))
.foldLeft(reject(),
(accum, p) -> (p == ConstBool.ACCEPT) ? p : or(accum, p),
accum -> accum == ConstBool.ACCEPT);
}
enum BooleanCombiner {
AND {
@Override
public Function1 combine(Iterable> in) {
return and(in);
}
},
OR {
@Override
public Function1 combine(Iterable> in) {
return or(in);
}
};
public abstract Function1 combine(Iterable> in);
}
/**
Use only on pure functions with no side effects. Wrap an expensive function with this and for
each input value, the output will only be computed once. Subsequent calls with the same input
will return identical output very quickly. Please note that the return values from f need to
implement equals() and hashCode() correctly for this to work correctly and quickly.
*/
static Function1 memoize(Function1 f) {
return new Function1 () {
private final Map > memo = new HashMap<>();
@Override
public synchronized B applyEx(A a) throws Exception {
Option val = memo.get(a);
if ( (val != null) && val.isSome() ) { return val.get(); }
B ret = f.apply(a);
memo.put(a, Option.of(ret));
return ret;
}
};
}
// ========================================= Instance =========================================
/** Implement this one method and you don't have to worry about checked exceptions. */
U applyEx(T t) throws Exception;
/** Call this convenience method so that you don't have to worry about checked exceptions. */
@Override default U apply(T t) {
try {
return applyEx(t);
} catch (RuntimeException re) {
throw re;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/** For compatibility with java.util.function.Consumer. Just a wrapper around apply(). */
@Override default void accept(T t) { apply(t); }
@SuppressWarnings("unchecked")
default Function1 compose(final Function1 super S, ? extends T> f) {
if (f == Const.IDENTITY) {
// This violates type safety, but makes sense - composing any function with the
// identity function should return the original function unchanged. If you mess up the
// types, then that's your problem. With generics and type erasure this may be the
// best you can do.
return (Function1) this;
}
final Function1 parent = this;
return s -> parent.applyEx(f.applyEx(s));
}
}