This question already has answers here:
Is there a way to compare lambdas?
(3 answers)
Closed 7 years ago.
I am not sure how I can be sure about equality/immutability of functional interface.
I guess there might be no way to assure equality when I use this syntactic sugar in java 8, please let me know any hint if you have any.
I made a short code snippet for my question.
public interface Element {
void doSomething(int a);
}
and I've tried to add instance of this interface in functional way
public class FunctionSet {
public void doubleUp(int a) {
System.out.println(a*2);
}
public void square(int a) {
System.out.println(a*a);
}
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
FunctionSet functionSet = new FunctionSet();
set.add(functionSet::doubleUp);
set.add(functionSet::square);
System.out.println(set.add(functionSet::doubleUp));
}
}
it prints true which means there were not any equality check and also I can't remove any instance from Set once I add it.
in case I use functional interface as an argument, Is there any way that I can compare those instance somehow?
will appreciate any help, thanks in advance!
You can store your method reference into a variable:
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
FunctionSet functionSet = new FunctionSet();
Element fn = functionSet::doubleUp;
set.add(fn);
set.add(functionSet::square);
System.out.println(set.add(fn));
}
This way it returns false.
When you create the same labmda or method reference in different code locations, it's roughly the same as you would create a new anonymous class in both positions:
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
FunctionSet functionSet = new FunctionSet();
set.add(new Element() {
#Override
public void doSomething(int a) {
functionSet.doubleUp(a);
}
});
set.add(new Element() {
#Override
public void doSomething(int a) {
functionSet.square(a);
}
});
System.out.println(set.add(new Element() {
#Override
public void doSomething(int a) {
functionSet.doubleUp(a);
}
}));
}
So every time it's a different object, though it may look the same. For every encountered method reference separate anonymous class is created at the runtime:
Element e1 = functionSet::doubleUp;
Element e2 = functionSet::doubleUp;
System.out.println(e1.getClass());
System.out.println(e2.getClass());
The output will be like this:
class FunctionSet$$Lambda$1/918221580
class FunctionSet$$Lambda$2/1554547125
So practically it's two distinct objects of two distinct classes. It would be quite difficult to conclude that they do the same thing without comparing their bytecode. Also note that they both capture the functionSet variable, so it should also be ensured that it wasn't changed between two method references.
The only workaround I can think up is to declare all the method references as constants in your code and later reference them instead of using method references directly:
public static final Element FN_DOUBLE_UP = new FunctionSet()::doubleUp;
public static final Element FN_SQUARE = new FunctionSet()::square;
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
set.add(FN_DOUBLE_UP);
set.add(FN_SQUARE);
System.out.println(set.add(FN_DOUBLE_UP));
}
Related
I am wondering if ya'll can help me get a better grip on generics.
I have simplified this question as much as possible.
I am trying to save the element stored in a linked list in a variable called saveIt. I know LinkedList itself uses generics, so I want my variable to take up whatever data type is in the list. I believe LinkedList itself designates that type as E, but when I try to declare a variable as 'E saveIt' I get "cannot resolve symbol E."
public class Main {
public static void main(String[] args) {
// whatever goes here ...
}
void saveElement(LinkedList input) {
E saveIt = input.getFirst();
}
}
If I make the LinkedList then I can declare a variable as 'Integer saveIt' but that isn't what I want to do.
public class Main {
public static void main(String[] args) {
// whatever goes here ...
}
void saveElement(LinkedList<Integer> input) {
Integer saveIt = input.getFirst();
}
}
I considered declaring 'Object saveIt' but I'm not sure whether that is the right approach. The concept of datatype E obviously exists in Java, and isn't quite the same as Object (or is it?), so why can't I access it (or how can I access it)?
public class Main {
public static void main(String[] args) {
// whatever goes here ...
}
void saveElement(LinkedList input) {
Object saveIt = input.getFirst();
}
}
So, basic question is if I want to have my method address whatever datatype is in the list, how do I do that?
<E> void saveElement(LinkedList<E> input) {
E saveIt = input.getFirst();
}
You need to tell Java that E is a type parameter of your method -- it's like another thing that's being passed in! -- and that the LinkedList contains elements of type E.
I would like to create a class that store a list of methods references and then executes all of them using Java 8 Lambda but I have some problem.
This is the class
public class MethodExecutor {
//Here I want to store the method references
List<Function> listOfMethodsToExecute = new LinkedList<>();
//Add a new function to the list
public void addFunction(Function f){
if(f!=null){
listOfMethodsToExecute.add(f);
}
}
//Executes all the methods previously stored on the list
public void executeAll(){
listOfMethodsToExecute.stream().forEach((Function function) -> {
function.apply(null);
}
}
}
This is the class that I created for test
public class Test{
public static void main(String[] args){
MethodExecutor me = new MethodExecutor();
me.addFunction(this::aMethod);
me.executeAll();
}
public void aMethod(){
System.out.println("Method executed!");
}
}
But there is something wrong when I pass this::aMethod using me.addFunction.
What is wrong?
You should provide a suitable functional interface which abstract method signature is compatible with your method reference signature. In your case it seems that Runnable instead of Function should be used:
public class MethodExecutor {
List<Runnable> listOfMethodsToExecute = new ArrayList<>();
//Add a new function to the list
public void addFunction(Runnable f){
if(f!=null){
listOfMethodsToExecute.add(f);
}
}
//Executes all the methods previously stored on the list
public void executeAll(){
listOfMethodsToExecute.forEach(Runnable::run);
}
}
Also note that in static main method this is not defined. Probably you wanted something like this:
me.addFunction(new Test()::aMethod);
You can't refer to this in a static context as there is no this
me.addFunction(this::aMethod);
You need to refer to an instance or define your Function to take a Test object.
public void addFunction(Function<Test, String> f){
if(f!=null){
listOfMethodsToExecute.add(f);
}
}
and
me.addFunction(Test::aMethod);
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
Following Question. I have a big amount of ArrayList attributes (basically the same as Kreuzlagerort20kg etc). Instead of initializing them all in the constructor (the part commented out) i'd love to initialize them inside the fillLager() method, making it possible to call the method inside the constructor and have them initialized and filled then. If i do it in the code, i always get a nullpointerexception.
Is it possible and/or sensible to initialize an arraylist inside a method, without getting said nullpointer?
import java.util.ArrayList;
public class Lager {
private ArrayList<Screws> KreuzLagerort20kg,KreuzLagerort50kg;
public Lager(){
//KreuzLagerort20kg = new ArrayList<Screws>();
//KreuzLagerort50kg = new ArrayList<Screws>();
fillLager(1,KreuzLagerort20kg,20);
fillLager(1,KreuzLagerort50kg,50);
}
public void fillLager(int typ,ArrayList<Screws> lager,double lagerGewicht){
lager = new ArrayList<Screws>();
// code that loops through combinations and adds them to the arraylist
}}}}}}
You can't call new on a variable passed into a method and still have the calling method refer to the original variable, as Java passes by reference. When you call new X() then there is a new reference and the method which called your other method will not know the variable is now pointing at another reference...
e.g.
public void methodA() {
String s = new String("AAAAA");
methodB(s);
System.out.println(s);
}
public void methodB(String referredString) {
referredString = new String("BBBBB");
}
calling methodA will print "AAAAA"
You will need to initialise in the constructor, or make the method return the variables you passed in...
public void methodA() {
String s = new String("AAAAA");
s = methodB(s);
System.out.println(s);
}
public String methodB(String referredString) {
referredString = new String("BBBBB");
return referredString ;
}
calling methodA will now print "BBBBB"
Alternatively - make the string declared outside of either method and don't pass it around at all... e.g.
String s = new String("AAAAA");
public void methodA() {
methodB();
System.out.println(s);
}
public void methodB() {
s = new String("BBBBB");
}
will also yield "BBBBB"
You can do it like this:
Instead of normally initializing it (like KreuzLagerort20kg = new ArrayList<Screws>();) in constructor, you do it in fillLager.
import java.util.ArrayList;
public class Lager {
private ArrayList<Screws> KreuzLagerort20kg,KreuzLagerort50kg;
public Lager(){
//KreuzLagerort20kg = new ArrayList<Screws>();
//KreuzLagerort50kg = new ArrayList<Screws>();
fillLager(1, 20);
fillLager(1, 50);
}
public void fillLager(int typ, int code){
if (code==20){
KreuzLagerort20kg = new ArrayList<Screws>();
}
if (code==50){
KreuzLagerort50kg = new ArrayList<Screws>();
}
// code that loops through combinations and adds them to the arraylist
}}}}}}
I have a function e.g.
helloworld(list<object> names)
I have the following code :
List<CustomClass> newMe = new ArrayList<CustomClass>();
Now, if i want to pass newMe into helloworld(newMe);. This is not possible because im down casting. How can i overcome this issue? Do i downcast my list to (Object) and then try to upcast it? is there another way? would appreciate an example.
thanks
Change the definition of helloworld to
public void helloworld(List<?> names) {
//method implementation...
}
Take into account that your method won't be able to add or remove elements from the list parameter.
Just use a ? as generic type in your parameter list. Example:
public class Foobar {
public static void helloworld(List<?> names) {
}
public static void main(String[] args) {
List<CustomClass> newMe = new ArrayList<>();
helloworld(newMe);
}
}
public class test {
public static void main(String[] args) throws Exception {
final int num = 111;
new Thread() {
#Override
public void run() {
num = 222;
}
}.start();
}
}
I want to change the value of num however I can only do that if I set it to final which would not let me modify this. In other languages such as C we can use pointers but Java cannot?
Java has neither closure nor pointers.
A solution would be to make the num static in the class :
public class test {
static int num = 111;
public static void main(String[] args) throws Exception {
new Thread() {
#Override
public void run() {
num = 222;
}
}.start();
}
}
Another solution would be to use an object like AtomicInteger. You can't change the value of the variable but you can change the content of the value :
public class test {
public static void main(String[] args) throws Exception {
final AtomicInteger num = new AtomicInteger(111);
new Thread() {
#Override
public void run() {
num.set(222);
}
}.start();
}
}
Why this isn't allowed
main is a method. As with other programming languages, when a method returns, all of the variables declared in its body go out of scope, and accessing them has undefined behavior. Under some circumstances, the memory location where they used to be will no longer be valid.
Obviously this is a problem. If you try to change num after main has returned, you might overwrite a portion of the stack that doesn't belong to num anymore. Java's response to this difficult situation is to introduce restrictions on how you can share variables: they must be final. Java can then safely locate them in such a way that reading them will produce consistent results even after the function has returned.
The C equivalent to this problem is storing and using the address of a local variable outside of its scope, something that all C programmers are taught to never do.
To get around it, declare num as a member of test, create an instance, and pass that to it. This removes the dependancy on a local variable, and thus removes the final restriction.
public class test
{
int num = 111;
public static void main(String[] args) throws Exception
{
test t = new test();
(new Thread(t) {
test mytest;
Thread(test t)
{
mytest = t;
}
#Override
public void run() {
mytest.num = 222;
}
}).start();
}
}
Well, you can access it if you declare variable outside the function. Like this:
public class test {
private static int num = 111;
public static void main(String[] args) throws Exception {
new Thread() {
#Override
public void run() {
num = 222;
}
}.start();
}
}
You are creating new Thread() { class as inner class. You can't access outer class variables without declaring them as final.
You can't change final variable references.
There are two ways you can do this,
1) Make num as static
2) Wrap num inside an object (You can update state of the object even though you define reference as final).
NOTE: Both are not thread safe.
Yep you can't win here! You need to set it final to be able to access it, but then you will not be able to modify it. You'll need to look at a different approach.