1.First of all 2. Understand the interface and its features to understand lambda expressions 3. How to use lambda expression 4. Conclusion
Hello. This is an article about lambda expressions newly added in Java 8.
By the way, the other day I got the Oracle certification Java SE8 Silver. Among them, there was a time when I mentioned the lambda expression added from Java 8. I got the impression that I couldn't understand it just by reading it in a book.
And even if I searched for and read an article about lambda expression on Qiita, what is written after all Because the contents of the reference book that is difficult to understand and what is written in the Java API are the same I thought few people really understood the benefits of lambda expressions.
So, this time, rather than what the lambda expression is, how to use the lambda expression. I wanted to write an article about its benefits.
That's why I will explain about lambda expressions from the next chapter, Before that, you need to understand the interface and its features once in order to understand lambda expressions.
Many articles written about lambda expressions are not clear to the author of the article.
I think it's because someone who fits into one of the above. So, in this article, I will first describe two points about the features of the interface and its advantages. It's about polymorphism and encapsulation.
Then the first point. About polymorphism.
By the way, what is an interface in Java? "* Defines only the types of variables and methods without describing the specific processing contents of the methods included in the class * * 1" is not it.
This alone does not come to a pin, so I will put a sample source.
PrintoutMessage.java
package sample;
public interface PrintoutMessage {
public void printSomeMessage(String message);
}
In the above sample source PrintoutMessage.java, there is a method called printSomeMessage and Only the argument type and variable name are defined. In this way, a method like printSomeMessage that defines only the method and its argument types and variable names Called an * abstract method . ( 2)
At this point, no processing is defined in the method called printSomeMessage, so You can't do anything with this method alone.
However, by implementing the interface in a class, you can write the process in that method. This also doesn't work, so check the sample code.
ConcretePrintMessage_Hello.java
package sample:ConcretePrintMessage_Hello.java
/* 1.Implement interface*/
public class ConcretePrintMessage_Hello implements PrintoutMessage {
@Override
/* 2.Represent the method of the implemented interface*/
public void printSomeMessage(String message) {
/* do some process */
/* do some process */
/* do some process */
/* do some process */
System.out.println(message + "Hello");
}
public static void main(String[] args) {
/* 3.Instantiation*/
ConcretePrintMessage_Hello p = new ConcretePrintMessage_Hello();
/* 4.Call the method*/
p.printSomeMessage("Welcome to Qiita,");
}
}
In ConcretePrintMessage_Hello.java above, by implementing the interface, The printSomeMessage method is made to display "message + Hello received as an argument". This time, I wrote only one line (System.out.println ();) for the sake of explanation. It is possible to have multiple processes as shown in the comments on the source. (* 3)
Up to this point, it has been found that the interface can be used by implementing the interface in a class, redefining the method in the implemented class (* 4), and describing the processing content.
However, with this alone, it would be "Why do you bother to use the interface? You should create the printSomeMessage method with ConcretePrintMessage_Hello.java without defining the interface?"
Let's take a look at another sample code to solve such a question.
ConcretePrintMessage_Goodbye.java
package sample;
/* 1.Implement interface*/
public class ConcretePrintMessage_Goodbye implements PrintoutMessage {
@Override
/* 2.Represent the method of the implemented interface*/
public void printSomeMessage(String message) {
/* do some process */
/* do some process */
/* do some process */
/* do some process */
System.out.println(message + "Goodbye");
}
public static void main(String[] args) {
/* 3.Instantiation*/
ConcretePrintMessage_Goodbye p = new ConcretePrintMessage_Goodbye();
/* 4.Call the method*/
p.printSomeMessage("See you again,");
}
}
This time, ConcretePrintMessage_Goodbye.java is used to display "message + Goodbye received as an argument" in the printSomeMessage method. There is only one difference from the previous ConcretePrintMessage_Hello.java. Whether to display "message + Hello received as an argument" or "message + Goodbye received as an argument".
Both have the same method name, printSomeMessage (String message) ;, but the same argument type and argument name, but the processing content is different. Have you heard of this?
Yes, this is "* polymorphism *". The benefits of polymorphism are not discussed here, but what we have learned so far is what an interface is. It's a way to achieve polymorphism. You can easily achieve polymorphism by defining an interface and implementing it. This is the first feature and advantage of the interface.
Next is the second point, encapsulation.
Now, I would like to add one method to ConcretePrintMessage_Goodbye.java.
ConcretePrintMessage_Goodbye.java
package sample;
/* 1.Implement interface*/
public class ConcretePrintMessage_Goodbye implements PrintoutMessage {
@Override
/* 2.Represent the method of the implemented interface*/
public void printSomeMessage(String message) {
/* do some process */
/* do some process */
/* do some process */
/* do some process */
System.out.println(message + "Goodbye");
}
public static void main(String[] args) {
/* 3.Instantiation*/
ConcretePrintMessage_Goodbye p = new ConcretePrintMessage_Goodbye();
/* 4.Call the method*/
p.printSomeMessage("See you again " + p.getMyName() + ", ");
}
/*Added method*/
private String getMyName() {
return "Tom";
}
}
The method added to ConcretePrintMessage_Goodbye.java is the getter getMyName () to get the name. The access modifier for this method is private, isn't it? Methods with the private modifier can only be referenced from the same class. Therefore, if you want to process only with that class, specify private as the access modifier. All you have to do is make it inaccessible from other classes. In this example, getting the name Tom by getMyName () is private because we want to do it only with ConcretePrintMessage_Goodbye.java.
On the other hand, the modifier of the method implemented in the interface is always public, so it can be accessed from all classes. Therefore, the abstract method defined in the interface can be used to implement what you want to process in common in all classes according to the class. Moreover, the method name used for the common process must be the same as the one defined in the interface. No matter who wrote the source, as long as you implement the interface, with a method of the same name Since common processing is performed, you can roughly imagine what it is doing at a glance.
This is encapsulation, and I've found that the interface helps to create the methods I want to access from all classes in doing the encapsulation.
These are the features of the interface and its advantages. (* 6)
So far, we know that the interface has the advantages of polymorphism and encapsulation, It feels like what the lambda expression has to do with it. To explain that, let's look at how to use the interface again. The sample source below is the same as the sample source above.
ConcretePrintMessage_Hello.java
package sample;
/* 1.Implement interface*/
public class ConcretePrintMessage_Hello implements PrintoutMessage {
@Override
/* 2.Represent the method of the implemented interface*/
public void printSomeMessage(String message) {
/* do some process */
/* do some process */
/* do some process */
/* do some process */
System.out.println(message + "Hello");
}
public static void main(String[] args) {
/* 3.Instantiation*/
ConcretePrintMessage_Hello p = new ConcretePrintMessage_Hello();
/* 4.Call the method*/
p.printSomeMessage("Welcome to Qiita,");
}
}
From the beginning I've been writing steps to use the interface for comments on the source, Isn't it annoying to take these four steps every time? (Lol) In an actual project, I write this for about 100 classes every time, so It's annoying to write this every time for 100 classes, even though the interface has its advantages.
Therefore, the lambda expression was born as a result of thinking "Isn't it easier to use the interface?"
… To put it bluntly, that's all for the lambda expression.
Let's check the sample code to see how easy it is to handle the interface!
ConcretePrintMessage_GoodMorning.java
package sample;
public class ConcretePrintMessage_GoodMorning {
public static void main(String[] args) {
PrintoutMessage p = (String message) -> {
/* do some process */
/* do some process */
/* do some process */
/* do some process */
System.out.println(message + "GoodMorning!!");
};
p.printSomeMessage("How's your sleep? ");
}
}
The procedure is considerably simplified compared to the previous source.
All you have to do is describe the processing content and call the method. The rest only mentions the specifications for lambda expressions that are commonplace in many places. If you look at the article, the lambda expression should be perfect. Especially for lambda expressions, to deal with the "functional interface" that I mentioned a little in this article. There are many specifications, so it is recommended to take a look around them.
Thank you for reading until the end. If you have any suggestions or questions, please leave a comment.
1 All interface fields are constants, and all methods are public.
2 An interface that has a single abstract method, such as PrintoutMessage.java, is also called a "functional interface".
3 Since there is a "functional interface", it is of course possible to return the return value after processing. (Generally, "functions" usually return a return value, although some functions do not return a return value ...)
4 When an interface is implemented, it is necessary to define "* concrete method *" that describes the processing contents of the abstract method defined in the interface on the implemented class.
5 Only access modifiers that are the same as or looser than the inheritance source can be added to the access modifiers of inherited and overridden methods.
6 For other detailed features, please refer to each site or book.
Recommended Posts