- Java: is there a map function?
- 6 Answers 6
- Is it possible to return map response from Functional interface in java [closed]
- 1 Answer 1
- Can a JPA Query return results as a Java Map?
- 12 Answers 12
- Returning a Map result using JPA Query getResultStream
- Returning a Map result using JPA Query getResultList and Java stream
- Returning a Map result using a Hibernate-specific ResultTransformer
- Avoid returning large result sets
Java: is there a map function?
If the answer to this question is yes, it answers also the other linked question. If the answer is no (and it seems so), they are completely unrelated.
6 Answers 6
Since Java 8, there are some standard options to do this in JDK:
Collection in = . Object[] mapped = in.stream().map(e -> doMap(e)).toArray(); // or List mapped = in.stream().map(e -> doMap(e)).collect(Collectors.toList());
@Natix agree about toList() . Replacing to different type: (List
There is no notion of a function in the JDK as of java 6.
Guava has a Function interface though and the
Collections2.transform(Collection, Function)
method provides the functionality you require.
// example, converts a collection of integers to their // hexadecimal string representations final Collection input = Arrays.asList(10, 20, 30, 40, 50); final Collection output = Collections2.transform(input, new Function() < @Override public String apply(final Integer input)< return Integer.toHexString(input.intValue()); >>); System.out.println(output);
These days, with Java 8, there is actually a map function, so I’d probably write the code in a more concise way:
Collection hex = input.stream() .map(Integer::toHexString) .collect(Collectors::toList);
It’s worth noting that while with Guava you can do this, you might not want to: code.google.com/p/guava-libraries/wiki/FunctionalExplained (read the «Caveats» section).
@AdamParkin true, but I’m pretty sure that refers to more advanced functional concepts than this, otherwise they wouldn’t have developed the transform() methods in the first place
Actually, no, there is often a definite performance hit with functional idioms, which is why they stress you should only use the facilities if you are certain it meets the two criteria outlined: net savings of LOC for the codebase as a whole, and proven performance gains due to lazy evaluation (or at least not performance hits). Not arguing against the use of them, just indicating that if you’re going to, you should heed the warnings of the implementers.
@SeanPatrickFloyd now that Java 8 is out, want to update this with an example involving lambdas? Like Collections2.transform(input -> Integer.toHexString(intput.intValue())
There is a wonderful library called Functional Java which handles many of the things you’d want Java to have but it doesn’t. Then again, there’s also this wonderful language Scala which does everything Java should have done but doesn’t while still being compatible with anything written for the JVM.
I am interested in how did they enable following syntax: a.map(
@Andrey — You can either ask them that yourself or check out the source code to see how it’s done. Here’s a link to the source: functionaljava.org/source
@Andrey: examples use syntax from BGGA closures proposal. While there is running prototype, it’s not in ‘official’ Java yet.
@Andrey: that syntax is part of a proposed specification for closures in Java (see second-to-last paragraph on homepage). There’s only a prototypical implementation.
Be very careful with Collections2.transform() from guava. That method’s greatest advantage is also its greatest danger: its laziness.
Look at the documentation of Lists.transform() , which I believe applies also to Collections2.transform() :
The function is applied lazily, invoked when needed. This is necessary for the returned list to be a view, but it means that the function will be applied many times for bulk operations like List.contains(java.lang.Object) and List.hashCode(). For this to perform well, function should be fast. To avoid lazy evaluation when the returned list doesn’t need to be a view, copy the returned list into a new list of your choosing.
Also in the documentation of Collections2.transform() they mention you get a live view, that change in the source list affect the transformed list. This sort of behaviour can lead to difficult-to-track problems if the developer doesn’t realize the way it works.
If you want a more classical «map», that will run once and once only, then you’re better off with FluentIterable , also from Guava, which has an operation which is much more simple. Here is the google example for it:
FluentIterable .from(database.getClientList()) .filter(activeInLastMonth()) .transform(Functions.toStringFunction()) .limit(10) .toList();
transform() here is the map method. It uses the same Function<> «callbacks» as Collections.transform() . The list you get back is read-only though, use copyInto() to get a read-write list.
Otherwise of course when java8 comes out with lambdas, this will be obsolete.
Is it possible to return map response from Functional interface in java [closed]
In the below code,I would like to return map from Functional interface. But I am getting error from the below code. Thanks in Advance.
Function < Employee, Map< String, Integer >> funcEmpToString = ( Employee e ) -> < Map map = new HashMap< String, Integer >( ); map.put( e.getName( ), e.getNumber( ) ) return map; >; import java.util.*; public class FunctionExample < public static List< String >convertEmpListToNamesList( List < Employee >employeeList, Function < Employee, String >funcEmpToString ) < List< String >empNameList = new ArrayList< String >( ); for ( Employee emp : employeeList ) < empNameList.add( funcEmpToString.apply( emp ) ); >return empNameList; > public static void main( String args[] ) < Function< Employee, String >funcEmpToString = ( Employee e ) -> ; List < Employee >employeeList = Arrays.asList( new Employee( "Tom Jones", 45 ), new Employee( "Harry Major", 25 ), new Employee( "Ethan Hardy", 65 ), new Employee( "Nancy Smith", 15 ), new Employee( "Deborah Sprightly", 29 ) ); List < String >empNameList = convertEmpListToNamesList( employeeList, funcEmpToString ); empNameList.forEach( System.out::println ); > >
Questions seeking debugging help («why isn’t this code working?») must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a minimal reproducible example. Use the edit link to improve your question — do not add more information via comments. Thanks!
The above code, even formatted correctly wouldnt even compile (with the imports in the middle of something, Please carefully format your code to make sense.
1 Answer 1
1- Yes it is possible. 2- I would need further information to assist you, as you did not told us about the error, I am assuming you are having issues with you missing semicolon:
map.put(e.getName(), e.getNumber())
Here is your code rewritten as example in a single snippet:
package other; import java.util.*; import java.util.function.Function; public class FunctionExample < private static class Employee< private String name; private int number; Employee(String name, int number)< this.name=name; this.number = number; >private int getNumber( ) < return number; >private String getName( ) < return name; >> Function < Employee, Map< String, Integer >> funcEmpToString = ( Employee e ) -> < Map map = new HashMap< String, Integer >( ); map.put( e.getName( ), e.getNumber( ) ); return map; >; public static List < String >convertEmpListToNamesList( List < Employee >employeeList, Function < Employee, String >funcEmpToString ) < List< String >empNameList = new ArrayList< String >( ); for ( Employee emp : employeeList ) < empNameList.add( funcEmpToString.apply( emp ) ); >return empNameList; > public static void main( String args[] ) < Function< Employee, String >funcEmpToString = ( Employee e ) -> < return e.getName( );>; List < Employee >employeeList = Arrays.asList( new Employee( "Tom Jones", 45 ), new Employee( "Harry Major", 25 ), new Employee( "Ethan Hardy", 65 ), new Employee( "Nancy Smith", 15 ), new Employee( "Deborah Sprightly", 29 ) ); List < String >empNameList = convertEmpListToNamesList( employeeList, funcEmpToString ); empNameList.forEach( System.out::println ); > >
Can a JPA Query return results as a Java Map?
We are currently building a Map manually based on the two fields that are returned by a named JPA query because JPA 2.1 only provides a getResultList() method:
@NamedQuery HashMap myMap = new HashMap(); for(Client c: em.createNamedQuery("myQuery").getResultList() )
But, I feel like a custom mapper or similar would be more performant since this list could easily be 30,000+ results. Any ideas to build a Map without iterating manually. (I am using OpenJPA, not hibernate)
Like the code shows,the number field (Long), one of two values returned. BUt I could live with any Type, so long as the key is the number and the value is the name. I added the declaration for more details.
12 Answers 12
Returning a Map result using JPA Query getResultStream
Since the JPA 2.2 version, you can use the getResultStream Query method to transform the List result into a Map :
Map postCountByYearMap = entityManager.createQuery(""" select YEAR(p.createdOn) as year, count(p) as postCount from Post p group by YEAR(p.createdOn) """, Tuple.class) .getResultStream() .collect( Collectors.toMap( tuple -> ((Number) tuple.get("year")).intValue(), tuple -> ((Number) tuple.get("postCount")).intValue() ) );
Returning a Map result using JPA Query getResultList and Java stream
If you’re using JPA 2.1 or older versions but your application is running on Java 8 or a newer version, then you can use getResultList and transform the List to a Java 8 stream:
Map postCountByYearMap = entityManager.createQuery(""" select YEAR(p.createdOn) as year, count(p) as postCount from Post p group by YEAR(p.createdOn) """, Tuple.class) .getResultList() .stream() .collect( Collectors.toMap( tuple -> ((Number) tuple.get("year")).intValue(), tuple -> ((Number) tuple.get("postCount")).intValue() ) );
Returning a Map result using a Hibernate-specific ResultTransformer
Another option is to use the MapResultTransformer class provided by the Hibernate Types open-source project:
Map postCountByYearMap = (Map) entityManager.createQuery(""" select YEAR(p.createdOn) as year, count(p) as postCount from Post p group by YEAR(p.createdOn) """) .unwrap(org.hibernate.query.Query.class) .setResultTransformer( new MapResultTransformer() ) .getSingleResult();
The MapResultTransformer is suitable for projects still running on Java 6 or using older Hibernate versions.
Avoid returning large result sets
But, I feel like a custom mapper or similar would be more performant since this list could easily be 30,000+ results.
This is a terrible idea. You never need to select 30k records. How would that fit in the UI? Or, why would you operate on such a large batch of records?
You should use query pagination as this will help you reduce the transaction response time and provide better concurrency.