I have to programm regular expression with lambda expressions for the university. I got stuck by 2 methods in a method.
here is my code:
static String ausdruck = "abcd";
public static Function<String, String> Char = (c) -> {
return (ausdruck.startsWith(c)) ? ausdruck = ausdruck.substring(1,
ausdruck.length()) : "Value Error";
};
public static BiFunction<Function<String, String>,
Function<String, String>,
Function<String, String>>
And = (f1, f2) -> {return null;};
what I want to do in the And method is: Char(Char.apply("a")) -> I want to call the function f2 with the f1 as a parameter.
the Call of the And Method have to look like:
And.apply(Char.apply("a"), Char.apply("b"));
I guess this is what you want
Func<Str,Str> f = and( comsume("a"), consume("b") );
f.apply("abcd"); // "cd"
Func<Str,Str> consume(String x)
return input->{
if(input.startsWith(x)) return input.substring(x.length());
else throws new IllegalArgument()
};
Func<Str,Str> and(Fun<Str,Str> f1, Func<Str,Str> f2)
return input-> f2.apply(f1.apply(input))
and is not necessary though, see Function.andThen method
f = consume("a").andThen( consume("b) )
Unfortunately, there is no "curry"; otherwise, we could do this
f = consume2.curry("a") .andThen ( consume2.curry("b") );
static BiFunc<Str,Str,Str> consume2 = (input,x)-> {...return input.substring(x.length()); ..
It's better off if you design your own functional interfaces, with needed methods like curry.
interface F1
String apply(String);
F1 and(F1);
interface F2
String apply(String,String);
F1 curry(String);
If I understand the question correctly, you want to create a function that compones a new function, executing one function with the result of another function. The best way to do this in a lambda would be to return a new lambda.
Try something like this:
BiFunction<Function<String, String>, Function<String, String>, Function<String, String>> compose =
(f1, f2) -> (a -> f2.apply(f1.apply(a)));
Example:
Function<String, String> upper = s -> s.toUpperCase();
Function<String, String> twice = s -> s + s;
Function<String, String> upperTwice = compose.apply(upper, twice);
System.out.println(upperTwice.apply("foo"));
Output is FOOFOO.
Concerning your concrete example
the Call of the And Method have to look like:
And.apply(Char.apply("a"), Char.apply("b");
I do not know exactly what you are trying to do, but I don't think this will work, given your current implementation of Char. It seems like you want to compose a lambda to remove a with another to remove b, but instead Char.apply("a") will not create another function, but actually remove "a" from your ausdruck String! Instead, your Char lambda should probably also return another lambda, and that lambda should not modify some static variable, but take and return another String parameter.
Function<String, Function<String, String>> stripChar =
c -> (s -> s.startsWith(c) ? s.substring(1) : "ERROR");
Function<String, String> stripAandC = compose.apply(stripChar.apply("c"), stripChar.apply("a"));
System.out.println(stripAandC.apply("cash"));
Output is sh.
Finally, in case you want to use this with anything other than just String, it might make sense to make compose an actual method instead of a lambda, so you can make use of generics. Also, you can make this a bit simpler by using andThen:
public static <A, B, C> Function<A, C> compose(Function<A, B> f1, Function<B,C> f2){
return f1.andThen(f2);
}
Related
Let's say I have this code:
Map<String, String> map;
// later on
map.entrySet().stream().map(MyObject::new).collect(Collectors.toList());
And I have a MyObject Constructor which takes two arguments of type String.
I want to be able to do this but I cannot.
I know I can do e -> new MyObject(e.getKey(), e.getValue()) but prefer MyObject::new.
Similar code works for Set<String> and List<String> with one argument constructor of MyObject class.
use a lambda:
map.entrySet()
.stream()
.map(e -> new MyObject(e.getKey(), e.getValue()))
.collect(Collectors.toList());
otherwise the only way to use a method reference is by creating a function as such:
private static MyObject apply(Map.Entry<String, String> e) {
return new MyObject(e.getKey(), e.getValue());
}
then do something like:
map.entrySet()
.stream()
.map(Main::apply)
.collect(Collectors.toList());
Where Main is the class containing the apply method.
map.entrySet().stream().map(MyObject::new).collect(Collectors.toList()));
And I have a MyObject Constructor which takes two arguments of type String. I want to be able to do this but I cannot.
In map.entrySet().stream().map(...), Java is expecting a Function,
mapping one value to another value.
One value.
From the stream, the function receives a value of type Map.Entry<String, String>,
but your constructor takes two String arguments.
Java doesn't automagically expand a Map.Entry<String, String> to a pair of Strings to pass to your constructor.
You have to do that unwrapping manually.
The problem with the constructor is that it defines two parameters, while Function#apply demanded by Stream#map accepts only one.
You could write a static factory method for MyObject
class MyObject {
public static MyObject of(Map.Entry<String, String> e) {
return new MyObject(e.getKey(), e.getValue());
}
}
and refer to it like
map(MyObject::of)
Before you do so, ask yourself if one pretty-looking line in a plain processing chain somewhere is worthy of a new constructor or utility method.
Add a Map.Entry constructor
class MyObject {
private final String k;
private final String v;
MyObject(String s1, String s2) {
k = s1;
v = s2;
}
MyObject(Map.Entry<String, String> e) {
this(e.getKey(), e.getValue());
}
public String toString() {
return "key: " + k + ' ' + "value: " + v;
}
}
You will be able to call
List<MyObject> myObjectList = map.entrySet().stream().map(MyObject::new).collect(Collectors.toList());
I have a interface that takes a string and returns a transformed string
I have some classes that will transform in different ways.
Is there any way in Java to create a stream of those classes and make a transformation of a string.
For example:
class MyClass implements MyOperation {
String execute(String s) { return doSomething(s); }
}
class MyClass2 implements MyOperation {
String execute(String s) { return doSomething(s); }
}
ArrayList<MyClass> operations = new ArrayList<>();
operations.add(new MyClass());
operations.add(new MyClass2());
...
operations.stream()...
Can I make a stream of that in order to make lots of transformations for a single string? I thought about .reduce() but it is strict about the data types.
Your classes all implement methods that transform a String to a String. In other words, they can be represented by a Function<String,String>. They can be combined as follows and applied on a single String:
List<Function<String,String>> ops = new ArrayList<> ();
ops.add (s -> s + "0"); // these lambda expressions can be replaced with your methods:
// for example - ops.add((new MyClass())::execute);
ops.add (s -> "1" + s);
ops.add (s -> s + " 2");
// here we combine them
Function<String,String> combined =
ops.stream ()
.reduce (Function.identity(), Function::andThen);
// and here we apply them all on a String
System.out.println (combined.apply ("dididi"));
Output:
1dididi0 2
The ArrayList<MyClass> should be ArrayList<MyOperation> else the call to operations.add(new MyClass2()); would yield a compilation error.
That said you're looking for this overload of reduce:
String result = operations.stream().reduce("myString",
(x, y) -> y.execute(x),
(a, b) -> {
throw new RuntimeException("unimplemented");
});
"myString" is the identity value.
(x, y) -> y.execute(x) is the accumulator function to be applied.
(a, b) -> {... is the combiner function used only when the stream is parallel. So you need not worry about it for a sequential stream.
You may also want to read upon an answer I've posted a while back "Deciphering Stream reduce function".
How can I write the following function using Java 8?
private static final Function<String, Integer> EmpIdToInt = (id) -> {
return Integer.valueOf(ACI.generate("emp",id).revealId().intValue());
};
Is there a better way of writing this function in Java 8?
Can anyone help?
Is there a better way of writing this function in java 8??
you're already using the features of java 8 and yes you can make the code shorter by removing ( ) because there is only one param and removing { } because there is only one statement of execution.
you could simplify it like so:
private static final Function<String, Integer> EmpIdToInt = id -> Integer.valueOf(ACI.generate("emp",id).revealId().intValue());
Note: I take away private static final for printing page.
IF your revealId is an Integer you can simplified to :
Function<String, Integer> EmpIdToInt = id -> ACI.generate("emp",id).revealId();
OR when revealId is not an Integer, but a int will be auto-boxing to an Integer, so you can remove the Integer.valueOf method call:
Function<String, Integer> EmpIdToInt = id -> ACI.generate("emp",id)
.revealId().intValue();
OR you can using a curry method chaining the functions step by step:
Note: class X is where revealId method is declared, and class Y is where intValue method is declared.
// revealId is an Integer
Function<String, Integer> EmpIdToInt = curry(ACI::generate, "emp")
.andThen(X::revealId);
// revealId is not an Integer
Function<String, Integer> EmpIdToInt = curry(ACI::generate, "emp")
.andThen(X::revealId)
.andThen(Y::intValue);
private static <T, A, R> Function<T, R> curry(BiFunction<A, T, R> it, A arg) {
return other -> it.apply(arg, other);
}
lets say we a Predicate and a Function-Interface:
Function<String, String> function = null;
Predicate<String> predicate = null;
Now I want to give the Predicate-Interface a method reference where the return type is a boolean and in our case the parameter a string. But why the following method reference seems to be right:
Predicate<String> predicate = String::isEmpty;
The isEmpty-method has no String-Parameter,although the Predicate-Interface requires a String-Parameter. Why it is still right? Am I missing something?
Another Example: The Function interface returns in our case a String and takes a String as parameter. But the following method reference seems to be wrong:
Function<String, String> function = String::concat; //wrong
The Concat-Method has a String as Parameter and returns a String. Why its wrong?
Hopefully somebody can explain it to me.
When you use a method reference on an instance method, the method receiver becomes the first argument. So
String::isEmpty
is equivalent to
(String str) -> str.isEmpty()
and
String::concat
is equivalent to
(String a, String b) -> a.concat(b)
...which does not match the type of Function.
The reason why
Function<String, String> function = String::concat;
does not compile is because it is equivalent to (as Louis written)
Function<String, String> function = (String a, String b) -> a.concat(b);
while Function.apply(T t) takes only one argument (t) and you are passing a function that takes two arguments (a and b).
String::isEmpty can, in theory, mean one of two things.
A static method in the String class:
s -> String.isEmpty(s)
An instance method in the String class:
(String s) -> s.isEmpty()
Your case falls into #2.
Similarly, String::concat can mean one of two things:
(s1, s2) -> String.concat(s1, s2)
or
(String s1, String s2) -> s1.concat(s2) // Your case
(However, this is not a Function<String, String>, as it does not take precisely one argument. It is, however, a BinaryOperator<String>.)
I have a situation where I have
class A {
private B b;
public B getB() {
return b;
}
}
and another class B
class B {
private List<C> c;
public List<C> getListC() {
return c;
}
}
Now class C contains two instance variables
class C {
private int id;
private String name;
public int getId() {
return id;
}
public String getName() {
return name;
}
}
Now I want to achieve the below using java 8
List<C> newListC = a.getB().getListC();
Map<Integer, String> map = new HashMap<>();
for(C c : newListC) {
map.put(c.getId,c.getName());
}
I have tried many time but every time I face different problems.
My code:
Optional<A> a=Optional.of(new A());
Map<Integer, String> map= a.map(A::getB)
.flatMap(b ->
b.getListC()
.stream()
.collect(Collectors.toMap(
C::getId,
C::getName
)
)
);
Error message :
Error:(164, 33) java: incompatible types: no instance(s) of type
variable(s) U,R,A,capture#1 of ?,T,K,U exist so that
java.util.Optional<U> conforms to
java.util.Map<java.lang.Integer,java.lang.String>
Thanks in advance
Though I hit couple of compilation errors as I can see few typos, but
Try:
List<C> newListC= new A().getB().getListC();
Map<Integer, String> stringMap = newListC.stream()
.collect(Collectors
.toMap(C::getId, C::getName));
Provided that you fixed your compilation issues, it should be emitting result equivalent to non-stream version of map.
You can’t flatMap an Optional to a Map; the function has to return an Optional. On the other hand, since the function doesn’t return an Optional, a flatMap is unnecessary and an ordinary map will do:
Map<Integer, String> map = Optional.of(new A())
.map(A::getB)
.map(b -> b.getListC().stream().collect(Collectors.toMap(C::getId, C::getName)))
.orElse(Collections.emptyMap());
But since the result of new A() can’t be null (and using of instead of ofNullable acknowledges this), the indirect processing at the beginning of the chain is unnecessary:
Map<Integer, String> map = Optional.ofNullable(new A().getB())
.map(b -> b.getListC().stream().collect(Collectors.toMap(C::getId, C::getName)))
.orElse(Collections.emptyMap());
But note that only the nullability of the result of getB is handled, as the function passed to the next mapping step unconditionally invokes stream() on the list returned by getListC. But returning null where a List is expected is bad coding style anyway; you can always return an empty list to represent the absence of values.
Maybe your confusion stems from a Stream based alternative solution:
Map<Integer, String> map = Stream.of(new A().getB())
.filter(Objects::nonNull)
.flatMap(b -> b.getListC().stream())
.collect(Collectors.toMap(C::getId, C::getName));
Here, a stream consisting of at most one element is created, followed by flatMaping it to the items of the list returned by getListC…