I have the following for each loop:
int someOtherVal = 0;
List<Applicators> applicatorList = List.of(applicator1, applicator2);
MyClass result = initialClassValue;
for(Applicator applicator: applicatorList) {
result = applicator.apply(result, someOtherVal);
}
The closest I can get to it using Stream API is:
applicatorList.stream()
.reduce(
initialClassValue,
(intermediateResult, applicator) -> applicator.apply(intermediateResult, someOtherVal),
(intermediateResult1, intermediateResult2) -> intermediateResult1 // complete garbage but need to provide for parallel streams which I am not using
)
Is there some other way to implement this which does not involve the needless overriding of combiner function?
My beef with using combiner function is that -
I am not using parallel streams, so combining of intermediate results should not be required
the garbage combiner override actually doesn't make sense in this context
You can do it by not specifying the initial value in the reduce method. However, this too has its disadvantages. Here is a related example:
create my own sum lambda (could have used Integer::sum)
it returns an Optional<T> of some type T.
due to the lack of an initial value it returns the first via orElse. But then, that is what your method would do if only one value. Or you could just return the optional and check if a value was present.
BinaryOperator<Integer> sumThem = (a,b)->a + b;
int[] arr = {1,2,3,4,5,6,7};
int sum = Arrays.stream(arr).boxed().reduce(sumThem::apply).orElse(1);
But there is nothing wrong with using a loop and may be the best way to go.
In Java I have the following code
List<Integer> myList = new ArrayList<>();
for (int i=0;i<9;i++) {
myList.add(i);
}
Integer sum = 0;
myList.forEach(i -> {
sum = sum + i; // does not compile, sum needs to be final or effectively final
});
for(int i : myList) {
sum = sum + i; //runs without problems
}
My question is, why is it exactly that I cannot change the value of sum from within the lambda? It does the exact same thing as the for loop down below, or am I wrong? Interesting is also the fact that if I declare the Integer sum outside of the main method as static, it works as well. Can anyone explain me why?
EDIT: In another similar question Does Java 8 support closures, the answer seems to be :
it is a combination of backwards compatibility and project resourcing constraints.
However I still cannot understand why it works if I make sum an array or if I declare it outside of main. I would also like to understand what is the difference between the myList.forEach and the for loop below, why the one works and the other one doesn't.
Try with:
final Integer[] sum = new Integer[1];
sum[0] = 0;
myList.forEach(i -> {
sum[0] = sum[0] + i;
});
Since lambda is actually a syntactic sugar for initializing an anonymous class (and overriding a method).
It's the same as if you have written:
final Integer[] sum = new Integer[1];
sum[0] = 0;
myList.forEach(new Consumer() {
public void accept(Integer element) {
sum[0] = sum[0] + element;
}
});
The variable that comes from outer scope and that you use within inner scope must be final (in this example sum). That is simply because Java does not support closures. Therefore, outer variable must be marked as final. Since Integer itself is immutable (if you declare it final, you cannot change it anymore), you have to use a wrapper object or an array (as I did).
You can find more useful info here:
Why are only final variables accessible in anonymous class?
Cannot refer to a non-final variable inside an inner class defined in a different method
Not exactly the answer you are looking for, but in most scenarios you won't need to modify that inside the lambda. This is because it's not idiomatic for lambdas to be state-changing in a proper functional style.
What you can do to achieve your result is use any of the higher-level functions provided to mask the "accumulator", and then assign:
sum = myList.stream().mapToInt(x->x).sum();
A lambda is basically an anonymous class. You can only access final local variables from anonymous class.
What you need is a wrapper class that can modify its content. For a quick hack, you can use AtomicInteger in this case:
AtomicLong sum = new AtomicLong(0);
myList.forEach(i -> {
sum.addAndGet(i); // does not matter getAndAdd or addAndGet
});
sum.get(); // to get the value
Another way is, if you are using Intellij IDEA, the IDE can suggest you to transform the variable into final one element array (as in darijan's answer).
i am php developer just started at java i want to declare dynamic variables inside a loop and for that i have to append the loop value to varaible name this is what i want .
I would like to make statement like this
for (i=1; i<6; i++)
{
String new_variable_ + i;
}
the above code does not work in java how to do it ?
what you are trying to do is not possible in java ... this language is
not that lose like php..its a type strict language
Variable declarations are declared to be static identifiers and cannot contain any computed values in java (and i venture to say this would be true in any statically typed language).
You say you can't find an associative array. Have you seen the java.util.Map interface (and it's implementations)? It is by definition an associative array:
Wikipedia: In computer science, an associative array, map, or dictionary is an abstract data type composed of a collection of (key,value) pairs, such that each possible key appears at most once in the collection.
Like I said in the comment, there's no dynamic variable in Java. At best you can do this:
HashMap variableMap = new HashMap<String,String>();
for (int i = 1; i < 6; i++) {
variableMap.put("new_variable_" + i, "some variable value");
}
Then to access them, you do:
String value = variableMap.get("new_variable_2");
Or to update it, you do:
variableMap.put("new_variable_2", "new value");
If you just want to use a string version of i within the loop, you need:
for (int i=1; i<6; i++)
{
String new_variable_ = "" + i;
//use new_variable here.
}
If you're looking for something different, I'll need some more details. Good luck!
Java is nearing version 7. It occurs to me that there must be plenty of textbooks and training manuals kicking around that teach methods based on older versions of Java, where the methods taught, would have far better solutions now.
What are some boilerplate code situations, especially ones that you see people implement through force of habit, that you find yourself refactoring to utilize the latest versions of Java?
Enums. Replacing
public static final int CLUBS = 0;
public static final int DIAMONDS = 1;
public static final int HEARTS = 2;
public static final int SPADES = 3;
with
public enum Suit {
CLUBS,
DIAMONDS,
HEARTS,
SPADES
}
Generics and no longer needing to create an iterator to go through all elements in a collection. The new version is much better, easier to use, and easier to understand.
EDIT:
Before:
List l = someList;
Iterator i = l.getIterator();
while (i.hasNext()) {
MyObject o = (MyObject)i.next();
}
After
List<MyObject> l = someList;
for (MyObject o : l) {
//do something
}
Using local variables of type StringBuffer to perform string concatenation. Unless synchronization is required, it is now recommended to use StringBuilder instead, because this class offers better performance (presumably because it is unsynchronized).
reading a string from standard input:
Java pre-5:
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str = reader.readLine();
reader.close();
}
catch (IOException e) {
System.err.println("error when closing input stream.");
}
Java 5:
Scanner reader = new Scanner(System.in);
String str = reader.nextLine();
reader.close();
Java 6:
Console reader = System.console();
String str = reader.readLine();
Older code using Thread instead of the many other alternatives to Thread... these days, very little of the code I run across still needs to use a raw thread. They would be better served by a level of abstraction, particular Callable/Futures/Executors.
See:
java.util.Timer
javax.swing.Timer
java.util.concurrent.*
Here is one that I see:
String.split() versus StringTokenizer.
StringTokenizer is not recommended for new code, but I still see people use it.
As for compatibility, Sun makes a huge effort to have Java be backwards and forwards compatible. That partially accounts for why generics are so complex. Deprecation is also supposed to help ease transitions from old to new code.
VARARGS can be useful too.
For example, you can use:
public int add(int... numbers){
int sum = 0 ;
for (int i : numbers){
sum+=i;
}
return sum ;
}
instead of:
public int add(int n1, int n2, int n3, int n4) ;
or
public int add(List<Integer> numbers) ;
Using local variables of type Vector to hold a list of objects. Unless synchronization is required, it is now recommended to use a List implementation such as ArrayList instead, because this class offers better performance (because it is unsynchronized).
Formatted printing was introduced as late as in JDK 1.5. So instead of using:
String str = "test " + intValue + " test " + doubleValue;
or the equivalent using a StringBuilder,
one can use
String str = String.format("test %d test %lg", intValue, doubleValue);
The latter is much more readable, both from the string concatenation and the string builder versions. Still I find that people adopt this style very slowly. Log4j framework for example, doesn't use this, although I believe it would be greatly benefited to do so.
Explicit conversion between primitive and wrapper types (e.g. Integer to int or vice versa) which is taken care of automatically by autoboxing/unboxing since Java 1.5.
An example is
Integer myInteger = 6;
int myInt = myInteger.intValue();
Can simply be written as
Integer myInteger = 6;
int myInt = myInteger;
But watch out for NullPointerExceptions :)
Q1: Well, the most obvious situations are in the generics / type specific collections. The other one that immediately springs to mind is the improved for loop, which I feel is a lot cleaner looking and easier to understand.
Q2: In general, I have been bundling the JVM along side of my application for customer-facing apps. This allows us to use new language features without having to worry about JVM incompatibility.
If I were not bundling the JRE, I would probably stick to 1.4 for compatibility reasons.
A simple change in since 1.5 but makes a small difference - in the Swing API accessing the contentPane of a JFrame:
myframe.getContentPane().add(mycomponent);
becomes
myframe.add(mycomponent);
And of course the introduction of Enums has changed the way many applications that used constants in the past behave.
String.format() has greatly improved String manipulation and the ternary if statement is quite helpful in making code easier to read.
Generic collections make coding much more bug-resistant.
OLD:
Vector stringVector = new Vector();
stringVector.add("hi");
stringVector.add(528); // oops!
stringVector.add(new Whatzit()); // Oh my, could spell trouble later on!
NEW:
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("hello again");
stringList.add(new Whatzit()); // Won't compile!
Using Iterator:
List list = getTheList();
Iterator iter = list.iterator()
while (iter.hasNext()) {
String s = (String) iter.next();
// .. do something
}
Or an alternate form sometimes seen:
List list = getTheList();
for (Iterator iter = list.iterator(); iter.hasNext();) {
String s = (String) iter.next();
// .. do something
}
Is now all replaced with:
List<String> list = getTheList();
for (String s : list) {
// .. do something
}
Although I admit that static imports can easily be overused, I like to use
import static Math.* ;
in classes that use a lot of Math functions. It can really decrease the verbosity of your code. I wouldn't recommend it for lesser-known libraries, though, since that can lead to confusion.
copying an existing array to a new array:
pre-Java 5:
int[] src = new int[] {1, 2, 3, 4, 5};
int[] dest = new int[src.length];
System.arraycopy(src, 0, dest, 0, src.length);
Java 6:
int[] src = new int[] {1, 2, 3, 4, 5};
int[] dest = Arrays.copyOf(src, src.length);
formerly, I had to explicitly create a new array and then copy the source elements to the new array (calling a method with a lot of parameters). now, the syntax is cleaner and the new array is returned from a method, I don't have to create it. by the way, the method Arrays.copyOf has a variation called Arrays.copyOfRange, which copies a specific region of the source array (pretty much like System.arraycopy).
Converting a number to a String:
String s = n + "";
In this case I think there has always been a better way of doing this:
String s = String.valueOf(n);
The new for-each construct to iterate over arrays and collection are the biggest for me.
These days, when ever I see the boilerplate for loop to iterate over an array one-by-one using an index variable, it makes me want to scream:
// AGGHHH!!!
int[] array = new int[] {0, 1, 2, 3, 4};
for (int i = 0; i < array.length; i++)
{
// Do something...
}
Replacing the above with the for construct introduced in Java 5:
// Nice and clean.
int[] array = new int[] {0, 1, 2, 3, 4};
for (int n : array)
{
// Do something...
}
Clean, concise, and best of all, it gives meaning to the code rather than showing how to do something.
Clearly, the code has meaning to iterate over the collection, rather than the old for loop saying how to iterate over an array.
Furthermore, as each element is processed independent of other elements, it may allow for future optimizations for parallel processing without having to make changes to the code. (Just speculation, of course.)
Related to varargs; the utility method Arrays.asList() which, starting from Java 5, takes varargs parameters is immensely useful.
I often find myself simplifying something like
List<String> items = new ArrayList<String>();
items.add("one");
items.add("two");
items.add("three");
handleItems(items);
by using
handleItems(Arrays.asList("one", "two", "three"));
Annotations
I wonder no one mentioned it so far, but many frameworks rely on annotations, for example Spring and Hibernate. It is common today to deprecate xml configuration files are in favor of annotations in code (though this means losing flexibility in moving from configuration to meta-code, but is often the right choice).The best example is EJB 2 (and older) compared to EJB 3.0 and how programming EJB has been simplified thanks to annotations.
I find annotations also very useful in combination with some AOP tools like AspectJ or Spring AOP. Such combination can be very powerful.
Changing JUnit 3-style tests:
class Test extends TestCase {
public void testYadaYada() { ... }
}
to JUnit 4-style tests:
class Test {
#Test public void yadaYada() { ... }
}
Improved singleton patterns. Technically these are covered under the popular answer enums, but it's a significant subcategory.
public enum Singleton {
INSTANCE;
public void someMethod() {
...
}
}
is cleaner and safer than
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton() {
...
}
public void someMethod() {
...
}
}
Converting classes to use generics, thereby avoiding situations with unnecessary casts.
Okay, now it's my turn to get yelled at.
I don't recommend 90% of these changes.
It's not that it's not a good idea to use them with new code, but breaking into existing code to change a for loop to a for(:) loop is simply a waste of time and a chance to break something. (IIWDFWI) If it works, don't fix it!
If you are at a real development company, that change now becomes something to code-review, test and possibly debug.
If someone doing this kind of a refactor for no reason caused a problem of ANY sort, I'd give them no end of shit.
On the other hand, if you're in the code and changing stuff on that line anyway, feel free to clean it up.
Also, all the suggestions in the name of "Performance" really need to learn about the laws of optimization. In two words, Don't! Ever! (Google the "Rules of optimization if you don't believe me).
I'm a little wary to refactor along these lines if that is all you are doing to your source tree. The examples so far do not seem like reasons alone to change any working code base, but maybe if you are adding new functionality you should take advantage of all the new stuff.
At the end of the day, these example are not really removing boiler plate code, they are just using the more manageable constructs of newer JDKs to make nice looking boiler plate code.
Most ways to make your code elegant are not in the JDK.
Using Swing's new DefaultRowSorter to sort tables versus rolling your own from scratch.
New version of Java rarely break existing code, so just leave old code alone and focus on how the new feature makes your life easier.
If you just leave old code alone, then writing new code using new features isn't as scary.
String comparisons, really old school Java programmers I've met would do:
String s1 = "...", s2 = "...";
if (s1.intern() == s2.intern()) {
....
}
(Supposedly for performance reasons)
Whereas these days most people just do:
String s1 = "...", s2 = "...";
if (s1.equals(s2)) {
....
}
Using Vector instead of the new Collections.
Using classes instead of enums
public class Enum
{
public static final Enum FOO = new Enum();
public static final Enum BAR = new Enum();
}
Using Thread instead of the new java.util.concurrency package.
Using marker interfaces instead of annotations
It is worth noting that Java 5.0 has been out for five years now and there have only been minor changes since then. You would have to be working on very old code to be still refactoring it.