Download full-text PDF. Ira R. Forman. Nate Forman. MANNING. Sample Chapter . Java Reflection in Action. by Ira R. Forman. and. You are a Java developer. You are asked to add a simple feature to your application. But "simple" can be deceiving: you have to make many changes. Java Reflection in Action Java Reflection in Action is unique in pr Ira R. Forman Nate Forman MANNING PRAISE FOR Java DOWNLOAD PDF.
|Language:||English, Japanese, Dutch|
|Genre:||Science & Research|
|ePub File Size:||17.37 MB|
|PDF File Size:||8.55 MB|
|Distribution:||Free* [*Sign up for free]|
(in Java) /~gibson/Teaching/CSC/adunsexanro.gq Java Reflection in Action (In Action Series). Manning Publications Co., Greenwich, CT. (in Java) /~gibson/Teaching/CSC/adunsexanro.gq . Java Reflection in Action (In Action Series). Manning Publications Co., Greenwich, CT. Java Reflection in Action (In Action series) [Ira R. Forman, Nate Forman] on adunsexanro.gq Explaining the Java Reflection API and providing techniques for using it Paperback: pages; Publisher: Manning Publications (October ).
Functions in Java Default methods Other good ideas from functional programming Passing code with behavior parameterization Coping with changing requirements Behavior parameterization Tackling verbosity Real-world examples Lambda expressions Lambdas in a nutshell Where and how to use lambdas Putting lambdas into practice: Using functional interfaces Type checking, type inference, and restrictions Method references Putting lambdas and method references into practice!
Useful methods to compose lambda expressions Similar ideas from mathematics Functional-style data processing Introducing streams What are streams? Getting started with streams Streams vs. Stream operations Working with streams Filtering and slicing Finding and matching Putting it all into practice Numeric streams Building streams Collecting data with streams Collectors in a nutshell Reducing and summarizing The Collector interface Developing your own collector for better performance Parallel data processing and performance Parallel streams Effective Java 8 programming Refactoring, testing, and debugging Refactoring for improved readability and flexibility Refactoring object-oriented design patterns with lambdas Testing lambdas Evolving APIs Default methods in a nutshell Usage patterns for default methods Resolution rules Using Optional as a better alternative to null How do you model the absence of a value?
Introducing the Optional class Patterns for adopting Optional Practical examples of using Optional Implementing an asynchronous API Make your code non-blocking Pipelining asynchronous tasks Reacting to a CompletableFuture completion Manipulating, parsing, and formatting dates Working with different time zones and calendars Beyond Java Thinking functionally Implementing and maintaining systems Recursion vs.
Functional programming techniques Functions everywhere Persistent data structures Lazy evaluation with streams Pattern matching Introduction to Scala Classes and traits Conclusions and where next for Java Review of Java 8 features The final word Miscellaneous language updates Generalized target-type inference Miscellaneous library updates Number and Math Performing multiple operations in parallel on a stream Forking a stream Performance considerations Lambdas and JVM bytecode Anonymous classes Bytecode generation InvokeDynamic to the rescue Code-generation strategies Fundamentals This first part of the book provides the fundamentals to help you get started with Java 8.
In chapter 1, we summarize the main changes to Java lambda expressions, method references, streams, and default methods and set the scene for the book. Chapter 3 gives a full explanation, with code examples and quizzes at every step, of the concepts of lambda expressions and method references. Its evolution via the addition of new features from Java 1. Java 8 was released in March So the question is this: We argue that the changes to Java 8 are in many ways more profound than any other changes to Java in its history.
The good news is that the changes enable you to write programs more easily—instead of writing verbose code like the following to sort a list of apples in inventory based on their weight , Collections. This book will explain what it does and how you can write similar code! But the vast majority of existing Java programs use only one of these cores and leave the other three idle or spend a small fraction of their processing power running part of the operating system or a virus checker.
The problem is that working with threads is difficult and error prone. Java has followed an evolutionary path of continually trying to make concurrency easier and less error prone.
Java 1. Java 5 added industrial-strength building blocks like thread pools and concurrent collections. Java 8 has a new, simpler way of thinking about parallelism. From these two examples more concise code and simpler use of multicore processors springs the whole consistent edifice that is Java 8. We start by giving you a quick taste of these ideas hopefully enough to intrigue you, but short enough to summarize them: As a result, it avoids the need for you to write code that uses synchronized, which is not only highly error prone but is also more expensive than you may realize on multicore CPUs.
Locking requires these to be synchronized, requiring relatively slow cache-coherency-protocol intercore communication. From a slightly revisionist viewpoint, the addition of Streams in Java 8 can be seen as a direct cause of the two other additions to Java 8: But thinking of passing code to methods as a mere consequence of Streams downplays its range of uses within Java 8.
It gives you a new concise way to express behavior parameterization. Suppose you want to write two methods that differ in only a few lines of code; you can now just pass the code of the parts that differ as an argument this programming technique is shorter, clearer, and less error prone than the common tendency to use copy and paste.
The Java 8 feature of passing code to methods and also being able to return it and incorporate it into data structures also provides access to a whole range of additional techniques that are commonly referred to as functional-style programming. The meat of this chapter begins with a high-level discussion on why languages evolve, continues with sections on the core features of Java 8, and then introduces the ideas of functional-style programming that the new features simplify using and that new computer architectures favor.
In essence, section 1. Section 1. Finally, section 1. In summary, this chapter introduces ideas that are successively elaborated in the rest of the book. Enjoy the ride! With the s came the quest for the perfect programming language. Peter Landin, famous computer scientist of his day, noted in in a landmark article that there had already been programming languages and speculated on what the next would be like—including arguments for functional-style programming similar to that in Java 8.
Many thousands of programming languages later, academics have concluded that programming languages behave like an ecosystem: We all hope for a perfect universal language, but in reality certain languages are better fitted for certain niches. Prior occupancy of a niche tends to discourage competitors.
Right from the start, it was a well-designed object-oriented language with many useful libraries. It also supported small-scale concurrency from day one, with its integrated support for threads and locks and with its early prescient acknowledgement, in the form of a hardware-neutral memory model, that concurrent threads on multicore processors can have unexpected behaviors in addition to those that happen on single-core processors.
Also, the decision to compile Java to JVM bytecode a virtual machine code that soon every browser supported meant that it became the language of choice for internet applet programs do you remember applets? Java has also been successful at colonizing various aspects of embedded computing everything from smartcards, toasters, and settop boxes to car braking systems.
How did Java get into a general programming niche? Object orientation became fashionable in the s for two reasons: This can be summarized as follows: But the climate is changing for the programming language ecosystem; programmers are increasingly dealing with so-called big data datasets of terabytes and up and wishing to exploit multicore computers or computing clusters effectively to process it.
Figure 1. Programming languages ecosystem and climate change The main benefit of Java 8 to a programmer is that it provides more programming tools and concepts to solve new or existing programming problems more quickly or, more importantly, in a more concise, more easily maintainable way. We highlight and develop the ideas behind three such programming concepts that have driven the development of the Java 8 features to exploit parallelism and write more concise code in general.
Stream processing The first programming concept is stream processing. For introductory purposes, a stream is a sequence of data items that are conceptually produced one at a time—a program might read items from an input stream one by one and similarly write items to an output stream. The output stream of one program could well be the input stream of another. One practical example is in Unix or Linux, where many programs operate by reading data from standard input stdin in Unix and C, System.
First, a little background: Unix cat creates a stream by concatenating two files, tr translates the characters in a stream, sort sorts lines in a stream, and tail -3 gives the last three lines in a stream.
We say that sort takes a stream of lines as input and produces another stream of lines as output the latter being sorted , as illustrated in figure 1. Note that in Unix the commands cat, tr, sort, and tail are executed concurrently, so that sort can be processing the first few lines before cat or tr has finished. A more mechanical analogy is a car-manufacturing assembly line where a stream of cars is queued between processing stations that each take a car, modify it, and pass it on to the next station for further processing; processing at separate stations is typically concurrent even though the assembly line is physically a sequence.
You can think of it as a fancy iterator for now. The Streams API has many methods that can be chained to form a complex pipeline just like Unix commands were chained in the previous example. The key motivation for this is that you can now program in Java 8 at a higher level of abstraction, structuring your thoughts of turning a stream of this into a stream of that similarly to how you think when writing database queries rather than one item at a time. Another advantage is that Java 8 can transparently run your pipeline of Stream operations on several CPU cores on disjoint parts of the input—this is parallelism almost for free instead of hard work using Threads.
Passing code to methods with behavior parameterization The second programming concept added to Java 8 is the ability to pass a piece of code to an API. This sounds awfully abstract. Although the sort command supports command-line parameters to perform various predefined kinds of sorting such as reverse order, these are limited.
The first four digits represent the year, the next two letters a country code, and last four digits the ID of a client. You may want to sort these invoice IDs by year or perhaps using the customer ID or even the country code.
What you really want is the ability to tell the sort command to take as an argument an ordering defined by the user: Now, as a direct parallel in Java, you want to tell a sort method to compare using a customized order. You could create a Comparator object to pass to the sort method as we showed at the start of this chapter, but this is verbose and obfuscates the idea of simply reusing an existing piece of behavior. Java 8 adds the ability to pass methods your code as arguments to other methods.
We also refer to this conceptually as behavior parameterization. Why is this important? The Streams API is built on the idea of passing code to parameterize the behavior of its operations, just as you passed compareUsingCustomerId to parameterize the behavior of sort. Passing method compareUsingCustomerId as an argument to sort We summarize how this works in section 1.
Java Reflection in Action
Chapters 13 and 14 look at more advanced things you can do using this feature, with techniques from the functional programming community. What do you have to give up? You may have to make some small changes in the way you code the behavior passed to stream methods. You must provide behavior that is safe to execute concurrently on different pieces of the input.
The previous parallelism arises only by assuming that multiple copies of your piece of code can work independently. Using synchronized across multiple processing cores is often far more expensive than you expect, because synchronization forces code to execute sequentially, which works against the goal of parallelism.
In contrast, in the imperative programming paradigm you typically describe a program in terms of a sequence of statements that mutate state.
The no-shared-mutable-data requirement means that a method is perfectly described solely by the way it transforms arguments to results; in other words, it behaves as a mathematical function and has no visible side effects. Other changes have made common things easier to express, for example, using a for-each loop instead of exposing the boilerplate use of an Iterator. Note that classical object-oriented programming and functional programming, as extremes, might appear to be in conflict.
But the idea is to get the best from both programming paradigms, so you have a better chance of having the right tool for the job!
We discuss this in detail in the next two sections: A takeaway line might be this: To endure, Java has to evolve by adding new features. Additionally, the new Java 8 features might, in the ecosystem analogy, enable Java to conquer programming-task territory currently occupied by other languages, so Java 8 programmers will be even more in demand.
We now introduce the new concepts in Java 8, one by one—pointing out on the way the chapters that cover these concepts in more detail. Functions in Java The word function in programming languages is commonly used as a synonym for method, particularly a static method; this is in addition to it being used for mathematical function, one without side effects.
Java 8 adds functions as new forms of value. These facilitate the use of Streams, covered in section 1. We start by showing that functions as values are useful in themselves. Think about the possible values manipulated by Java programs. First, there are primitive values such as 42 of type int and 3. Second, values can be objects more strictly, references to objects. The only way to get one of these is by using new, perhaps via a factory method or a library function; object references point to instances of a class.
Even arrays are objects. Values as listed previously are first-class Java citizens, but various other Java concepts, such as methods and classes, exemplify second-class citizens. Methods are fine when used to define classes, which in turn may be instantiated to produce values, but neither are values themselves. So does this matter? Yes, it turns out that being able to pass methods around at run-time, and hence making them first-class citizens, is very useful in programming, and so the Java 8 designers added this ability to Java.
Methods and lambdas as first-class citizens Experiments in other languages such as Scala and Groovy have determined that allowing concepts like methods to be used as first-class values made programming easier by adding to the toolset available to programmers. And once programmers become familiar with a powerful feature, they become reluctant to use languages without it!
So the designers of Java 8 decided to allow methods to be values—to make it easier for you to program. Moreover, the Java 8 feature of methods as values forms the basis of various other Java 8 features such as Streams. The first new Java 8 feature we introduce is that of method references. Suppose you want to filter all the hidden files in a directory. It can be viewed as a function that takes a File and returns a boolean. But to use it for filtering you need to wrap it into a FileFilter object that you then pass to the File.
You already have a method isHidden that you could use. Why do you have to wrap it up in a verbose FileFilter class and then instantiate it? Now, in Java 8 you can rewrite that code as follows: You already have the function isHidden available, so you just pass it to the listFiles method using the Java 8 method reference:: One advantage is that your code now reads closer to the problem statement.
Analogously to using an object reference when you pass an object around and object references are created by new , in Java 8 when you write File:: This concept is discussed in detail in chapter 3. Given that methods contain code the executable body of a method , then using method references enables passing code around as in figure 1. Passing the method reference File:: Chapter 3 explores lambdas in detail.
Passing code: Suppose you have a class Apple with a method getColor and a variable inventory holding a list of Apples; then you might wish to select all the green apples and return them in a list.
The word filter is commonly used to express this concept. Before Java 8, you thus might write a method filterGreenApples: We all know the dangers of copy and paste for software engineering updates and bug fixes to one variant but not the other , and hey, these two methods vary only in one line: If the difference between the two method calls in the highlighted code had been simply as to what weight range was acceptable, then you could have just passed lower and upper acceptable weights as arguments to filter—perhaps , to select heavy apples over g or 0, 80 to select light apples under 80 g.
But as we mentioned previously, Java 8 makes it possible to pass the code of the condition as an argument, thus avoiding code duplication of the filter method. You can now write this: The key idea to take away for now is that you can pass around a method in Java 8!
The previous code passed a method Apple:: The word predicate is often used in mathematics to mean something function-like that takes a value for an argument and returns true or false.
But Java 8 has solved this too. Code clarity should be your guide. The Java 8 designers could almost have stopped here, and perhaps they would have done so before multicore CPUs! Java 8 instead contains a whole new Collections-like API called Streams, containing a comprehensive set of operations similar to filter that functional programmers may be familiar with for example, map, reduce , along with methods to convert between Collections and Streams, which we now investigate.
Streams Nearly every Java application makes and processes collections. Using the Streams API, you can solve this problem as follows: Chapters 4—7 are dedicated to explaining how to make sense of the Streams API.
You need to iterate through each element one by one using a for-each loop and then process the elements. We call this way of iterating over data external iteration.
The data processing happens internally inside the library. We call this idea internal iteration. We come back to these ideas in chapter 4. As a second pain point of working with collections, think for a second about how you would process the list of transactions if you had a vast number of them; how can you process this huge list?
In theory, if you have eight cores, they should be able to process your data eight times as fast as using one core because they work in parallel. Each of the cores in a multicore chip is a full-fledged CPU. Multicore All new desktop and laptop computers are multicore computers. The problem is that a classic Java program uses just a single one of these cores, and the power of the others is wasted.
Similarly, many companies use computing clusters computers connected together with fast networks to be able to process vast amounts of data efficiently. Java 8 facilitates new programming styles to better exploit such computers. It reads every page on the internet and creates an index, mapping every word appearing on any internet page back to every URL containing that word.
Then, when you do a Google search involving several words, software can quickly use this index to give you a set of web pages containing those words. Multithreading is difficult The problem is that exploiting parallelism by writing multithreaded code using the Threads API from previous versions of Java is difficult.
You have to think differently: This model is harder to think about than a step-by-step sequential model. For example, figure 1. A possible problem with two threads trying to add to a shared sum variable. The result is instead of an expected result of Java 8 also addresses both problems boilerplate and obscurity involving processing collections and difficulty leveraging multicore with the Streams API java.
The first design motivator is that there are many data processing patterns similar to filterApples in the previous section, or operations familiar from database query languages such as SQL that occur over and over again and that would benefit from forming part of a library: The second motivator is that such operations can often be parallelized. For instance, as illustrated in figure 1. The CPUs then filter their respective half-lists 2.
Finally 3 , one CPU would join the two results this is closely related to how Google searches work so quickly, of course using many more than two processors. The key point here is that Streams allows and encourages the elements within a Stream to be processed in parallel. Although it may seem odd at first, often the fastest way to filter a Collection using filterApples on a List in the previous section is to convert it to a Stream, process it in parallel, and then convert it back to a List, as exemplified here for both the serial and parallel cases.
Sequential processing: One of the practical issues the Java 8 developers found in evolving Java with all these new goodies was that of evolving existing interfaces. For example, the method Collections.
This may seem trivial but, prior to Java 8, you can update an interface only if you update all the classes that implement it—a logistic nightmare! This issue is resolved in Java 8 by default methods. Parallelism in Java and no shared mutable state People have always said parallelism in Java is difficult, and all this stuff about synchronized is error prone.
There are actually two magic bullets. First, the library handles partitioning—breaking down a big stream into several smaller streams to be processed in parallel for you. But it turns out that this restriction feels quite natural as a coder see, by way of example, our Apple:: Default methods Default methods are added to Java 8 largely to support library designers by enabling them to write more evolvable interfaces.
We cover them in detail in chapter 9. In section 1. The simplest solution, which you might employ for your own interfaces, would have been for the Java 8 designers simply to add the stream method to the Collection interface and add the implementation in the ArrayList class. But doing this would have been a nightmare for users. There are many alternative collection frameworks that implement interfaces from the Collections API.
Adding a new method to an interface means all concrete classes must provide an implementation for it. Language designers have no control on all existing implementations of Collections, so you have a bit of a dilemma: So who implements them? The missing method bodies are given as part of the interface hence default implementations rather than in the implementing class. This provides a way for an interface designer to enlarge an interface beyond those methods that were originally planned—without breaking existing code.
Java 8 uses the new default keyword in the interface specification to achieve this.
For example, in Java 8 you can now call the sort method directly on a List. This is made possible with the following default method in the Java 8 List interface, which calls the static method Collections. But wait a second—a single class can implement multiple interfaces, right?
So if you have multiple default implementations in several interfaces, does that mean you have a form of multiple inheritance in Java? Yes, to some extent! Other good ideas from functional programming The previous sections introduced two core ideas from functional programming that are now part of Java: Both of these ideas are exploited by the new Streams API we described earlier.
One of these is avoiding null by explicit use of more descriptive data types. Indeed, Tony Hoare, one of the giants of computer science, said in a presentation at QCon London I call it my billion-dollar mistake.
It was the invention of the null reference in In other words, it uses the type system to allow you to indicate when a variable is anticipated to potentially have a missing value. A second idea is that of structural pattern matching. Here we mean the one familiar from mathematics and functional programming whereby a function is defined by cases, rather than using if-then-else. Other languages have shown that, for more complex data types, pattern matching can express programming ideas more concisely compared to using if-then-else.
In the meantime, we illustrate with an example expressed in the Scala programming language another Java-like language using the JVM that has inspired some aspects of Java evolution; see chapter Suppose you want to write a program that does basic simplifications on a tree representing an arithmetic expression.
Given a data type Expr representing such expressions, in Scala you can write the following code to decompose an Expr into its parts and then return another Expr: For now, you can think of pattern matching as an extended form of switch that can decompose a data type into its components at the same time.
Why should the switch statement in Java be limited to primitive values and Strings? Functional languages tend to allow switch to be used on many more data types, including allowing pattern matching in the Scala code, this is achieved using a match operation.
In object-oriented design, the visitor pattern is a common pattern used to walk through a family of classes such as the different components of a car: You forgot to explicitly deal with it. This material is positioned toward the end of the book to provide additional insight into why the new Java 8 features were added. Summary Following are the key concepts you should take away from this chapter: Although Java may be supremely healthy at the moment, you can recall other healthy languages such as COBOL that failed to evolve.
Comparator, Runnable, and GUI A well-known problem in software engineering is that no matter what you do, user requirements will change. For example, imagine an application to help a farmer understand his inventory. The farmer might want a functionality to find all green apples in his inventory. In addition, similar new functionalities ought to be straightforward to implement and maintainable in the long term. Behavior parameterization is a software development pattern that lets you handle frequent requirement changes.
In a nutshell, it means taking a block of code and making it available without executing it. This block of code can be called later by other parts of your programs, which means that you can defer the execution of that block of code. For instance, you could pass the block of code as an argument to another method that will execute it later.
So you can tell him to download a list of things such as bread, cheese, and wine. This is equivalent to calling a method goAnddownload with a list of products as argument. You could pass him the list of instructions by email, and when he receives it, he can go ahead and follow the instructions. We start the chapter by walking you through an example of how you can evolve your code to be more flexible for changing requirements. Building on this knowledge, we show how to use behavior parameterization for several real-world examples.
For example, you may have already used the behavior parameterization pattern using existing classes and interfaces in the Java API to sort a List, to filter names of files, or to tell a Thread to execute a block of code or even perform GUI event handling.
Lambda expressions in Java 8 tackle the problem of verbosity. We show in chapter 3 how to construct lambda expressions, where to use them, and how you can make your code more concise by adopting them. Coping with changing requirements Writing code that can cope with changing requirements is difficult. In the context of a farm-inventory application, you have to implement a functionality to filter green apples from a list. Sounds easy, right? First attempt: The highlighted line shows the condition required to select green apples.
But now the farmer changes his mind and wants to also filter red apples. What can you do? A good principle is this: Second attempt: Too easy, right? Heavy apples typically have a weight greater than g.
What if you want to alter the filter traversing to enhance performance? You now have to modify the implementation of all of your methods instead of a single one.
This is expensive from an engineering effort perspective. You could combine the color and weight into one method called filter. You could add a flag to differentiate between color and weight queries. But never do this! Third attempt: This solution is extremely bad. First, the client code looks terrible. What do true and false mean? What if the farmer asks you to filter with different attributes of an apple, for example, its size, its shape, its origin, and so on?
Furthermore, what if the farmer asks you for more complicated queries that combine attributes, such as green apples that are also heavy?
This can be fine for certain well-defined problems. But in this case what you need is a better way to tell your filterApples method the selection criteria for apples. In the next section we describe how to make use of behavior parameterization to attain that flexibility.
Behavior parameterization You saw in the previous section that you need a better way than adding lots of parameters to cope with changing requirements.
One possible solution is to model your selection criteria: We call this a predicate that is, a function that returns a boolean. Figure 2. What you just did is related to the strategy design pattern, which lets you define a family of algorithms, encapsulate each algorithm called a strategy , and select an algorithm at run-time.
But how can you make use of the different implementations of ApplePredicate? You need your filterApples method to accept ApplePredicate objects to test a condition on an Apple. This is what behavior parameterization means: To achieve this in the running example, you add a parameter to the filterApples method to take an ApplePredicate object.
This has a great software engineering benefit: Fourth attempt: You can now create different ApplePredicate objects and pass them to the filterApples method.
Free flexibility! For example, if the farmer asks you to find all red apples that are heavier than g, all you need to do is create a class that implements the ApplePredicate accordingly. Your code is now flexible enough for any change of requirements involving the attributes of Apple: Note that in the previous example, the only code that really matters is the implementation of the test method, as illustrated in figure 2. Unfortunately, because the filterApples method can only take objects, you have to wrap that code inside an ApplePredicate object.
Parameterizing the behavior of filterApples and passing different filter strategies Multiple behaviors, one parameter As we explained earlier, behavior parameterization is great because it enables you to separate the logic of iterating the collection to filter and the behavior to apply on each element of that collection.
As a consequence, you can reuse the same method and give it different behaviors to achieve different things, as illustrated in figure 2. This is why behavior parameterization is a useful concept you should have in your toolset for creating flexible APIs. Parameterizing the behavior of filterApples and passing different filter strategies To make sure you feel comfortable with the idea of behavior parameterization, have a go at Quiz 2.
Quiz 2. Write a flexible prettyPrintApple method Write a prettyPrintApple method that takes a List of Apples and that can be parameterized with multiple ways to generate a String output from an apple a bit like multiple customized toString methods. For example, you could tell your pretty-PrintApple method to print only the weight of each apple.
To help you get started, we provide a rough skeleton of the prettyPrintApple method: First, you need a way to represent a behavior that takes an Apple and returns a formatted String result. You did something similar when you created an ApplePredicate interface: You can do this by adding a parameter to prettyPrintApple: You do this by instantiating implementations of AppleFormatter and giving them as arguments to prettyPrintApple: Or try this: Behavior parameterization: Java has a mechanism called anonymous classes, which let you declare and instantiate a class at the same time.
They enable you to improve your code one step further by making it a little more concise. Section 2. They allow you to declare and instantiate a class at the same time. In other words, they allow you to create ad hoc implementations. Fifth attempt: First, they tend to be very bulky because they take a lot of space, as shown in the highlighted code here using the same two examples used previously: Second, many programmers find them confusing to use.
For example, Quiz 2. Try your hand at it. Anonymous class puzzler What will the output be when this code is executed: The answer is 5, because this refers to the enclosing Runnable, not the enclosing class MeaningOfThis. Good code should be easy to comprehend at a glance. In the context of passing a simple piece of code for example, a boolean expression representing a selection criterion , you still have to create an object and explicitly implement a method to define a new behavior for example, the method test for Predicate or the method handle for EventHandler.
Sixth attempt: Behavior parameterization vs. Seventh attempt: At the moment, the filterApples method works only for Apple. This pattern lets you encapsulate a behavior a piece of code and parameterize the behavior of methods by passing and using these behaviors you create for example, different predicates for an Apple.
We mentioned earlier that this approach is similar to the strategy design pattern. You may have already used this pattern in practice. Many methods in the Java API can be parameterized with different behaviors. These methods are often used together with anonymous classes.
We show three examples, which should solidify the idea of passing code for you: Sorting with a Comparator Sorting a collection is a recurring programming task. For example, say your farmer wants you to sort the inventory of apples based on their weight. Sound familiar? Yes, you need a way to represent and use different sorting behaviors to easily adapt to changing requirements. In Java 8, a List comes with a sort method you could also use Collections. The behavior of sort can be parameterized using a java.
Comparator object, which has the following interface: For example, you can use it to sort the inventory by increasing weight using an anonymous class: The internal details of how to sort are abstracted away.
With a lambda expression it would look like this: Executing a block of code with Runnable Threads are like a lightweight process: But how can you tell a thread what block of code to run? Several threads may run different code. What you need is a way to represent a piece of code to be executed later. In Java, you can use the Runnable interface to represent a block of code to be executed; note that the code will return no result that is, void: GUI event handling A typical pattern in GUI programming is to perform an action in response to a certain event such as clicking or hovering over text.
For example, if the user clicks the Send button, you may wish to display a popup or perhaps log the action in a file. Again, you need a way to cope with changes; you should be able to perform any response. Anonymous classes helped a bit before Java 8 to get rid of the verbosity associated with declaring multiple concrete classes for an interface that are needed only once.
It lets you define a block of code that represents a behavior and then pass it around. But you saw that using anonymous classes to represent different behaviors is unsatisfying: In this chapter, we teach you about a new feature in Java 8 that tackles this problem: For now you can think of lambda expressions as anonymous functions, basically methods without declared names, but which can also be passed as arguments to a method as you can with an anonymous class.
We show how to construct them, where to use them, and how you can make your code more concise by using them. We also explain some new goodies such as type inference and new important interfaces available in the Java 8 API. Finally, we introduce method references, a useful new feature that goes hand in hand with lambda expressions. This chapter is organized in such a way as to teach you step by step how to write more concise and flexible code. At the end of this chapter, we bring together all the concepts taught into a concrete example: Lambdas in a nutshell A lambda expression can be understood as a concise representation of an anonymous function that can be passed around: But like a method, a lambda has a list of parameters, a body, a return type, and a possible list of exceptions that can be thrown.
Why should you care about lambda expressions? You saw in the previous chapter that passing code is currently tedious and verbose in Java. Well, good news! Lambdas fix this problem: But you no longer have to write clumsy code using anonymous classes to benefit from behavior parameterization! Lambda expressions will encourage you to adopt the style of behavior parameterization that we described in the previous chapter.
The net result is that your code will be clearer and more flexible. For example, using a lambda expression you can create a custom Comparator object in a more concise way. We explain in the next section exactly where and how you can use lambda expressions. The lambda we just showed you has three parts, as shown in figure 3. Figure 3.
A lambda expression is composed of parameters, an arrow, and a body. To illustrate further, the following listing shows five examples of valid lambda expressions in Java 8. Listing 3.
Working through Quiz 3. Quiz 3. Lambda syntax Based on the syntax rules just shown, which of the following are not valid lambda expressions? Only 4 and 5 are invalid lambdas.
This lambda has no parameters and returns void. This lambda has no parameters and returns a String as an expression. This lambda has no parameters and returns a String using an explicit return statement.
To make this lambda valid, curly braces are required as follows: To make this lambda valid, you can remove the curly braces and semicolon as follows: Or if you prefer, you can use an explicit return statement as follows: Table 3. You could also use another lambda with the filter method you implemented in the previous chapter: You can use a lambda expression in the context of a functional interface.
Because Predicate specifies only one abstract method: You already know several other functional interfaces in the Java API such as Comparator and Runnable, which we explored in chapter 2: An interface is still a functional interface if it has many default methods as long as it specifies only one abstract method. To check your understanding, Quiz 3. Functional interface Which of these interfaces are functional interfaces? Only Adder is a functional interface.
What can you do with functional interfaces? Lambda expressions let you provide the implementation of the abstract method of a functional interface directly inline and treat the whole expression as an instance of a functional interface more technically speaking, an instance of a concrete implementation of the functional interface.
The following code is valid because Runnable is a functional interface defining only one abstract method, run: Function descriptor The signature of the abstract method of the functional interface essentially describes the signature of the lambda expression. We call this abstract method a function descriptor. For example, the Runnable interface can be viewed as the signature of a function that accepts nothing and returns nothing void because it has only one abstract method called run, which accepts nothing and returns nothing void.
Java reuses existing nominal types provided by functional interfaces and maps them into a form of function types behind the scenes. We use a special notation throughout the chapter to describe the signatures of lambdas and functional interfaces. This is exactly what the Runnable interface represents.
We detail how the compiler checks whether a lambda is valid in a given context in section 3. For now, it suffices to understand that a lambda expression can be assigned to a variable or passed to a method expecting a functional interface as argument, provided the lambda expression has the same signature as the abstract method of the functional interface. For instance, in our earlier example, you could pass a lambda directly to the process method as follows: This is exactly the signature of the run method defined in the Runnable interface.
But they chose this way because it fits naturally without increasing the complexity of the language. In addition, most Java programmers are already familiar with the idea of an interface with a single abstract method for example, with event handling. Try Quiz 3. Where can you use lambdas? Which of the following are valid uses of lambda expressions? Only 1 and 2 are valid. Note that running this code will do nothing because the body of the lambda is empty!
What about FunctionalInterface? This annotation is used to indicate that the interface is intended to be a functional interface. You can think of it like the Override notation to indicate that a method is overridden. A recurrent pattern in resource processing for example, dealing with files or databases is to open a resource, do some processing on it, and then close the resource.
The setup and cleanup phases are always similar and surround the important code doing the processing. This is called the execute around pattern, as illustrated in figure 3. Step 1: Remember behavior parameterization This current code is limited. You can read only the first line of the file. Does this sound familiar?
Yes, you need to parameterize the behavior of processFile. You need a way to pass behavior to processFile so it can execute different behaviors using a BufferedReader. Passing behavior is exactly what lambdas are for. So what should the new processFile method look like if you wanted to read two lines at once? You basically need a lambda that takes a BufferedReader and returns a String.
Step 2: Use a functional interface to pass behaviors We explained earlier that lambdas can be used only in the context of a functional interface. Step 3: Execute a behavior!
You now need only a way to execute the code represented by the lambda inside the body of processFile. Remember, lambda expressions let you provide the implementation of the abstract method of a functional interface directly inline, and they treat the whole expression as an instance of a functional interface.
You can therefore call the method process on the resulting BufferedReaderProcessor object inside the processFile body to perform the processing: Step 4: Groovy slides - Hacker Disassembling Uncovered.
Manning - Spring In Action, 2nd Ed Manning - Struts 2 in Action Manning - Wicket In Action - Aug Manning - Windows PowerShell in Action - feb Mapping 1. Good code should be easy to comprehend at a glance. This enables certain optimizations that we explain in the next chapter, such as laziness and short-circuiting. Serialization also requires access to the components of an array. In addition, stream operations have two important characteristics: Object orientation became fashionable in the s for two reasons: The idea with the second kind of method references such as String:: Java reflection also allows the ability to access nonpublic members of a class.
- PROJECT MANAGEMENT METRICS KPIS AND DASHBOARDS PDF
- MONSTROUS MAKEUP MANUAL PDF
- THERMALTAKE XASER III MANUAL PDF
- CHAIN REACTION SIMONE ELKELES EBOOK
- JIRO JAVA-BASED TECHNOLOGY PDF
- ENGINEERING MANAGEMENT PDF
- TOYOTA AURIS OWNERS MANUAL PDF
- DRUPAL 7 UBERCART 3 ECOMMERCE MANUAL PDF
- MKB 10 PDF
- BUKU GRATIS UNTUK GOOGLE PLAY BOOK
- CHINA HISTORY PDF
- VENU BHAGAVAN BOOKS PDF
- CS FRIEDMAN COLDFIRE TRILOGY EBOOK